From d773473d18e083c097bd145d9c0558b5d5dcb421 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Wed, 31 Jul 2024 08:58:37 +0200 Subject: [PATCH] Replace deprecated GtkUIManager This replaces a deprecated GtkUIManager with a new EUIManager, which uses its own file format, similar to the .ui used by the gtk+, but not the same. This brought in more structures like EUIAction and EUIActionGroup. To name the few most significant changes: The overall window architecture had been changed internally too, the EShellView is a widget now and contains everything except of the header bar. This allows to create the window content once and not regenerate it every switch between the views. It also moved the EUIManager from the EShellWindow to the EShellView. The EMailShellContent does not implement an EMailReader interface any more. It allows to have cleaner EMailReader usage in the code. To get to the EMailReader use: EMailView *mail_view = NULL; g_object_get (e_shell_view_get_shell_content (mail_shell_view), "mail-view", &mail_view, NULL); if (mail_view) { EMailReader *mail_reader = E_MAIL_READER (mail_view); ... g_clear_object (&mail_view); } The plugins cannot have their UI definitions in the .eplug file, these are added in the code, directly to the EUIManager. Modules already did that. --- CMakeLists.txt | 1 - config.h.in | 3 - data/icons/CMakeLists.txt | 1 + .../icons/hicolor_apps_scalable_gcr-gnupg.svg | 102 + data/ui/CMakeLists.txt | 19 +- data/ui/e-comp-editor.eui | 70 + data/ui/e-html-editor.eui | 214 ++ data/ui/evolution-calendars.eui | 214 ++ data/ui/evolution-calendars.ui | 199 - data/ui/evolution-composer.eui | 102 + data/ui/evolution-contacts.eui | 125 + data/ui/evolution-contacts.ui | 120 - data/ui/evolution-mail-reader.eui | 221 ++ data/ui/evolution-mail-reader.ui | 210 - data/ui/evolution-mail-viewer.eui | 60 + data/ui/evolution-mail-viewer.ui | 210 - data/ui/evolution-mail.eui | 216 ++ data/ui/evolution-mail.ui | 213 -- data/ui/evolution-memos.eui | 95 + data/ui/evolution-memos.ui | 87 - data/ui/evolution-shell.eui | 108 + data/ui/evolution-shell.ui | 97 - data/ui/evolution-tasks.eui | 109 + data/ui/evolution-tasks.ui | 101 - data/webkit/e-editor.js | 22 +- .../evolution-shell-docs.sgml.in | 5 +- .../evolution-util-docs.sgml.in | 17 +- po/POTFILES.in | 3 - .../gui/contact-editor/e-contact-editor.c | 101 +- .../gui/widgets/e-addressbook-view.c | 22 +- .../gui/widgets/eab-contact-display.c | 103 +- src/calendar/gui/e-calendar-view.c | 18 +- src/calendar/gui/e-comp-editor-event.c | 168 +- src/calendar/gui/e-comp-editor-memo.c | 56 +- .../gui/e-comp-editor-page-attachments.c | 86 +- src/calendar/gui/e-comp-editor-page-general.c | 146 +- .../gui/e-comp-editor-page-recurrence.c | 51 +- .../gui/e-comp-editor-page-reminders.c | 51 +- .../gui/e-comp-editor-page-schedule.c | 49 +- src/calendar/gui/e-comp-editor-task.c | 101 +- src/calendar/gui/e-comp-editor.c | 466 +-- src/calendar/gui/e-comp-editor.h | 9 +- src/calendar/gui/e-memo-table.c | 22 +- src/calendar/gui/e-task-table.c | 22 +- src/composer/CMakeLists.txt | 4 - src/composer/e-composer-actions.c | 786 ++-- src/composer/e-composer-private.c | 311 +- src/composer/e-composer-private.h | 12 +- src/composer/e-msg-composer.c | 255 +- src/composer/evolution-composer.ui | 85 - src/e-util/CMakeLists.txt | 19 +- src/e-util/e-action-combo-box.c | 313 +- src/e-util/e-action-combo-box.h | 11 +- src/e-util/e-alert-bar.c | 7 +- src/e-util/e-alert-dialog.c | 13 +- src/e-util/e-alert.c | 76 +- src/e-util/e-alert.h | 10 +- src/e-util/e-attachment-bar.c | 38 +- src/e-util/e-attachment-handler-image.c | 65 +- src/e-util/e-attachment-paned.c | 15 +- src/e-util/e-attachment-view.c | 492 ++- src/e-util/e-attachment-view.h | 17 +- src/e-util/e-charset-combo-box.c | 259 +- src/e-util/e-charset-combo-box.h | 36 +- src/e-util/e-charset.c | 234 +- src/e-util/e-charset.h | 11 +- src/e-util/e-content-editor.c | 2 +- src/e-util/e-content-editor.h | 4 +- src/e-util/e-emoticon-action.c | 251 -- src/e-util/e-emoticon-action.h | 73 - src/e-util/e-emoticon-tool-button.c | 561 --- src/e-util/e-emoticon-tool-button.h | 75 - src/e-util/e-emoticon.c | 12 +- src/e-util/e-emoticon.h | 10 +- src/e-util/e-focus-tracker.c | 456 +-- src/e-util/e-focus-tracker.h | 30 +- src/e-util/e-headerbar-button.c | 333 +- src/e-util/e-headerbar-button.h | 10 +- src/e-util/e-headerbar.c | 44 + src/e-util/e-headerbar.h | 1 + src/e-util/e-html-editor-actions.c | 1339 ++++--- src/e-util/e-html-editor-actions.h | 2 +- src/e-util/e-html-editor-manager.ui | 196 - src/e-util/e-html-editor-paragraph-dialog.c | 21 +- src/e-util/e-html-editor-private.h | 63 +- src/e-util/e-html-editor.c | 1005 +++-- src/e-util/e-html-editor.h | 21 +- src/e-util/e-mail-signature-editor.c | 223 +- src/e-util/e-menu-bar.c | 7 +- src/e-util/e-menu-tool-action.c | 57 - src/e-util/e-menu-tool-action.h | 73 - src/e-util/e-menu-tool-button.c | 161 +- src/e-util/e-menu-tool-button.h | 5 +- src/e-util/e-misc-utils.c | 431 +-- src/e-util/e-misc-utils.h | 21 +- src/e-util/e-plugin-ui.c | 439 +-- src/e-util/e-plugin-ui.h | 9 +- src/e-util/e-popup-action.c | 392 -- src/e-util/e-popup-action.h | 95 - src/e-util/e-proxy-selector.c | 14 +- src/e-util/e-table-column-selector.c | 16 +- src/e-util/e-tree-view-frame.c | 211 +- src/e-util/e-tree-view-frame.h | 9 +- src/e-util/e-ui-action-group.c | 665 ++++ src/e-util/e-ui-action-group.h | 44 + src/e-util/e-ui-action.c | 1757 +++++++++ src/e-util/e-ui-action.h | 125 + src/e-util/e-ui-manager.c | 2229 +++++++++++ src/e-util/e-ui-manager.h | 97 + src/e-util/e-ui-menu.c | 517 +++ src/e-util/e-ui-menu.h | 44 + src/e-util/e-ui-parser.c | 1469 +++++++ src/e-util/e-ui-parser.h | 75 + src/e-util/e-util-enums.h | 47 + src/e-util/e-util.h | 9 +- src/e-util/e-web-view.c | 703 ++-- src/e-util/e-web-view.h | 22 +- src/e-util/test-html-editor-units-utils.c | 18 +- src/e-util/test-html-editor-units.c | 20 +- src/e-util/test-html-editor.c | 428 ++- src/e-util/test-tree-view-frame.c | 8 +- src/mail/CMakeLists.txt | 2 - src/mail/e-mail-browser.c | 625 +-- src/mail/e-mail-browser.h | 1 - src/mail/e-mail-display.c | 1003 ++--- src/mail/e-mail-display.h | 11 +- src/mail/e-mail-folder-sort-order-dialog.c | 31 +- src/mail/e-mail-label-action.c | 120 - src/mail/e-mail-label-action.h | 72 - src/mail/e-mail-label-list-store.c | 45 +- src/mail/e-mail-label-list-store.h | 3 +- src/mail/e-mail-label-tree-view.c | 8 +- src/mail/e-mail-notes.c | 203 +- src/mail/e-mail-paned-view.c | 133 +- src/mail/e-mail-paned-view.h | 8 + src/mail/e-mail-print-config-headers.c | 16 +- src/mail/e-mail-reader-utils.c | 16 +- src/mail/e-mail-reader.c | 3378 ++++++++--------- src/mail/e-mail-reader.h | 32 +- src/mail/e-mail-templates-store.c | 190 +- src/mail/e-mail-templates-store.h | 11 +- src/mail/e-mail-viewer.c | 766 ++-- src/mail/e-mail.h | 1 - src/mail/em-composer-utils.c | 67 +- src/mail/em-folder-selector.c | 10 +- src/mail/mail-send-recv.c | 24 +- src/mail/message-list.c | 6 +- .../addressbook/e-book-shell-backend.c | 74 +- .../addressbook/e-book-shell-content.c | 13 +- .../addressbook/e-book-shell-view-actions.c | 1175 +++--- .../addressbook/e-book-shell-view-actions.h | 164 +- .../addressbook/e-book-shell-view-private.c | 107 +- .../addressbook/e-book-shell-view-private.h | 6 +- src/modules/addressbook/e-book-shell-view.c | 93 +- .../backup-restore/evolution-backup-restore.c | 125 +- .../calendar/e-cal-attachment-handler.c | 155 +- .../calendar/e-cal-base-shell-backend.c | 6 +- .../calendar/e-cal-base-shell-backend.h | 4 +- .../calendar/e-cal-base-shell-sidebar.c | 14 +- src/modules/calendar/e-cal-shell-backend.c | 87 +- src/modules/calendar/e-cal-shell-content.c | 21 +- .../calendar/e-cal-shell-view-actions.c | 1671 ++++---- .../calendar/e-cal-shell-view-actions.h | 316 +- .../calendar/e-cal-shell-view-memopad.c | 181 +- .../calendar/e-cal-shell-view-private.c | 154 +- .../calendar/e-cal-shell-view-private.h | 7 +- .../calendar/e-cal-shell-view-taskpad.c | 247 +- src/modules/calendar/e-cal-shell-view.c | 232 +- src/modules/calendar/e-memo-shell-backend.c | 68 +- .../calendar/e-memo-shell-view-actions.c | 852 ++--- .../calendar/e-memo-shell-view-actions.h | 120 +- .../calendar/e-memo-shell-view-private.c | 89 +- .../calendar/e-memo-shell-view-private.h | 6 +- src/modules/calendar/e-memo-shell-view.c | 72 +- src/modules/calendar/e-task-shell-backend.c | 68 +- .../calendar/e-task-shell-view-actions.c | 1099 +++--- .../calendar/e-task-shell-view-actions.h | 172 +- .../calendar/e-task-shell-view-private.c | 89 +- .../calendar/e-task-shell-view-private.h | 6 +- src/modules/calendar/e-task-shell-view.c | 82 +- .../e-composer-to-meeting.c | 49 +- .../e-meeting-to-composer.c | 45 +- src/modules/mail/e-mail-attachment-handler.c | 329 +- src/modules/mail/e-mail-shell-backend.c | 91 +- src/modules/mail/e-mail-shell-content.c | 400 +- src/modules/mail/e-mail-shell-view-actions.c | 1625 ++++---- src/modules/mail/e-mail-shell-view-actions.h | 510 +-- src/modules/mail/e-mail-shell-view-private.c | 712 ++-- src/modules/mail/e-mail-shell-view-private.h | 21 +- src/modules/mail/e-mail-shell-view.c | 299 +- src/modules/mail/em-composer-prefs.c | 4 +- src/modules/mdn/evolution-mdn.c | 16 +- .../offline-alert/evolution-offline-alert.c | 2 +- .../e-mail-display-popup-prefer-plain.c | 179 +- .../evolution/e-rss-shell-view-extension.c | 116 +- src/modules/settings/e-settings-mail-reader.c | 8 +- .../e-mail-display-popup-text-highlight.c | 381 +- src/modules/webkit-editor/e-webkit-editor.c | 4 +- .../web-extension/e-editor-web-extension.c | 2 +- .../attachment-reminder/attachment-reminder.c | 2 +- .../email-custom-header/email-custom-header.c | 124 +- .../email-custom-header/email-custom-header.h | 6 - .../org-gnome-email-custom-header.eplug.xml | 16 +- src/plugins/external-editor/external-editor.c | 73 +- .../org-gnome-external-editor.eplug.xml | 12 +- src/plugins/face/face.c | 62 +- src/plugins/face/org-gnome-face.eplug.xml | 10 +- .../mail-notification/mail-notification.c | 41 +- src/plugins/mail-to-task/mail-to-task.c | 222 +- .../org-gnome-mail-to-task.eplug.xml | 62 +- .../mailing-list-actions.c | 262 +- .../org-gnome-mailing-list-actions.eplug.xml | 44 +- .../org-gnome-publish-calendar.eplug.xml | 10 +- .../publish-calendar/publish-calendar.c | 48 +- .../org-gnome-save-calendar.eplug.xml | 29 +- src/plugins/save-calendar/save-calendar.c | 198 +- .../templates/org-gnome-templates.eplug.xml | 18 +- src/plugins/templates/templates.c | 332 +- src/shell/CMakeLists.txt | 2 - src/shell/e-shell-headerbar.c | 326 -- src/shell/e-shell-headerbar.h | 56 - src/shell/e-shell-searchbar.c | 340 +- src/shell/e-shell-searchbar.h | 5 +- src/shell/e-shell-sidebar.c | 15 +- src/shell/e-shell-switcher.c | 53 +- src/shell/e-shell-switcher.h | 5 +- src/shell/e-shell-view.c | 2157 ++++++++++- src/shell/e-shell-view.h | 67 +- src/shell/e-shell-window-actions.c | 1919 +++------- src/shell/e-shell-window-actions.h | 44 +- src/shell/e-shell-window-private.c | 602 +-- src/shell/e-shell-window-private.h | 48 +- src/shell/e-shell-window.c | 1379 ++----- src/shell/e-shell-window.h | 56 +- src/shell/e-shell.c | 3 - 235 files changed, 26381 insertions(+), 23850 deletions(-) create mode 100644 data/icons/hicolor_apps_scalable_gcr-gnupg.svg create mode 100644 data/ui/e-comp-editor.eui create mode 100644 data/ui/e-html-editor.eui create mode 100644 data/ui/evolution-calendars.eui delete mode 100644 data/ui/evolution-calendars.ui create mode 100644 data/ui/evolution-composer.eui create mode 100644 data/ui/evolution-contacts.eui delete mode 100644 data/ui/evolution-contacts.ui create mode 100644 data/ui/evolution-mail-reader.eui delete mode 100644 data/ui/evolution-mail-reader.ui create mode 100644 data/ui/evolution-mail-viewer.eui delete mode 100644 data/ui/evolution-mail-viewer.ui create mode 100644 data/ui/evolution-mail.eui delete mode 100644 data/ui/evolution-mail.ui create mode 100644 data/ui/evolution-memos.eui delete mode 100644 data/ui/evolution-memos.ui create mode 100644 data/ui/evolution-shell.eui delete mode 100644 data/ui/evolution-shell.ui create mode 100644 data/ui/evolution-tasks.eui delete mode 100644 data/ui/evolution-tasks.ui delete mode 100644 src/composer/evolution-composer.ui delete mode 100644 src/e-util/e-emoticon-action.c delete mode 100644 src/e-util/e-emoticon-action.h delete mode 100644 src/e-util/e-emoticon-tool-button.c delete mode 100644 src/e-util/e-emoticon-tool-button.h delete mode 100644 src/e-util/e-html-editor-manager.ui delete mode 100644 src/e-util/e-menu-tool-action.c delete mode 100644 src/e-util/e-menu-tool-action.h delete mode 100644 src/e-util/e-popup-action.c delete mode 100644 src/e-util/e-popup-action.h create mode 100644 src/e-util/e-ui-action-group.c create mode 100644 src/e-util/e-ui-action-group.h create mode 100644 src/e-util/e-ui-action.c create mode 100644 src/e-util/e-ui-action.h create mode 100644 src/e-util/e-ui-manager.c create mode 100644 src/e-util/e-ui-manager.h create mode 100644 src/e-util/e-ui-menu.c create mode 100644 src/e-util/e-ui-menu.h create mode 100644 src/e-util/e-ui-parser.c create mode 100644 src/e-util/e-ui-parser.h delete mode 100644 src/mail/e-mail-label-action.c delete mode 100644 src/mail/e-mail-label-action.h delete mode 100644 src/shell/e-shell-headerbar.c delete mode 100644 src/shell/e-shell-headerbar.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 224a212c99..3214485bc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,7 +223,6 @@ setup_build_flags(${ENABLE_MAINTAINER_MODE}) set(MATH_LDFLAGS -lm) CHECK_INCLUDE_FILE(sys/wait.h HAVE_SYS_WAIT_H) -CHECK_INCLUDE_FILE(X11/XF86keysym.h HAVE_XFREE) CHECK_FUNCTION_EXISTS(nl_langinfo HAVE_NL_LANGINFO) # ****************************** diff --git a/config.h.in b/config.h.in index a0b4b6e6bb..7b77a9d91f 100644 --- a/config.h.in +++ b/config.h.in @@ -66,9 +66,6 @@ /* ISO codes prefix */ #define ISO_CODES_PREFIX "@ISO_CODES_PREFIX@" -/* defined if you have X11/XF86keysym.h */ -#cmakedefine HAVE_XFREE 1 - /* Define if TNEF attachments parser should be built */ #cmakedefine ENABLE_YTNEF 1 diff --git a/data/icons/CMakeLists.txt b/data/icons/CMakeLists.txt index 104bbc8c00..8a3d70141b 100644 --- a/data/icons/CMakeLists.txt +++ b/data/icons/CMakeLists.txt @@ -58,6 +58,7 @@ set(private_icons hicolor_apps_scalable_evolution-mail-symbolic.svg hicolor_apps_scalable_evolution-memos-symbolic.svg hicolor_apps_scalable_evolution-tasks-symbolic.svg + hicolor_apps_scalable_gcr-gnupg.svg hicolor_apps_scalable_im-aim.svg hicolor_apps_scalable_im-icq.svg hicolor_apps_scalable_im-jabber.svg diff --git a/data/icons/hicolor_apps_scalable_gcr-gnupg.svg b/data/icons/hicolor_apps_scalable_gcr-gnupg.svg new file mode 100644 index 0000000000..36ffd688b3 --- /dev/null +++ b/data/icons/hicolor_apps_scalable_gcr-gnupg.svg @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + diff --git a/data/ui/CMakeLists.txt b/data/ui/CMakeLists.txt index 1c3d04a56a..f4222ca699 100644 --- a/data/ui/CMakeLists.txt +++ b/data/ui/CMakeLists.txt @@ -1,11 +1,14 @@ -install(FILES evolution-calendars.ui - evolution-contacts.ui - evolution-mail.ui - evolution-mail-reader.ui - evolution-mail-viewer.ui - evolution-memos.ui - evolution-shell.ui - evolution-tasks.ui +install(FILES e-comp-editor.eui + e-html-editor.eui + evolution-calendars.eui + evolution-composer.eui + evolution-contacts.eui + evolution-mail.eui + evolution-mail-reader.eui + evolution-mail-viewer.eui + evolution-memos.eui + evolution-shell.eui + evolution-tasks.eui evolution-shortcuts.ui DESTINATION ${uidir} ) diff --git a/data/ui/e-comp-editor.eui b/data/ui/e-comp-editor.eui new file mode 100644 index 0000000000..0f4d3f420a --- /dev/null +++ b/data/ui/e-comp-editor.eui @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/e-html-editor.eui b/data/ui/e-html-editor.eui new file mode 100644 index 0000000000..cbff2e2a1a --- /dev/null +++ b/data/ui/e-html-editor.eui @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-calendars.eui b/data/ui/evolution-calendars.eui new file mode 100644 index 0000000000..da6a0e0359 --- /dev/null +++ b/data/ui/evolution-calendars.eui @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-calendars.ui b/data/ui/evolution-calendars.ui deleted file mode 100644 index 7919602372..0000000000 --- a/data/ui/evolution-calendars.ui +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/ui/evolution-composer.eui b/data/ui/evolution-composer.eui new file mode 100644 index 0000000000..d35add81c8 --- /dev/null +++ b/data/ui/evolution-composer.eui @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-contacts.eui b/data/ui/evolution-contacts.eui new file mode 100644 index 0000000000..b819b0becd --- /dev/null +++ b/data/ui/evolution-contacts.eui @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-contacts.ui b/data/ui/evolution-contacts.ui deleted file mode 100644 index 2cdba8aa1b..0000000000 --- a/data/ui/evolution-contacts.ui +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/ui/evolution-mail-reader.eui b/data/ui/evolution-mail-reader.eui new file mode 100644 index 0000000000..c6ac0a68a8 --- /dev/null +++ b/data/ui/evolution-mail-reader.eui @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-mail-reader.ui b/data/ui/evolution-mail-reader.ui deleted file mode 100644 index efa3da7af1..0000000000 --- a/data/ui/evolution-mail-reader.ui +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/ui/evolution-mail-viewer.eui b/data/ui/evolution-mail-viewer.eui new file mode 100644 index 0000000000..76868ba8aa --- /dev/null +++ b/data/ui/evolution-mail-viewer.eui @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-mail-viewer.ui b/data/ui/evolution-mail-viewer.ui deleted file mode 100644 index 8984e9f1b3..0000000000 --- a/data/ui/evolution-mail-viewer.ui +++ /dev/null @@ -1,210 +0,0 @@ - - - - -
- - Go to _Previous Message - go-previous - mail-viewer.goto-previous - <Control>Page_Up - - - Go to _Next Message - go-next - mail-viewer.goto-next - <Control>Page_Down - -
-
- - - _File -
- - _Open… - document-open - mail-viewer.open - <Control>o - - - _Print - document-print - mail-viewer.print - <Control>p - -
-
- - _Close - mail-viewer.close - <Control>w - -
-
- - _Edit -
- - C_ut - edit-cut - mail-viewer.cut - <Control>x - - - _Copy - edit-copy - mail-viewer.copy - <Control>c - - - _Paste - edit-paste - mail-viewer.paste - <Control>v - -
-
- - _Select All - edit-select-all - mail-viewer.select-all - -
-
- - _Find in Message… - edit-find - mail-viewer.find - <Control><Shift>f - -
-
- - _View -
- - _Load Images - image-x-generic - mail-viewer.load-images - <Control>i - - - All Message _Headers - mail-viewer.all-headers - - - Message _Source - mail-viewer.msg-source - <Control>u - - - _Caret Mode - mail-viewer.caret-mode - F7 - - - _Zoom - - _Zoom In - zoom-in - mail-viewer.zoom-in - <Control>plus - - - Zoom _Out - zoom-out - mail-viewer.zoom-out - <Control>minus - - - _Normal Size - zoom-original - mail-viewer.zoom-zero - <Control>0 - - -
- - Ch_aracter Encoding -
- - _Default - mail-viewer.charset - - -
-
-
- - _Message -
- - _Import… - mail-viewer.import-one - - - _Edit as New Message - mail-viewer.edit-as-new - - - A_dd Sender to Address Book - mail-viewer.add-sender - -
-
- - _Reply to Sender - mail-reply-sender - mail-viewer.reply-sender - <Control>r - - - Reply to _List - mail-viewer.reply-list - <Control>l - - - Reply to _All - mail-reply-all - mail-viewer.reply-all - <Control><Shift>r - - - Al_ternative Reply… - mail-viewer.reply-alt - <Control><Primary>r - - - _Forward - mail-forward - mail-viewer.forward - <Control><Primary>f - - - F_orward As -
- - _Attached - mail-viewer.forward-attached - - - _Inline - mail-viewer.forward-inline - - - _Quoted - mail-viewer.forward-quoted - -
-
- - Re_direct - mail-viewer.redirect - -
-
-
-
-
-
diff --git a/data/ui/evolution-mail.eui b/data/ui/evolution-mail.eui new file mode 100644 index 0000000000..8ec5dbd2c8 --- /dev/null +++ b/data/ui/evolution-mail.eui @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-mail.ui b/data/ui/evolution-mail.ui deleted file mode 100644 index 6ba4929f29..0000000000 --- a/data/ui/evolution-mail.ui +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/ui/evolution-memos.eui b/data/ui/evolution-memos.eui new file mode 100644 index 0000000000..c50dbad12f --- /dev/null +++ b/data/ui/evolution-memos.eui @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-memos.ui b/data/ui/evolution-memos.ui deleted file mode 100644 index 8810b91ce9..0000000000 --- a/data/ui/evolution-memos.ui +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/ui/evolution-shell.eui b/data/ui/evolution-shell.eui new file mode 100644 index 0000000000..5f22ea74e7 --- /dev/null +++ b/data/ui/evolution-shell.eui @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-shell.ui b/data/ui/evolution-shell.ui deleted file mode 100644 index 477713dd5c..0000000000 --- a/data/ui/evolution-shell.ui +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/ui/evolution-tasks.eui b/data/ui/evolution-tasks.eui new file mode 100644 index 0000000000..6a1d58f74d --- /dev/null +++ b/data/ui/evolution-tasks.eui @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/ui/evolution-tasks.ui b/data/ui/evolution-tasks.ui deleted file mode 100644 index cd5a2687e8..0000000000 --- a/data/ui/evolution-tasks.ui +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js index d4ee23a2cb..44960d1496 100644 --- a/data/webkit/e-editor.js +++ b/data/webkit/e-editor.js @@ -2625,7 +2625,7 @@ EvoEditor.applyFontReset = function(record, isUndo) EvoEditor.replaceInheritFonts = function(undoRedoRecord, selectionUpdater, nodes) { - var ii; + var ii, changed = false; if (!nodes) nodes = document.querySelectorAll("FONT[face=inherit]"); @@ -2667,7 +2667,10 @@ EvoEditor.replaceInheritFonts = function(undoRedoRecord, selectionUpdater, nodes } node.remove(); + changed = true; } else { + if (node.hasAttribute ("face")) + changed = true; node.removeAttribute("face"); } @@ -2677,6 +2680,8 @@ EvoEditor.replaceInheritFonts = function(undoRedoRecord, selectionUpdater, nodes if (undoRedoRecord && undoRedoRecord.changes) undoRedoRecord.apply = EvoEditor.applyFontReset; + + return changed; } EvoEditor.maybeReplaceInheritFonts = function() @@ -2708,15 +2713,17 @@ EvoEditor.SetFontName = function(name) if (!name || name == "") name = "inherit"; - var record, selectionUpdater = EvoSelection.CreateUpdaterObject(), bodyFontFamily; + var record, selectionUpdater = EvoSelection.CreateUpdaterObject(), bodyFontFamily, changed = false; // to workaround https://bugs.webkit.org/show_bug.cgi?id=204622 bodyFontFamily = document.body.style.fontFamily; record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_GROUP, "SetFontName"); try { - if (!document.getSelection().isCollapsed && bodyFontFamily) + if (!document.getSelection().isCollapsed && bodyFontFamily) { document.body.style.fontFamily = ""; + changed = TRUE; + } document.execCommand("FontName", false, name); @@ -2732,19 +2739,22 @@ EvoEditor.SetFontName = function(name) subrecord = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "SetFontName", null, null, EvoEditor.CLAIM_CONTENT_FLAG_NONE); try { - EvoEditor.replaceInheritFonts(subrecord, selectionUpdater); + changed = EvoEditor.replaceInheritFonts(subrecord, selectionUpdater); selectionUpdater.restore(); } finally { EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "SetFontName"); } } } finally { - if (bodyFontFamily && document.body.style.fontFamily != bodyFontFamily) + if (bodyFontFamily && document.body.style.fontFamily != bodyFontFamily) { document.body.style.fontFamily = bodyFontFamily; + changed = true; + } EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "SetFontName"); EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE); - EvoEditor.EmitContentChanged(); + if (changed) + EvoEditor.EmitContentChanged(); EvoEditor.removeEmptyStyleAttribute(document.body); } diff --git a/docs/reference/evolution-shell/evolution-shell-docs.sgml.in b/docs/reference/evolution-shell/evolution-shell-docs.sgml.in index 8778d8d784..f15f659a87 100644 --- a/docs/reference/evolution-shell/evolution-shell-docs.sgml.in +++ b/docs/reference/evolution-shell/evolution-shell-docs.sgml.in @@ -24,7 +24,6 @@ - @@ -42,6 +41,10 @@ Index + + Index of new symbols in 3.56 + + Index of new symbols in 3.54 diff --git a/docs/reference/evolution-util/evolution-util-docs.sgml.in b/docs/reference/evolution-util/evolution-util-docs.sgml.in index 9d59c113d8..978a8f91e6 100644 --- a/docs/reference/evolution-util/evolution-util-docs.sgml.in +++ b/docs/reference/evolution-util/evolution-util-docs.sgml.in @@ -108,10 +108,8 @@ - - @@ -252,6 +250,15 @@ + + User Interface Manager + + + + + + + (Unsorted Sections) @@ -286,7 +293,6 @@ - @@ -301,7 +307,6 @@ - @@ -333,6 +338,10 @@ Index + + Index of new symbols in 3.56 + + Index of new symbols in 3.54 diff --git a/po/POTFILES.in b/po/POTFILES.in index ed7d2c30df..fe1f349ce3 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -22,7 +22,6 @@ data/org.gnome.evolution.spamassassin.gschema.xml.in data/org.gnome.evolution.text-highlight.gschema.xml.in data/org.gnome.Evolution.appdata.xml.in.in data/org.gnome.Evolution.desktop.in.in -[type: gettext/glade]data/ui/evolution-mail-viewer.ui [type: gettext/glade]data/ui/evolution-shortcuts.ui data/views/addressbook/galview.xml data/views/calendar/galview.xml @@ -244,7 +243,6 @@ src/e-util/e-online-button.c src/e-util/e-paned.c src/e-util/e-passwords.c src/e-util/e-plugin.c -src/e-util/e-popup-action.c src/e-util/e-preferences-window.c src/e-util/e-print.c src/e-util/e-proxy-editor.c @@ -548,7 +546,6 @@ src/plugins/templates/templates.c src/shell/e-shell-backend.c src/shell/e-shell.c src/shell/e-shell-content.c -src/shell/e-shell-headerbar.c src/shell/e-shell-migrate.c src/shell/e-shell-searchbar.c src/shell/e-shell-switcher.c diff --git a/src/addressbook/gui/contact-editor/e-contact-editor.c b/src/addressbook/gui/contact-editor/e-contact-editor.c index c68a80f79d..20bc012545 100644 --- a/src/addressbook/gui/contact-editor/e-contact-editor.c +++ b/src/addressbook/gui/contact-editor/e-contact-editor.c @@ -242,37 +242,12 @@ struct _EContactEditorPrivate GtkWidget *fullname_dialog; GtkWidget *categories_dialog; - GtkUIManager *ui_manager; + EUIManager *ui_manager; EFocusTracker *focus_tracker; }; G_DEFINE_TYPE_WITH_PRIVATE (EContactEditor, e_contact_editor, EAB_TYPE_EDITOR) -static GtkActionEntry undo_entries[] = { - - { "undo-menu", - "Undo menu", - NULL, - NULL, - NULL, - NULL }, /* just a fake undo menu, to get shortcuts working */ - - { "undo", - "edit-undo", - N_("_Undo"), - "z", - N_("Undo"), - NULL }, /* Handled by EFocusTracker */ - - { "redo", - "edit-redo", - N_("_Redo"), - "y", - N_("Redo"), - NULL } /* Handled by EFocusTracker */ - -}; - static void connect_closure_free (ConnectClosure *connect_closure) { @@ -5244,56 +5219,66 @@ e_contact_editor_init (EContactEditor *e_contact_editor) static void e_contact_editor_constructed (GObject *object) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry undo_entries[] = { + { "undo-menu", + NULL, + "Undo menu", + NULL, + NULL, + NULL }, /* just a fake undo menu, to get shortcuts working */ + + { "undo", + "edit-undo", + N_("_Undo"), + "z", + N_("Undo"), + NULL }, /* Handled by EFocusTracker */ + + { "redo", + "edit-redo", + N_("_Redo"), + "y", + N_("Redo"), + NULL } /* Handled by EFocusTracker */ + }; + EContactEditor *editor = E_CONTACT_EDITOR (object); - GtkActionGroup *action_group; - GtkAction *action; - GError *error = NULL; + EUIAction *action; /* Chain up to parent's method. */ G_OBJECT_CLASS (e_contact_editor_parent_class)->constructed (object); editor->priv->focus_tracker = e_focus_tracker_new (GTK_WINDOW (editor->priv->app)); - editor->priv->ui_manager = gtk_ui_manager_new (); + editor->priv->ui_manager = e_ui_manager_new (); gtk_window_add_accel_group ( GTK_WINDOW (editor->priv->app), - gtk_ui_manager_get_accel_group (editor->priv->ui_manager)); + e_ui_manager_get_accel_group (editor->priv->ui_manager)); e_signal_connect_notify ( editor->priv->focus_tracker, "notify::focus", G_CALLBACK (contact_editor_focus_widget_changed_cb), editor); - action_group = gtk_action_group_new ("undo"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, undo_entries, - G_N_ELEMENTS (undo_entries), editor); - gtk_ui_manager_insert_action_group ( - editor->priv->ui_manager, action_group, 0); + e_ui_manager_add_actions_with_eui_data (editor->priv->ui_manager, "undo", GETTEXT_PACKAGE, + undo_entries, G_N_ELEMENTS (undo_entries), editor, eui); - action = gtk_action_group_get_action (action_group, "undo"); + e_ui_manager_add_action_groups_to_widget (editor->priv->ui_manager, editor->priv->app); + + action = e_ui_manager_get_action (editor->priv->ui_manager, "undo"); e_focus_tracker_set_undo_action (editor->priv->focus_tracker, action); - action = gtk_action_group_get_action (action_group, "redo"); + action = e_ui_manager_get_action (editor->priv->ui_manager, "redo"); e_focus_tracker_set_redo_action (editor->priv->focus_tracker, action); - - g_object_unref (action_group); - - gtk_ui_manager_add_ui_from_string (editor->priv->ui_manager, ui, -1, &error); - if (error != NULL) { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } } static void diff --git a/src/addressbook/gui/widgets/e-addressbook-view.c b/src/addressbook/gui/widgets/e-addressbook-view.c index 4a0a99c653..cf4aedcc19 100644 --- a/src/addressbook/gui/widgets/e-addressbook-view.c +++ b/src/addressbook/gui/widgets/e-addressbook-view.c @@ -956,7 +956,7 @@ addressbook_view_update_actions (ESelectable *selectable, gint n_clipboard_targets) { EAddressbookView *view; - GtkAction *action; + EUIAction *action; GtkTargetList *target_list; gboolean can_paste = FALSE; gboolean source_is_editable; @@ -980,32 +980,32 @@ addressbook_view_update_actions (ESelectable *selectable, action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); sensitive = source_is_editable && (n_selected > 0); tooltip = _("Cut selected contacts to the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); sensitive = (n_selected > 0); tooltip = _("Copy selected contacts to the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); sensitive = source_is_editable && can_paste; tooltip = _("Paste contacts from the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_delete_selection_action (focus_tracker); sensitive = source_is_editable && (n_selected > 0); tooltip = _("Delete selected contacts"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_select_all_action (focus_tracker); sensitive = (n_contacts > 0); tooltip = _("Select all visible contacts"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); } static void diff --git a/src/addressbook/gui/widgets/eab-contact-display.c b/src/addressbook/gui/widgets/eab-contact-display.c index 349e5080d5..7a188b1478 100644 --- a/src/addressbook/gui/widgets/eab-contact-display.c +++ b/src/addressbook/gui/widgets/eab-contact-display.c @@ -57,18 +57,6 @@ enum { LAST_SIGNAL }; -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -""; - static guint signals[LAST_SIGNAL]; G_DEFINE_TYPE_WITH_PRIVATE (EABContactDisplay, eab_contact_display, E_TYPE_WEB_VIEW) @@ -90,9 +78,11 @@ contact_display_emit_send_message (EABContactDisplay *display, } static void -action_contact_mailto_copy_cb (GtkAction *action, - EABContactDisplay *display) +action_contact_mailto_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EABContactDisplay *display = user_data; GtkClipboard *clipboard; EWebView *web_view; EContact *contact; @@ -121,9 +111,11 @@ action_contact_mailto_copy_cb (GtkAction *action, } static void -action_contact_send_message_cb (GtkAction *action, - EABContactDisplay *display) +action_contact_send_message_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EABContactDisplay *display = user_data; EWebView *web_view; const gchar *uri; gint index; @@ -136,23 +128,6 @@ action_contact_send_message_cb (GtkAction *action, contact_display_emit_send_message (display, index); } -static GtkActionEntry internal_mailto_entries[] = { - - { "contact-mailto-copy", - "edit-copy", - N_("Copy _Email Address"), - "c", - N_("Copy the email address to the clipboard"), - G_CALLBACK (action_contact_mailto_copy_cb) }, - - { "contact-send-message", - "mail-message-new", - N_("_Send New Message To…"), - NULL, - N_("Send a mail message to this address"), - G_CALLBACK (action_contact_send_message_cb) } -}; - static void load_contact (EABContactDisplay *display) { @@ -340,15 +315,14 @@ contact_display_content_loaded_cb (EWebView *web_view, static void contact_display_update_actions (EWebView *web_view) { - GtkActionGroup *action_group; + EUIActionGroup *action_group; gboolean scheme_is_internal_mailto; gboolean visible; const gchar *group_name; const gchar *uri; /* Chain up to parent's update_actions() method. */ - E_WEB_VIEW_CLASS (eab_contact_display_parent_class)-> - update_actions (web_view); + E_WEB_VIEW_CLASS (eab_contact_display_parent_class)->update_actions (web_view); uri = e_web_view_get_selected_uri (web_view); @@ -358,14 +332,14 @@ contact_display_update_actions (EWebView *web_view) /* Override how EWebView treats internal-mailto URIs. */ group_name = "uri"; action_group = e_web_view_get_action_group (web_view, group_name); - visible = gtk_action_group_get_visible (action_group); + visible = e_ui_action_group_get_visible (action_group); visible &= !scheme_is_internal_mailto; - gtk_action_group_set_visible (action_group, visible); + e_ui_action_group_set_visible (action_group, visible); group_name = "internal-mailto"; visible = scheme_is_internal_mailto; action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + e_ui_action_group_set_visible (action_group, visible); } static void @@ -463,12 +437,38 @@ eab_contact_display_class_init (EABContactDisplayClass *class) static void eab_contact_display_init (EABContactDisplay *display) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry internal_mailto_entries[] = { + + { "contact-mailto-copy", + "edit-copy", + N_("Copy _Email Address"), + "c", + N_("Copy the email address to the clipboard"), + action_contact_mailto_copy_cb, NULL, NULL, NULL }, + + { "contact-send-message", + "mail-message-new", + N_("_Send New Message To…"), + NULL, + N_("Send a mail message to this address"), + action_contact_send_message_cb, NULL, NULL, NULL } + }; + EWebView *web_view; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; + EUIManager *ui_manager; GSettings *settings; - const gchar *domain = GETTEXT_PACKAGE; - GError *error = NULL; display->priv = eab_contact_display_get_instance_private (display); @@ -486,21 +486,8 @@ eab_contact_display_init (EABContactDisplay *display) web_view, "style-updated", G_CALLBACK (load_contact), NULL); - action_group = gtk_action_group_new ("internal-mailto"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - gtk_action_group_add_actions ( - action_group, internal_mailto_entries, - G_N_ELEMENTS (internal_mailto_entries), display); - - /* Because we are loading from a hard-coded string, there is - * no chance of I/O errors. Failure here implies a malformed - * UI definition. Full stop. */ - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) - g_error ("%s", error->message); + e_ui_manager_add_actions_with_eui_data (ui_manager, "internal-mailto", NULL, + internal_mailto_entries, G_N_ELEMENTS (internal_mailto_entries), display, eui); settings = e_util_ref_settings ("org.gnome.evolution.addressbook"); g_signal_connect_object (settings, "changed::preview-home-before-work", diff --git a/src/calendar/gui/e-calendar-view.c b/src/calendar/gui/e-calendar-view.c index 8a2a6e7a44..fee35afdf6 100644 --- a/src/calendar/gui/e-calendar-view.c +++ b/src/calendar/gui/e-calendar-view.c @@ -420,7 +420,7 @@ calendar_view_update_actions (ESelectable *selectable, gint n_clipboard_targets) { ECalendarView *view; - GtkAction *action; + EUIAction *action; GtkTargetList *target_list; GSList *selected, *link; gboolean can_paste = FALSE; @@ -463,26 +463,26 @@ calendar_view_update_actions (ESelectable *selectable, action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable && !is_editing; tooltip = _("Cut selected events to the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && !is_editing; tooltip = _("Copy selected events to the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); sensitive = sources_are_editable && can_paste && !is_editing; tooltip = _("Paste events from the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_delete_selection_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable && !recurring && !is_editing; tooltip = _("Delete selected events"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); } static void diff --git a/src/calendar/gui/e-comp-editor-event.c b/src/calendar/gui/e-comp-editor-event.c index 675f899c30..873f646aca 100644 --- a/src/calendar/gui/e-comp-editor-event.c +++ b/src/calendar/gui/e-comp-editor-event.c @@ -52,16 +52,6 @@ struct _ECompEditorEventPrivate { G_DEFINE_TYPE_WITH_PRIVATE (ECompEditorEvent, e_comp_editor_event, E_TYPE_COMP_EDITOR) -static void -ece_event_action_classification_cb (GtkRadioAction *action, - GtkRadioAction *current, - ECompEditorEvent *event_editor) -{ - g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor)); - - e_comp_editor_set_changed (E_COMP_EDITOR (event_editor), TRUE); -} - static void ece_event_update_times (ECompEditorEvent *event_editor, EDateEdit *date_edit, @@ -166,7 +156,7 @@ ece_event_sensitize_widgets (ECompEditor *comp_editor, { ECompEditorEvent *event_editor; gboolean is_organizer; - GtkAction *action; + EUIAction *action; GtkWidget *widget; guint32 flags; @@ -197,18 +187,18 @@ ece_event_sensitize_widgets (ECompEditor *comp_editor, #undef sensitize_part action = e_comp_editor_get_action (comp_editor, "all-day-event"); - gtk_action_set_sensitive (action, !force_insensitive); + e_ui_action_set_sensitive (action, !force_insensitive); /* Disable radio items, instead of the whole submenu, to see the value with read-only events/calendars. */ action = e_comp_editor_get_action (comp_editor, "classify-private"); - gtk_action_set_sensitive (action, !force_insensitive); + e_ui_action_set_sensitive (action, !force_insensitive); action = e_comp_editor_get_action (comp_editor, "classify-confidential"); - gtk_action_set_sensitive (action, !force_insensitive); + e_ui_action_set_sensitive (action, !force_insensitive); action = e_comp_editor_get_action (comp_editor, "classify-public"); - gtk_action_set_sensitive (action, !force_insensitive); + e_ui_action_set_sensitive (action, !force_insensitive); if (event_editor->priv->insensitive_info_alert) e_alert_response (event_editor->priv->insensitive_info_alert, GTK_RESPONSE_OK); @@ -387,10 +377,10 @@ ece_event_update_timezone (ECompEditorEvent *event_editor, (g_strcmp0 (i_cal_timezone_get_location (zone), i_cal_timezone_get_location (cfg_zone)) != 0 || g_strcmp0 (i_cal_timezone_get_tzid (zone), i_cal_timezone_get_tzid (cfg_zone)) != 0)) { /* Show timezone part */ - GtkAction *action; + EUIAction *action; action = e_comp_editor_get_action (comp_editor, "view-timezone"); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + e_ui_action_set_active (action, TRUE); } } @@ -410,10 +400,10 @@ ece_event_fill_widgets (ECompEditor *comp_editor, ICalComponent *component) { ECompEditorEvent *event_editor; + EUIAction *action; ICalTime *dtstart, *dtend; ICalProperty *prop; gboolean all_day_event = FALSE; - GtkAction *action; guint32 flags; g_return_if_fail (E_IS_COMP_EDITOR_EVENT (comp_editor)); @@ -513,7 +503,7 @@ ece_event_fill_widgets (ECompEditor *comp_editor, g_object_unref (settings); } - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + e_ui_action_set_active (action, TRUE); g_clear_object (&dtstart); g_clear_object (&dtend); @@ -537,10 +527,10 @@ ece_event_fill_component (ECompEditor *comp_editor, ICalComponent *component) { ECompEditorEvent *event_editor; - gboolean date_valid, time_valid; ICalProperty *dtstart_prop, *dtend_prop; ICalProperty *prop; ICalProperty_Class class_value; + gboolean date_valid, time_valid; g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), FALSE); g_return_val_if_fail (I_CAL_IS_COMPONENT (component), FALSE); @@ -637,11 +627,9 @@ ece_event_fill_component (ECompEditor *comp_editor, g_clear_object (&dtstart_prop); g_clear_object (&dtend_prop); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION ( - e_comp_editor_get_action (comp_editor, "classify-private")))) + if (e_ui_action_get_active (e_comp_editor_get_action (comp_editor, "classify-private"))) class_value = I_CAL_CLASS_PRIVATE; - else if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION ( - e_comp_editor_get_action (comp_editor, "classify-confidential")))) + else if (e_ui_action_get_active (e_comp_editor_get_action (comp_editor, "classify-confidential"))) class_value = I_CAL_CLASS_CONFIDENTIAL; else class_value = I_CAL_CLASS_PUBLIC; @@ -674,7 +662,7 @@ ece_event_notify_target_client_cb (GObject *object, gpointer user_data) { ECompEditorEvent *event_editor; - GtkAction *action; + EUIAction *action; g_return_if_fail (E_IS_COMP_EDITOR_EVENT (object)); @@ -710,10 +698,10 @@ transform_toggle_to_timezone_visible_cb (GBinding *binding, gpointer user_data) { ECompEditor *comp_editor = user_data; - GtkToggleAction *action = GTK_TOGGLE_ACTION (e_comp_editor_get_action (comp_editor, "view-timezone")); + EUIAction *action = e_comp_editor_get_action (comp_editor, "view-timezone"); g_value_set_boolean (to_value, - gtk_toggle_action_get_active (action) && + e_ui_action_get_active (action) && (!g_value_get_boolean (from_value) || ece_event_client_needs_all_day_as_time (comp_editor))); return TRUE; @@ -734,129 +722,123 @@ transform_all_day_check_to_action_sensitive_cb (GBinding *binding, return TRUE; } +static void +ece_event_classification_radio_set_state_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + ECompEditor *self = user_data; + + g_return_if_fail (E_IS_COMP_EDITOR_EVENT (self)); + + e_ui_action_set_state (action, parameter); + + e_comp_editor_set_changed (self, TRUE); +} + static void ece_event_setup_ui (ECompEditorEvent *event_editor) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " \n" - " \n" - " \n" - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - const GtkToggleActionEntry view_actions[] = { + static const EUIActionEntry entries[] = { { "view-categories", NULL, N_("_Categories"), NULL, N_("Toggles whether to display categories"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "view-timezone", "stock_timezone", N_("Time _Zone"), NULL, N_("Toggles whether the time zone is displayed"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "all-day-event", "stock_new-24h-appointment", N_("All _Day Event"), "Y", N_("Toggles whether to have All Day Event"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "show-time-busy", "dialog-error", N_("Show Time as _Busy"), NULL, N_("Toggles whether to show time as busy"), - NULL, - FALSE } - }; - - const GtkRadioActionEntry classification_radio_entries[] = { + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "classify-public", NULL, N_("Pu_blic"), NULL, N_("Classify as public"), - I_CAL_CLASS_PUBLIC }, + NULL, "s", "'public'", ece_event_classification_radio_set_state_cb }, { "classify-private", NULL, N_("_Private"), NULL, N_("Classify as private"), - I_CAL_CLASS_PRIVATE }, + NULL, "s", "'private'", ece_event_classification_radio_set_state_cb }, { "classify-confidential", NULL, N_("_Confidential"), NULL, N_("Classify as confidential"), - I_CAL_CLASS_CONFIDENTIAL } + NULL, "s", "'confidential'", ece_event_classification_radio_set_state_cb } }; ECompEditor *comp_editor; GSettings *settings; - GtkUIManager *ui_manager; - GtkAction *action; - GtkActionGroup *action_group; + EUIManager *ui_manager; + EUIAction *action; GtkWidget *widget; - GError *error = NULL; g_return_if_fail (E_IS_COMP_EDITOR_EVENT (event_editor)); comp_editor = E_COMP_EDITOR (event_editor); settings = e_comp_editor_get_settings (comp_editor); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_add_toggle_actions (action_group, - view_actions, G_N_ELEMENTS (view_actions), event_editor); - - gtk_action_group_add_radio_actions ( - action_group, classification_radio_entries, - G_N_ELEMENTS (classification_radio_entries), - I_CAL_CLASS_PUBLIC, - G_CALLBACK (ece_event_action_classification_cb), event_editor); - - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - e_plugin_ui_register_manager (ui_manager, "org.gnome.evolution.event-editor", event_editor); - e_plugin_ui_enable_manager (ui_manager, "org.gnome.evolution.event-editor"); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), event_editor, eui); action = e_comp_editor_get_action (comp_editor, "view-categories"); e_binding_bind_property ( diff --git a/src/calendar/gui/e-comp-editor-memo.c b/src/calendar/gui/e-comp-editor-memo.c index d554280206..a63eaddab0 100644 --- a/src/calendar/gui/e-comp-editor-memo.c +++ b/src/calendar/gui/e-comp-editor-memo.c @@ -123,7 +123,7 @@ ece_memo_notify_target_client_cb (GObject *object, ECompEditorMemo *memo_editor; ECompEditor *comp_editor; ECalClient *cal_client; - GtkAction *action; + EUIAction *action; GtkWidget *description_widget; GtkTextBuffer *text_buffer; gboolean supports_date; @@ -163,10 +163,10 @@ ece_memo_notify_target_client_cb (GObject *object, gtk_widget_hide (GTK_WIDGET (memo_editor->priv->attachments_page)); action = e_comp_editor_get_action (comp_editor, "view-categories"); - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_comp_editor_get_action (comp_editor, "option-attendees"); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); } else { supports_date = !cal_client || !e_client_check_capability (E_CLIENT (cal_client), E_CAL_STATIC_CAPABILITY_NO_MEMO_START_DATE); @@ -185,10 +185,10 @@ ece_memo_notify_target_client_cb (GObject *object, gtk_widget_show (GTK_WIDGET (memo_editor->priv->attachments_page)); action = e_comp_editor_get_action (comp_editor, "view-categories"); - gtk_action_set_sensitive (action, TRUE); + e_ui_action_set_sensitive (action, TRUE); action = e_comp_editor_get_action (comp_editor, "option-attendees"); - gtk_action_set_visible (action, TRUE); + e_ui_action_set_visible (action, TRUE); } } @@ -241,53 +241,39 @@ ece_memo_sensitize_widgets (ECompEditor *comp_editor, static void ece_memo_setup_ui (ECompEditorMemo *memo_editor) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + ""; - const GtkToggleActionEntry view_actions[] = { + static const EUIActionEntry view_actions[] = { { "view-categories", NULL, N_("_Categories"), NULL, N_("Toggles whether to display categories"), - NULL, - FALSE } + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state } }; ECompEditor *comp_editor; GSettings *settings; - GtkUIManager *ui_manager; - GtkAction *action; - GtkActionGroup *action_group; - GError *error = NULL; + EUIManager *ui_manager; + EUIAction *action; g_return_if_fail (E_IS_COMP_EDITOR_MEMO (memo_editor)); comp_editor = E_COMP_EDITOR (memo_editor); settings = e_comp_editor_get_settings (comp_editor); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_add_toggle_actions (action_group, - view_actions, G_N_ELEMENTS (view_actions), memo_editor); - - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - e_plugin_ui_register_manager (ui_manager, "org.gnome.evolution.memo-editor", memo_editor); - e_plugin_ui_enable_manager (ui_manager, "org.gnome.evolution.memo-editor"); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + view_actions, G_N_ELEMENTS (view_actions), memo_editor, eui); action = e_comp_editor_get_action (comp_editor, "view-categories"); e_binding_bind_property ( diff --git a/src/calendar/gui/e-comp-editor-page-attachments.c b/src/calendar/gui/e-comp-editor-page-attachments.c index b4ca64ea42..2326e55332 100644 --- a/src/calendar/gui/e-comp-editor-page-attachments.c +++ b/src/calendar/gui/e-comp-editor-page-attachments.c @@ -88,9 +88,11 @@ ecep_before_properties_popup_cb (EAttachmentView *view, } static void -ecep_attachments_action_attach_cb (GtkAction *action, - ECompEditorPageAttachments *page_attachments) +ecep_attachments_action_attach_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPageAttachments *page_attachments = user_data; ECompEditor *comp_editor; EAttachmentStore *store; @@ -105,9 +107,12 @@ ecep_attachments_action_attach_cb (GtkAction *action, } static void -ecep_attachments_select_page_cb (GtkAction *action, - ECompEditorPage *page) +ecep_attachments_select_page_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPage *page = user_data; + g_return_if_fail (E_IS_COMP_EDITOR_PAGE_ATTACHMENTS (page)); e_comp_editor_page_select (page); @@ -256,7 +261,7 @@ ecep_attachments_sensitize_widgets (ECompEditorPage *page, gboolean force_insensitive) { ECompEditor *comp_editor; - GtkAction *action; + EUIAction *action; g_return_if_fail (E_IS_COMP_EDITOR_PAGE_ATTACHMENTS (page)); @@ -265,7 +270,7 @@ ecep_attachments_sensitize_widgets (ECompEditorPage *page, comp_editor = e_comp_editor_page_ref_editor (page); action = e_comp_editor_get_action (comp_editor, "attachments-attach"); - gtk_action_set_sensitive (action, !force_insensitive); + e_ui_action_set_sensitive (action, !force_insensitive); g_clear_object (&comp_editor); } @@ -748,80 +753,67 @@ ecep_attachments_dispose (GObject *object) static void ecep_attachments_setup_ui (ECompEditorPageAttachments *page_attachments) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - GtkActionEntry editable_entries[] = { + static const EUIActionEntry editable_entries[] = { { "attachments-attach", "mail-attachment", N_("_Attachment…"), "m", N_("Attach a file"), - G_CALLBACK (ecep_attachments_action_attach_cb) } + ecep_attachments_action_attach_cb, NULL, NULL, NULL } }; - GtkActionEntry options_entries[] = { + static const EUIActionEntry options_entries[] = { { "page-attachments", "mail-attachment", N_("_Attachments"), NULL, N_("Show attachments"), - G_CALLBACK (ecep_attachments_select_page_cb) } + ecep_attachments_select_page_cb, NULL, NULL, NULL } }; ECompEditor *comp_editor; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GtkAction *action; - GError *error = NULL; + EUIManager *ui_manager; + EUIAction *action; g_return_if_fail (E_IS_COMP_EDITOR_PAGE_ATTACHMENTS (page_attachments)); comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_attachments)); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = e_comp_editor_get_action_group (comp_editor, "editable"); - gtk_action_group_add_actions ( - action_group, editable_entries, - G_N_ELEMENTS (editable_entries), page_attachments); + e_ui_manager_add_actions (ui_manager, "editable", GETTEXT_PACKAGE, + editable_entries, G_N_ELEMENTS (editable_entries), page_attachments); - action = gtk_action_group_get_action (action_group, "attachments-attach"); + action = e_comp_editor_get_action (comp_editor, "attachments-attach"); e_binding_bind_property ( page_attachments, "visible", action, "visible", G_BINDING_SYNC_CREATE); - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + options_entries, G_N_ELEMENTS (options_entries), page_attachments, eui); - gtk_action_group_add_actions ( - action_group, options_entries, - G_N_ELEMENTS (options_entries), page_attachments); - - action = gtk_action_group_get_action (action_group, "page-attachments"); + action = e_comp_editor_get_action (comp_editor, "page-attachments"); e_binding_bind_property ( page_attachments, "visible", action, "visible", G_BINDING_SYNC_CREATE); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) { - g_warning ("%s: Failed to add UI from string: %s", G_STRFUNC, error->message); - g_error_free (error); - } - g_clear_object (&comp_editor); } @@ -830,11 +822,11 @@ ecep_attachments_constructed (GObject *object) { ECompEditorPageAttachments *page_attachments; ECompEditor *comp_editor; + EUIAction *action; GSettings *settings; GtkSizeGroup *size_group; GtkWidget *container; GtkWidget *widget; - GtkAction *action; G_OBJECT_CLASS (e_comp_editor_page_attachments_parent_class)->constructed (object); @@ -939,7 +931,7 @@ ecep_attachments_constructed (GObject *object) widget = gtk_button_new (); action = e_attachment_view_get_action (E_ATTACHMENT_VIEW (page_attachments->priv->icon_view), "add-uri"); gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ()); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action); + e_ui_action_util_assign_to_widget (action, widget); gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0); gtk_widget_show (widget); @@ -950,7 +942,7 @@ ecep_attachments_constructed (GObject *object) widget = gtk_button_new (); action = e_attachment_view_get_action (E_ATTACHMENT_VIEW (page_attachments->priv->icon_view), "add"); gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ()); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action); + e_ui_action_util_assign_to_widget (action, widget); gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0); gtk_widget_show (widget); diff --git a/src/calendar/gui/e-comp-editor-page-general.c b/src/calendar/gui/e-comp-editor-page-general.c index 70806c284d..a91172cd78 100644 --- a/src/calendar/gui/e-comp-editor-page-general.c +++ b/src/calendar/gui/e-comp-editor-page-general.c @@ -92,43 +92,63 @@ ecep_general_set_column_visible (ECompEditorPageGeneral *page_general, } static void -action_view_role_cb (GtkToggleAction *action, - ECompEditorPageGeneral *page_general) +action_view_role_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPageGeneral *page_general = user_data; + g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general)); + e_ui_action_set_active (action, !e_ui_action_get_active (action)); + ecep_general_set_column_visible (page_general, E_MEETING_STORE_ROLE_COL, - gtk_toggle_action_get_active (action)); + e_ui_action_get_active (action)); } static void -action_view_rsvp_cb (GtkToggleAction *action, - ECompEditorPageGeneral *page_general) +action_view_rsvp_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPageGeneral *page_general = user_data; + g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general)); + e_ui_action_set_active (action, !e_ui_action_get_active (action)); + ecep_general_set_column_visible (page_general, E_MEETING_STORE_RSVP_COL, - gtk_toggle_action_get_active (action)); + e_ui_action_get_active (action)); } static void -action_view_status_cb (GtkToggleAction *action, - ECompEditorPageGeneral *page_general) +action_view_status_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPageGeneral *page_general = user_data; + g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general)); + e_ui_action_set_active (action, !e_ui_action_get_active (action)); + ecep_general_set_column_visible (page_general, E_MEETING_STORE_STATUS_COL, - gtk_toggle_action_get_active (action)); + e_ui_action_get_active (action)); } static void -action_view_type_cb (GtkToggleAction *action, - ECompEditorPageGeneral *page_general) +action_view_type_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPageGeneral *page_general = user_data; + g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general)); + e_ui_action_set_active (action, !e_ui_action_get_active (action)); + ecep_general_set_column_visible (page_general, E_MEETING_STORE_TYPE_COL, - gtk_toggle_action_get_active (action)); + e_ui_action_get_active (action)); } static void @@ -682,76 +702,67 @@ static void ecep_general_init_ui (ECompEditorPageGeneral *page_general, ECompEditor *comp_editor) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - - const GtkToggleActionEntry attendees_toggle_entry[] = { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + static const EUIActionEntry attendees_toggle_entry[] = { { "option-attendees", NULL, N_("A_ttendees"), NULL, N_("Toggles whether the Attendees are displayed"), - NULL, - FALSE } + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state } }; - const GtkToggleActionEntry columns_toggle_entries[] = { - + static const EUIActionEntry columns_toggle_entries[] = { { "view-role", NULL, N_("R_ole Field"), NULL, N_("Toggles whether the Role field is displayed"), - G_CALLBACK (action_view_role_cb), - TRUE }, + NULL, NULL, "true", action_view_role_cb }, { "view-rsvp", NULL, N_("_RSVP"), NULL, N_("Toggles whether the RSVP field is displayed"), - G_CALLBACK (action_view_rsvp_cb), - TRUE }, + NULL, NULL, "true", action_view_rsvp_cb }, { "view-status", NULL, N_("_Status Field"), NULL, N_("Toggles whether the Status field is displayed"), - G_CALLBACK (action_view_status_cb), - TRUE }, + NULL, NULL, "true", action_view_status_cb }, { "view-type", NULL, N_("_Type Field"), NULL, N_("Toggles whether the Attendee Type is displayed"), - G_CALLBACK (action_view_type_cb), - TRUE } + NULL, NULL, "true", action_view_type_cb } }; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GtkAction *action; + EUIManager *ui_manager; + EUIAction *action; GSettings *settings; - GError *error = NULL; g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page_general)); g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); @@ -759,33 +770,16 @@ ecep_general_init_ui (ECompEditorPageGeneral *page_general, settings = e_comp_editor_get_settings (comp_editor); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = gtk_action_group_new ("columns"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_toggle_actions ( - action_group, columns_toggle_entries, - G_N_ELEMENTS (columns_toggle_entries), page_general); - gtk_ui_manager_insert_action_group ( - ui_manager, action_group, 0); + e_ui_manager_add_actions (ui_manager, "columns", GETTEXT_PACKAGE, + columns_toggle_entries, G_N_ELEMENTS (columns_toggle_entries), page_general); e_binding_bind_property ( page_general, "show-attendees", - action_group, "sensitive", + e_ui_manager_get_action_group (ui_manager, "columns"), "sensitive", G_BINDING_SYNC_CREATE); - g_object_unref (action_group); - - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_add_toggle_actions ( - action_group, attendees_toggle_entry, - G_N_ELEMENTS (attendees_toggle_entry), page_general); - - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + attendees_toggle_entry, G_N_ELEMENTS (attendees_toggle_entry), page_general, eui); action = e_comp_editor_get_action (comp_editor, "option-attendees"); e_binding_bind_property ( @@ -798,24 +792,32 @@ ecep_general_init_ui (ECompEditorPageGeneral *page_general, settings, "editor-show-role", action, "active", G_SETTINGS_BIND_DEFAULT); + ecep_general_set_column_visible (page_general, E_MEETING_STORE_ROLE_COL, + e_ui_action_get_active (action)); action = e_comp_editor_get_action (comp_editor, "view-rsvp"); g_settings_bind ( settings, "editor-show-rsvp", action, "active", G_SETTINGS_BIND_DEFAULT); + ecep_general_set_column_visible (page_general, E_MEETING_STORE_RSVP_COL, + e_ui_action_get_active (action)); action = e_comp_editor_get_action (comp_editor, "view-status"); g_settings_bind ( settings, "editor-show-status", action, "active", G_SETTINGS_BIND_DEFAULT); + ecep_general_set_column_visible (page_general, E_MEETING_STORE_STATUS_COL, + e_ui_action_get_active (action)); action = e_comp_editor_get_action (comp_editor, "view-type"); g_settings_bind ( settings, "editor-show-type", action, "active", G_SETTINGS_BIND_DEFAULT); + ecep_general_set_column_visible (page_general, E_MEETING_STORE_TYPE_COL, + e_ui_action_get_active (action)); } static void @@ -824,10 +826,10 @@ ecep_general_sensitize_widgets (ECompEditorPage *page, { ECompEditorPageGeneral *page_general; GtkTreeSelection *selection; - GtkAction *action; gboolean sensitive, organizer_is_user, delegate, delegate_to_many = FALSE, read_only = TRUE, any_selected = FALSE; ECompEditor *comp_editor; ECalClient *client; + EUIAction *action; guint32 flags; g_return_if_fail (E_IS_COMP_EDITOR_PAGE_GENERAL (page)); @@ -871,7 +873,7 @@ ecep_general_sensitize_widgets (ECompEditorPage *page, gtk_widget_set_sensitive (page_general->priv->attendees_list_view, !read_only && !force_insensitive); action = e_comp_editor_get_action (comp_editor, "option-attendees"); - gtk_action_set_sensitive (action, !force_insensitive && !read_only); + e_ui_action_set_sensitive (action, !force_insensitive && !read_only); if (page_general->priv->comp_color && !e_comp_editor_property_part_get_sensitize_handled (page_general->priv->comp_color)) { diff --git a/src/calendar/gui/e-comp-editor-page-recurrence.c b/src/calendar/gui/e-comp-editor-page-recurrence.c index 5355755e2a..1a4482b764 100644 --- a/src/calendar/gui/e-comp-editor-page-recurrence.c +++ b/src/calendar/gui/e-comp-editor-page-recurrence.c @@ -2010,9 +2010,12 @@ ecep_recurrence_fill_component (ECompEditorPage *page, } static void -ecep_recurrence_select_page_cb (GtkAction *action, - ECompEditorPage *page) +ecep_recurrence_select_page_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPage *page = user_data; + g_return_if_fail (E_IS_COMP_EDITOR_PAGE_RECURRENCE (page)); e_comp_editor_page_select (page); @@ -2021,44 +2024,39 @@ ecep_recurrence_select_page_cb (GtkAction *action, static void ecep_recurrence_setup_ui (ECompEditorPageRecurrence *page_recurrence) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + ""; - const GtkActionEntry options_actions[] = { + static const EUIActionEntry options_actions[] = { { "page-recurrence", "stock_task-recurring", N_("R_ecurrence"), NULL, N_("Set or unset recurrence"), - G_CALLBACK (ecep_recurrence_select_page_cb) } + ecep_recurrence_select_page_cb, NULL, NULL, NULL } }; ECompEditor *comp_editor; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GtkAction *action; - GError *error = NULL; + EUIManager *ui_manager; + EUIAction *action; g_return_if_fail (E_IS_COMP_EDITOR_PAGE_RECURRENCE (page_recurrence)); comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_recurrence)); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_add_actions (action_group, - options_actions, G_N_ELEMENTS (options_actions), page_recurrence); + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + options_actions, G_N_ELEMENTS (options_actions), page_recurrence, eui); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - action = gtk_action_group_get_action (action_group, "page-recurrence"); + action = e_comp_editor_get_action (comp_editor, "page-recurrence"); if (action) { e_binding_bind_property ( page_recurrence, "visible", @@ -2067,11 +2065,6 @@ ecep_recurrence_setup_ui (ECompEditorPageRecurrence *page_recurrence) } g_clear_object (&comp_editor); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } } static void diff --git a/src/calendar/gui/e-comp-editor-page-reminders.c b/src/calendar/gui/e-comp-editor-page-reminders.c index 68661b5683..2ff89a735f 100644 --- a/src/calendar/gui/e-comp-editor-page-reminders.c +++ b/src/calendar/gui/e-comp-editor-page-reminders.c @@ -1677,9 +1677,12 @@ ecep_reminders_fill_component (ECompEditorPage *page, } static void -ecep_reminders_select_page_cb (GtkAction *action, - ECompEditorPage *page) +ecep_reminders_select_page_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPage *page = user_data; + g_return_if_fail (E_IS_COMP_EDITOR_PAGE_REMINDERS (page)); e_comp_editor_page_select (page); @@ -1688,44 +1691,39 @@ ecep_reminders_select_page_cb (GtkAction *action, static void ecep_reminders_setup_ui (ECompEditorPageReminders *page_reminders) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + ""; - const GtkActionEntry options_actions[] = { + static const EUIActionEntry options_actions[] = { { "page-reminders", "appointment-soon", N_("_Reminders"), NULL, N_("Set or unset reminders"), - G_CALLBACK (ecep_reminders_select_page_cb) } + ecep_reminders_select_page_cb, NULL, NULL, NULL } }; ECompEditor *comp_editor; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GtkAction *action; - GError *error = NULL; + EUIManager *ui_manager; + EUIAction *action; g_return_if_fail (E_IS_COMP_EDITOR_PAGE_REMINDERS (page_reminders)); comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_reminders)); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_add_actions (action_group, - options_actions, G_N_ELEMENTS (options_actions), page_reminders); + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + options_actions, G_N_ELEMENTS (options_actions), page_reminders, eui); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - action = gtk_action_group_get_action (action_group, "page-reminders"); + action = e_comp_editor_get_action (comp_editor, "page-reminders"); if (action) { e_binding_bind_property ( page_reminders, "visible", @@ -1734,11 +1732,6 @@ ecep_reminders_setup_ui (ECompEditorPageReminders *page_reminders) } g_clear_object (&comp_editor); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } } static gboolean diff --git a/src/calendar/gui/e-comp-editor-page-schedule.c b/src/calendar/gui/e-comp-editor-page-schedule.c index 6310b8b021..81e78abe88 100644 --- a/src/calendar/gui/e-comp-editor-page-schedule.c +++ b/src/calendar/gui/e-comp-editor-page-schedule.c @@ -477,9 +477,12 @@ e_comp_editor_page_schedule_get_property (GObject *object, } static void -ecep_schedule_select_page_cb (GtkAction *action, - ECompEditorPage *page) +ecep_schedule_select_page_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditorPage *page = user_data; + g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page)); e_comp_editor_page_select (page); @@ -488,47 +491,37 @@ ecep_schedule_select_page_cb (GtkAction *action, static void ecep_schedule_setup_ui (ECompEditorPageSchedule *page_schedule) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + ""; - const GtkActionEntry options_actions[] = { + static const EUIActionEntry options_actions[] = { { "page-schedule", "query-free-busy", N_("_Schedule"), NULL, N_("Query free / busy information for the attendees"), - G_CALLBACK (ecep_schedule_select_page_cb) } + ecep_schedule_select_page_cb, NULL, NULL, NULL } }; ECompEditor *comp_editor; - GtkUIManager *ui_manager; - GtkAction *action; - GtkActionGroup *action_group; - GError *error = NULL; + EUIManager *ui_manager; + EUIAction *action; g_return_if_fail (E_IS_COMP_EDITOR_PAGE_SCHEDULE (page_schedule)); comp_editor = e_comp_editor_page_ref_editor (E_COMP_EDITOR_PAGE (page_schedule)); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_add_actions (action_group, - options_actions, G_N_ELEMENTS (options_actions), page_schedule); - - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + options_actions, G_N_ELEMENTS (options_actions), page_schedule, eui); action = e_comp_editor_get_action (comp_editor, "page-schedule"); e_binding_bind_property ( diff --git a/src/calendar/gui/e-comp-editor-task.c b/src/calendar/gui/e-comp-editor-task.c index 010eb5a76b..5b93862ab9 100644 --- a/src/calendar/gui/e-comp-editor-task.c +++ b/src/calendar/gui/e-comp-editor-task.c @@ -190,10 +190,10 @@ ece_task_update_timezone (ECompEditorTask *task_editor, (g_strcmp0 (i_cal_timezone_get_location (zone), i_cal_timezone_get_location (cfg_zone)) != 0 || g_strcmp0 (i_cal_timezone_get_tzid (zone), i_cal_timezone_get_tzid (cfg_zone)) != 0)) { /* Show timezone part */ - GtkAction *action; + EUIAction *action; action = e_comp_editor_get_action (comp_editor, "view-timezone"); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + e_ui_action_set_active (action, TRUE); } } } @@ -216,8 +216,8 @@ ece_task_notify_target_client_cb (GObject *object, ECompEditorTask *task_editor; ECompEditor *comp_editor; ECalClient *cal_client; + EUIAction *action; GtkWidget *edit_widget; - GtkAction *action; gboolean date_only; gboolean was_allday; gboolean can_recur; @@ -231,7 +231,7 @@ ece_task_notify_target_client_cb (GObject *object, cal_client = e_comp_editor_get_target_client (comp_editor); action = e_comp_editor_get_action (comp_editor, "all-day-task"); - was_allday = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); + was_allday = e_ui_action_get_active (action); date_only = !cal_client || e_client_check_capability (E_CLIENT (cal_client), E_CAL_STATIC_CAPABILITY_TASK_DATE_ONLY); @@ -243,14 +243,14 @@ ece_task_notify_target_client_cb (GObject *object, gtk_widget_set_sensitive (edit_widget, !date_only); action = e_comp_editor_get_action (comp_editor, "view-timezone"); - gtk_action_set_sensitive (action, !date_only); + e_ui_action_set_sensitive (action, !date_only); action = e_comp_editor_get_action (comp_editor, "all-day-task"); - gtk_action_set_visible (action, !date_only); + e_ui_action_set_visible (action, !date_only); if (was_allday) { action = e_comp_editor_get_action (comp_editor, "all-day-task"); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + e_ui_action_set_active (action, TRUE); } can_reminders = !cal_client || !e_client_check_capability (E_CLIENT (cal_client), E_CAL_STATIC_CAPABILITY_TASK_NO_ALARM); @@ -531,7 +531,7 @@ ece_task_sensitize_widgets (ECompEditor *comp_editor, gboolean force_insensitive) { ECompEditorTask *task_editor; - GtkAction *action; + EUIAction *action; gboolean is_organizer; guint32 flags; @@ -544,7 +544,7 @@ ece_task_sensitize_widgets (ECompEditor *comp_editor, task_editor = E_COMP_EDITOR_TASK (comp_editor); action = e_comp_editor_get_action (comp_editor, "all-day-task"); - gtk_action_set_sensitive (action, !force_insensitive); + e_ui_action_set_sensitive (action, !force_insensitive); if (task_editor->priv->insensitive_info_alert) e_alert_response (task_editor->priv->insensitive_info_alert, GTK_RESPONSE_OK); @@ -592,10 +592,10 @@ ece_task_fill_widgets (ECompEditor *comp_editor, E_COMP_EDITOR_CLASS (e_comp_editor_task_parent_class)->fill_widgets (comp_editor, component); if (force_allday) { - GtkAction *action; + EUIAction *action; action = e_comp_editor_get_action (comp_editor, "all-day-task"); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + e_ui_action_set_active (action, TRUE); } } @@ -774,81 +774,70 @@ ece_task_all_day_notify_active_cb (GObject *object, static void ece_task_setup_ui (ECompEditorTask *task_editor) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " \n" - " \n" - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - const GtkToggleActionEntry view_actions[] = { + static const EUIActionEntry view_actions[] = { { "view-categories", NULL, N_("_Categories"), NULL, N_("Toggles whether to display categories"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "view-timezone", "stock_timezone", N_("Time _Zone"), NULL, N_("Toggles whether the time zone is displayed"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "all-day-task", "stock_new-24h-appointment", N_("All _Day Task"), "Y", N_("Toggles whether to have All Day Task"), - NULL, - FALSE } + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state } }; ECompEditor *comp_editor; GSettings *settings; - GtkUIManager *ui_manager; - GtkAction *action; - GtkActionGroup *action_group; + EUIManager *ui_manager; + EUIAction *action; GtkWidget *edit_widget; - GError *error = NULL; g_return_if_fail (E_IS_COMP_EDITOR_TASK (task_editor)); comp_editor = E_COMP_EDITOR (task_editor); settings = e_comp_editor_get_settings (comp_editor); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_add_toggle_actions (action_group, - view_actions, G_N_ELEMENTS (view_actions), task_editor); - - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - e_plugin_ui_register_manager (ui_manager, "org.gnome.evolution.task-editor", task_editor); - e_plugin_ui_enable_manager (ui_manager, "org.gnome.evolution.task-editor"); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + view_actions, G_N_ELEMENTS (view_actions), task_editor, eui); action = e_comp_editor_get_action (comp_editor, "view-timezone"); e_binding_bind_property ( diff --git a/src/calendar/gui/e-comp-editor.c b/src/calendar/gui/e-comp-editor.c index eacd0c2cd8..5a4219b627 100644 --- a/src/calendar/gui/e-comp-editor.c +++ b/src/calendar/gui/e-comp-editor.c @@ -52,9 +52,10 @@ struct _ECompEditorPrivate { guint32 flags; EMenuBar *menu_bar; + GtkWidget *menu_button; /* owned by menu_bar */ EFocusTracker *focus_tracker; - GtkUIManager *ui_manager; + EUIManager *ui_manager; GSList *pages; /* ECompEditorPage * */ gulong show_attendees_handler_id; @@ -130,11 +131,25 @@ ece_restore_focus (ECompEditor *comp_editor) } } +static EUIActionGroup * +ece_get_action_group (ECompEditor *comp_editor, + const gchar *group_name) +{ + EUIManager *ui_manager; + + g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); + g_return_val_if_fail (group_name != NULL, NULL); + + ui_manager = e_comp_editor_get_ui_manager (comp_editor); + + return e_ui_manager_get_action_group (ui_manager, group_name); +} + static void e_comp_editor_enable (ECompEditor *comp_editor, gboolean enable) { - GtkActionGroup *group; + EUIActionGroup *group; GtkWidget *current_focus; g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); @@ -143,14 +158,14 @@ e_comp_editor_enable (ECompEditor *comp_editor, gtk_widget_set_sensitive (GTK_WIDGET (comp_editor->priv->content), enable); - group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_set_sensitive (group, enable); + group = ece_get_action_group (comp_editor, "individual"); + e_ui_action_group_set_sensitive (group, enable); - group = e_comp_editor_get_action_group (comp_editor, "core"); - gtk_action_group_set_sensitive (group, enable); + group = ece_get_action_group (comp_editor, "core"); + e_ui_action_group_set_sensitive (group, enable); - group = e_comp_editor_get_action_group (comp_editor, "editable"); - gtk_action_group_set_sensitive (group, enable); + group = ece_get_action_group (comp_editor, "editable"); + e_ui_action_group_set_sensitive (group, enable); if (enable) { e_comp_editor_sensitize_widgets (comp_editor); @@ -1433,27 +1448,32 @@ e_comp_editor_prompt_and_save_changes (ECompEditor *comp_editor, } static void -action_close_cb (GtkAction *action, - ECompEditor *comp_editor) +action_close_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); + ECompEditor *self = user_data; - if (e_comp_editor_prompt_and_save_changes (comp_editor, TRUE)) - e_comp_editor_close (comp_editor); + g_return_if_fail (E_IS_COMP_EDITOR (self)); + + if (e_comp_editor_prompt_and_save_changes (self, TRUE)) + e_comp_editor_close (self); } static void -action_help_cb (GtkAction *action, - ECompEditor *comp_editor) +action_help_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditor *self = user_data; ECompEditorClass *klass; - g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); + g_return_if_fail (E_IS_COMP_EDITOR (self)); - klass = E_COMP_EDITOR_GET_CLASS (comp_editor); + klass = E_COMP_EDITOR_GET_CLASS (self); g_return_if_fail (klass->help_section != NULL); - e_display_help (GTK_WINDOW (comp_editor), klass->help_section); + e_display_help (GTK_WINDOW (self), klass->help_section); } static void @@ -1485,31 +1505,51 @@ ece_print_or_preview (ECompEditor *comp_editor, } static void -action_print_cb (GtkAction *action, - ECompEditor *comp_editor) +action_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - ece_print_or_preview (comp_editor, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG); + ECompEditor *self = user_data; + + g_return_if_fail (E_IS_COMP_EDITOR (self)); + + ece_print_or_preview (self, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG); } static void -action_print_preview_cb (GtkAction *action, - ECompEditor *comp_editor) +action_print_preview_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - ece_print_or_preview (comp_editor, GTK_PRINT_OPERATION_ACTION_PREVIEW); + ECompEditor *self = user_data; + + g_return_if_fail (E_IS_COMP_EDITOR (self)); + + ece_print_or_preview (self, GTK_PRINT_OPERATION_ACTION_PREVIEW); } static void -action_save_cb (GtkAction *action, - ECompEditor *comp_editor) +action_save_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - e_comp_editor_save_and_close (comp_editor, FALSE); + ECompEditor *self = user_data; + + g_return_if_fail (E_IS_COMP_EDITOR (self)); + + e_comp_editor_save_and_close (self, FALSE); } static void -action_save_and_close_cb (GtkAction *action, - ECompEditor *comp_editor) +action_save_and_close_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - e_comp_editor_save_and_close (comp_editor, TRUE); + ECompEditor *self = user_data; + + g_return_if_fail (E_IS_COMP_EDITOR (self)); + + e_comp_editor_save_and_close (self, TRUE); } static gboolean @@ -1697,7 +1737,7 @@ static void ece_sensitize_widgets (ECompEditor *comp_editor, gboolean force_insensitive) { - GtkActionGroup *group; + EUIActionGroup *group; GSList *link; g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); @@ -1712,11 +1752,11 @@ ece_sensitize_widgets (ECompEditor *comp_editor, e_comp_editor_page_sensitize_widgets (page, force_insensitive); } - group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_set_sensitive (group, !force_insensitive); + group = ece_get_action_group (comp_editor, "individual"); + e_ui_action_group_set_sensitive (group, !force_insensitive); - group = e_comp_editor_get_action_group (comp_editor, "editable"); - gtk_action_group_set_sensitive (group, !force_insensitive); + group = ece_get_action_group (comp_editor, "editable"); + e_ui_action_group_set_sensitive (group, !force_insensitive); } static void @@ -1836,7 +1876,7 @@ comp_editor_delete_event (GtkWidget *widget, /* It's disabled when the component is being saved */ if (gtk_widget_get_sensitive (GTK_WIDGET (comp_editor->priv->content))) - action_close_cb (NULL, comp_editor); + action_close_cb (NULL, NULL, comp_editor); return TRUE; } @@ -1853,10 +1893,10 @@ comp_editor_key_press_event (GtkWidget *widget, if (event->keyval == GDK_KEY_Escape && !e_alert_bar_close_alert (comp_editor->priv->alert_bar)) { - GtkAction *action; + EUIAction *action; action = e_comp_editor_get_action (comp_editor, "close"); - gtk_action_activate (action); + g_action_activate (G_ACTION (action), NULL); return TRUE; } @@ -1950,38 +1990,54 @@ e_comp_editor_set_shell (ECompEditor *comp_editor, comp_editor->priv->shell = g_object_ref (shell); } -static GtkWidget * -comp_editor_construct_header_bar (ECompEditor *comp_editor, - GtkWidget *menu_button) +static gboolean +comp_editor_ui_manager_create_item_cb (EUIManager *manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) { - GtkWidget *widget; - GtkWidget *button; - GtkAction *action; - GtkHeaderBar *header_bar; + ECompEditor *self = user_data; - widget = gtk_header_bar_new (); - gtk_widget_show (widget); - header_bar = GTK_HEADER_BAR (widget); - gtk_header_bar_set_show_close_button (header_bar, TRUE); + g_return_val_if_fail (E_IS_COMP_EDITOR (self), FALSE); - if (menu_button) - gtk_header_bar_pack_end (header_bar, menu_button); + if (for_kind != E_UI_ELEMENT_KIND_HEADERBAR || + g_strcmp0 (g_action_get_name (G_ACTION (action)), "menu-button") != 0) + return FALSE; - action = e_comp_editor_get_action (comp_editor, "save-and-close"); + if (self->priv->menu_button) + *out_item = G_OBJECT (g_object_ref (self->priv->menu_button)); + else + *out_item = NULL; - button = e_header_bar_button_new (_("Save and Close"), action); - e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "suggested-action"); - e_header_bar_button_set_show_icon_only (E_HEADER_BAR_BUTTON (button), FALSE); - gtk_widget_show (button); - gtk_header_bar_pack_start (header_bar, button); + return TRUE; +} - action = e_comp_editor_get_action (comp_editor, "save"); +static gboolean +comp_editor_ui_manager_create_gicon_cb (EUIManager *manager, + const gchar *name, + GIcon **out_gicon) +{ + GIcon *icon; + GIcon *emblemed_icon; + GEmblem *emblem; - button = e_header_bar_button_new (NULL, action); - gtk_widget_show (button); - gtk_header_bar_pack_start (header_bar, button); + if (g_strcmp0 (name, "ECompEditor::save-and-close") != 0) + return FALSE; - return widget; + icon = g_themed_icon_new ("window-close"); + emblemed_icon = g_themed_icon_new ("document-save"); + emblem = g_emblem_new (emblemed_icon); + g_object_unref (emblemed_icon); + + emblemed_icon = g_emblemed_icon_new (icon, emblem); + g_object_unref (emblem); + g_object_unref (icon); + + *out_gicon = emblemed_icon; + + return TRUE; } static void @@ -2139,137 +2195,91 @@ e_comp_editor_get_property (GObject *object, static void e_comp_editor_constructed (GObject *object) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; - - GtkActionEntry core_entries[] = { + static const EUIActionEntry core_entries[] = { { "close", "window-close", N_("_Close"), "w", N_("Close the current window"), - G_CALLBACK (action_close_cb) }, + action_close_cb, NULL, NULL, NULL }, { "copy-clipboard", "edit-copy", N_("_Copy"), "c", N_("Copy the selection"), - NULL }, /* Handled by EFocusTracker */ + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ { "cut-clipboard", "edit-cut", N_("Cu_t"), "x", N_("Cut the selection"), - NULL }, /* Handled by EFocusTracker */ + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ { "delete-selection", "edit-delete", N_("_Delete"), NULL, N_("Delete the selection"), - NULL }, /* Handled by EFocusTracker */ + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ { "help", "help-browser", N_("_Help"), "F1", N_("View help"), - G_CALLBACK (action_help_cb) }, + action_help_cb, NULL, NULL, NULL }, { "paste-clipboard", "edit-paste", N_("_Paste"), "v", N_("Paste the clipboard"), - NULL }, /* Handled by EFocusTracker */ + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ { "print", "document-print", N_("_Print…"), "p", NULL, - G_CALLBACK (action_print_cb) }, + action_print_cb, NULL, NULL, NULL }, { "print-preview", "document-print-preview", N_("Pre_view…"), NULL, NULL, - G_CALLBACK (action_print_preview_cb) }, + action_print_preview_cb, NULL, NULL, NULL }, { "select-all", "edit-select-all", N_("Select _All"), "a", N_("Select all text"), - NULL }, /* Handled by EFocusTracker */ + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "show-toolbar", + NULL, + N_("Show _toolbar"), + NULL, + NULL, + NULL, NULL, "true", (EUIActionFunc) e_ui_action_set_state }, { "undo", "edit-undo", N_("_Undo"), "z", N_("Undo"), - NULL }, /* Handled by EFocusTracker */ + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ { "redo", "edit-redo", N_("_Redo"), "y", N_("Redo"), - NULL }, /* Handled by EFocusTracker */ + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ /* Menus */ @@ -2278,85 +2288,82 @@ e_comp_editor_constructed (GObject *object) N_("_Classification"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "edit-menu", NULL, N_("_Edit"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "file-menu", NULL, N_("_File"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "help-menu", NULL, N_("_Help"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "insert-menu", NULL, N_("_Insert"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, + + { "menu-button", + NULL, + N_("Menu"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, { "options-menu", NULL, N_("_Options"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "view-menu", NULL, N_("_View"), NULL, NULL, - NULL } + NULL, NULL, NULL, NULL } }; - GtkActionEntry editable_entries[] = { + static const EUIActionEntry editable_entries[] = { { "save", "document-save", N_("_Save"), "s", N_("Save current changes"), - G_CALLBACK (action_save_cb) }, + action_save_cb, NULL, NULL, NULL }, { "save-and-close", - NULL, + "gicon::ECompEditor::save-and-close", N_("Save and Close"), "Return", N_("Save current changes and close editor"), - G_CALLBACK (action_save_and_close_cb) } - }; - - GtkToggleActionEntry toggle_entries[] = { - { "show-toolbar", - NULL, - N_("Show _toolbar"), - NULL, - NULL, - NULL }, + action_save_and_close_cb, NULL, NULL, NULL } }; ECompEditor *comp_editor = E_COMP_EDITOR (object); + GObject *ui_item; GtkWidget *widget; - GtkWidget *menu_button = NULL; GtkBox *vbox; - GtkAction *action; - GtkActionGroup *action_group; + EUIAction *action; EFocusTracker *focus_tracker; - GError *error = NULL; + GError *local_error = NULL; G_OBJECT_CLASS (e_comp_editor_parent_class)->constructed (object); @@ -2364,89 +2371,51 @@ e_comp_editor_constructed (GObject *object) G_CALLBACK (e_util_check_gtk_bindings_in_key_press_event_cb), NULL); comp_editor->priv->calendar_settings = e_util_ref_settings ("org.gnome.evolution.calendar"); - comp_editor->priv->ui_manager = gtk_ui_manager_new (); + comp_editor->priv->ui_manager = e_ui_manager_new (); + + g_signal_connect (comp_editor->priv->ui_manager, "create-item", + G_CALLBACK (comp_editor_ui_manager_create_item_cb), comp_editor); + g_signal_connect (comp_editor->priv->ui_manager, "create-gicon", + G_CALLBACK (comp_editor_ui_manager_create_gicon_cb), comp_editor); gtk_window_add_accel_group ( GTK_WINDOW (comp_editor), - gtk_ui_manager_get_accel_group (comp_editor->priv->ui_manager)); + e_ui_manager_get_accel_group (comp_editor->priv->ui_manager)); /* Setup Action Groups */ - action_group = gtk_action_group_new ("individual"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_ui_manager_insert_action_group ( - comp_editor->priv->ui_manager, action_group, 0); - g_object_unref (action_group); + e_ui_manager_add_actions (comp_editor->priv->ui_manager, "core", GETTEXT_PACKAGE, + core_entries, G_N_ELEMENTS (core_entries), comp_editor); - action_group = gtk_action_group_new ("core"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, core_entries, - G_N_ELEMENTS (core_entries), comp_editor); - gtk_ui_manager_insert_action_group ( - comp_editor->priv->ui_manager, action_group, 0); - g_object_unref (action_group); + e_ui_manager_add_actions (comp_editor->priv->ui_manager, "editable", GETTEXT_PACKAGE, + editable_entries, G_N_ELEMENTS (editable_entries), comp_editor); - action_group = gtk_action_group_new ("editable"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, editable_entries, - G_N_ELEMENTS (editable_entries), comp_editor); - gtk_ui_manager_insert_action_group ( - comp_editor->priv->ui_manager, action_group, 0); - g_object_unref (action_group); + e_ui_manager_set_action_groups_widget (comp_editor->priv->ui_manager, GTK_WIDGET (comp_editor)); - action = gtk_action_group_get_action (action_group, "save-and-close"); + action = e_comp_editor_get_action (comp_editor, "save-and-close"); if (action) { - GtkAction *save_action; - GIcon *icon; - GIcon *emblemed_icon; - GEmblem *emblem; + EUIAction *save_action; - icon = g_themed_icon_new ("window-close"); - emblemed_icon = g_themed_icon_new ("document-save"); - emblem = g_emblem_new (emblemed_icon); - g_object_unref (emblemed_icon); + save_action = e_comp_editor_get_action (comp_editor, "save"); - emblemed_icon = g_emblemed_icon_new (icon, emblem); - g_object_unref (emblem); - g_object_unref (icon); - - gtk_action_set_gicon (action, emblemed_icon); - - g_object_unref (emblemed_icon); - - save_action = gtk_action_group_get_action (action_group, "save"); e_binding_bind_property ( save_action, "sensitive", action, "sensitive", G_BINDING_SYNC_CREATE); } - action_group = gtk_action_group_new ("toggle"); - gtk_action_group_add_toggle_actions ( - action_group, toggle_entries, - G_N_ELEMENTS (toggle_entries), comp_editor); - gtk_ui_manager_insert_action_group ( - comp_editor->priv->ui_manager, action_group, 0); - g_object_unref (action_group); - - action = gtk_action_group_get_action (action_group, "show-toolbar"); + action = e_comp_editor_get_action (comp_editor, "show-toolbar"); if (action) { g_settings_bind ( - comp_editor->priv->calendar_settings, "editor-show-toolbar", - action, "active", - G_SETTINGS_BIND_DEFAULT); + comp_editor->priv->calendar_settings, "editor-show-toolbar", + action, "active", + G_SETTINGS_BIND_DEFAULT); } - gtk_ui_manager_add_ui_from_string (comp_editor->priv->ui_manager, ui, -1, &error); - if (error != NULL) { - g_warning ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } + if (!e_ui_parser_merge_file (e_ui_manager_get_parser (comp_editor->priv->ui_manager), "e-comp-editor.eui", &local_error)) + g_warning ("%s: Failed to read e-comp-editor.eui file: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error"); + + g_clear_error (&local_error); widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); g_object_set (G_OBJECT (widget), @@ -2462,34 +2431,25 @@ e_comp_editor_constructed (GObject *object) gtk_container_add (GTK_CONTAINER (comp_editor), widget); /* Construct the main menu and headerbar. */ - widget = e_comp_editor_get_managed_widget (comp_editor, "/main-menu"); - comp_editor->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (comp_editor), &menu_button); + ui_item = e_ui_manager_create_item (comp_editor->priv->ui_manager, "main-menu"); + widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (ui_item)); + g_clear_object (&ui_item); + + comp_editor->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (comp_editor), &comp_editor->priv->menu_button); gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); if (e_util_get_use_header_bar ()) { - widget = comp_editor_construct_header_bar (comp_editor, menu_button); + ui_item = e_ui_manager_create_item (comp_editor->priv->ui_manager, "main-headerbar"); + widget = GTK_WIDGET (ui_item); gtk_window_set_titlebar (GTK_WINDOW (comp_editor), widget); - /* Destroy items from the toolbar, which are in the header bar */ - widget = e_comp_editor_get_managed_widget (comp_editor, "/main-toolbar/save-and-close"); - gtk_widget_destroy (widget); - - widget = e_comp_editor_get_managed_widget (comp_editor, "/main-toolbar/save"); - gtk_widget_destroy (widget); - } else if (menu_button) { - g_object_ref_sink (menu_button); - gtk_widget_destroy (menu_button); + ui_item = e_ui_manager_create_item (comp_editor->priv->ui_manager, "toolbar-with-headerbar"); + } else { + ui_item = e_ui_manager_create_item (comp_editor->priv->ui_manager, "toolbar-without-headerbar"); } - widget = e_comp_editor_get_managed_widget (comp_editor, "/main-toolbar"); + widget = GTK_WIDGET (ui_item); gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - e_util_setup_toolbar_icon_size (GTK_TOOLBAR (widget), GTK_ICON_SIZE_BUTTON); - - gtk_style_context_add_class ( - gtk_widget_get_style_context (widget), - GTK_STYLE_CLASS_PRIMARY_TOOLBAR); g_settings_bind ( comp_editor->priv->calendar_settings, "editor-show-toolbar", @@ -2564,7 +2524,7 @@ e_comp_editor_constructed (GObject *object) /* Desensitize the "save" action. */ action = e_comp_editor_get_action (comp_editor, "save"); - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); e_binding_bind_property (comp_editor, "changed", action, "sensitive", 0); @@ -2619,6 +2579,7 @@ e_comp_editor_dispose (GObject *object) g_clear_object (&comp_editor->priv->validation_alert); g_clear_object (&comp_editor->priv->menu_bar); + comp_editor->priv->menu_button = NULL; comp_editor->priv->activity_bar = NULL; opened_editors = g_slist_remove (opened_editors, comp_editor); @@ -3075,7 +3036,7 @@ e_comp_editor_get_focus_tracker (ECompEditor *comp_editor) return comp_editor->priv->focus_tracker; } -GtkUIManager * +EUIManager * e_comp_editor_get_ui_manager (ECompEditor *comp_editor) { g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); @@ -3083,49 +3044,18 @@ e_comp_editor_get_ui_manager (ECompEditor *comp_editor) return comp_editor->priv->ui_manager; } -GtkAction * +EUIAction * e_comp_editor_get_action (ECompEditor *comp_editor, const gchar *action_name) { - GtkUIManager *ui_manager; + EUIManager *ui_manager; g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); g_return_val_if_fail (action_name != NULL, NULL); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - return e_lookup_action (ui_manager, action_name); -} - -GtkActionGroup * -e_comp_editor_get_action_group (ECompEditor *comp_editor, - const gchar *group_name) -{ - GtkUIManager *ui_manager; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - g_return_val_if_fail (group_name != NULL, NULL); - - ui_manager = e_comp_editor_get_ui_manager (comp_editor); - - return e_lookup_action_group (ui_manager, group_name); -} - -GtkWidget * -e_comp_editor_get_managed_widget (ECompEditor *comp_editor, - const gchar *widget_path) -{ - GtkUIManager *ui_manager; - GtkWidget *widget; - - g_return_val_if_fail (E_IS_COMP_EDITOR (comp_editor), NULL); - g_return_val_if_fail (widget_path != NULL, NULL); - - ui_manager = e_comp_editor_get_ui_manager (comp_editor); - widget = gtk_ui_manager_get_widget (ui_manager, widget_path); - g_return_val_if_fail (widget != NULL, NULL); - - return widget; + return e_ui_manager_get_action (ui_manager, action_name); } static gchar * diff --git a/src/calendar/gui/e-comp-editor.h b/src/calendar/gui/e-comp-editor.h index e8b43c965d..f9f86c223c 100644 --- a/src/calendar/gui/e-comp-editor.h +++ b/src/calendar/gui/e-comp-editor.h @@ -109,14 +109,9 @@ guint32 e_comp_editor_get_flags (ECompEditor *comp_editor); void e_comp_editor_set_flags (ECompEditor *comp_editor, guint32 flags); EFocusTracker * e_comp_editor_get_focus_tracker (ECompEditor *comp_editor); -GtkUIManager * e_comp_editor_get_ui_manager (ECompEditor *comp_editor); -GtkAction * e_comp_editor_get_action (ECompEditor *comp_editor, +EUIManager * e_comp_editor_get_ui_manager (ECompEditor *comp_editor); +EUIAction * e_comp_editor_get_action (ECompEditor *comp_editor, const gchar *action_name); -GtkActionGroup *e_comp_editor_get_action_group (ECompEditor *comp_editor, - const gchar *group_name); -GtkWidget * e_comp_editor_get_managed_widget - (ECompEditor *comp_editor, - const gchar *widget_path); const gchar * e_comp_editor_get_alarm_email_address (ECompEditor *comp_editor); void e_comp_editor_set_alarm_email_address diff --git a/src/calendar/gui/e-memo-table.c b/src/calendar/gui/e-memo-table.c index 829f5bf379..ac482553bd 100644 --- a/src/calendar/gui/e-memo-table.c +++ b/src/calendar/gui/e-memo-table.c @@ -628,7 +628,7 @@ memo_table_update_actions (ESelectable *selectable, gint n_clipboard_targets) { EMemoTable *memo_table; - GtkAction *action; + EUIAction *action; GtkTargetList *target_list; GSList *list, *iter; gboolean can_paste = FALSE; @@ -660,32 +660,32 @@ memo_table_update_actions (ESelectable *selectable, action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable && !is_editing; tooltip = _("Cut selected memos to the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && !is_editing; tooltip = _("Copy selected memos to the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); sensitive = sources_are_editable && can_paste && !is_editing; tooltip = _("Paste memos from the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_delete_selection_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable && !is_editing; tooltip = _("Delete selected memos"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_select_all_action (focus_tracker); sensitive = TRUE; tooltip = _("Select all visible memos"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); } static void diff --git a/src/calendar/gui/e-task-table.c b/src/calendar/gui/e-task-table.c index 52c52e97f5..64eabe3fd4 100644 --- a/src/calendar/gui/e-task-table.c +++ b/src/calendar/gui/e-task-table.c @@ -808,7 +808,7 @@ task_table_update_actions (ESelectable *selectable, gint n_clipboard_targets) { ETaskTable *task_table; - GtkAction *action; + EUIAction *action; GtkTargetList *target_list; GSList *list, *iter; gboolean can_paste = FALSE; @@ -843,32 +843,32 @@ task_table_update_actions (ESelectable *selectable, action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable && !is_editing; tooltip = _("Cut selected tasks to the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); sensitive = (n_selected > 0) && !is_editing; tooltip = _("Copy selected tasks to the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); sensitive = sources_are_editable && can_paste && !is_editing; tooltip = _("Paste tasks from the clipboard"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_delete_selection_action (focus_tracker); sensitive = (n_selected > 0) && sources_are_editable && !is_editing; tooltip = _("Delete selected tasks"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); action = e_focus_tracker_get_select_all_action (focus_tracker); sensitive = TRUE; tooltip = _("Select all visible tasks"); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, tooltip); } static void diff --git a/src/composer/CMakeLists.txt b/src/composer/CMakeLists.txt index b609d8dbe5..eae1e94fdd 100644 --- a/src/composer/CMakeLists.txt +++ b/src/composer/CMakeLists.txt @@ -1,9 +1,5 @@ add_error_files(composer mail-composer.error) -install(FILES evolution-composer.ui - DESTINATION ${uidir} -) - set(DEPENDENCIES econtacteditor econtactlisteditor diff --git a/src/composer/e-composer-actions.c b/src/composer/e-composer-actions.c index 8d026c8546..3fae83eae4 100644 --- a/src/composer/e-composer-actions.c +++ b/src/composer/e-composer-actions.c @@ -26,12 +26,16 @@ #include static void -action_attach_cb (GtkAction *action, - EMsgComposer *composer) +action_attach_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; EAttachmentView *view; EAttachmentStore *store; + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + view = e_msg_composer_get_attachment_view (composer); store = e_attachment_view_get_store (view); @@ -39,25 +43,29 @@ action_attach_cb (GtkAction *action, } static void -action_charset_cb (GtkRadioAction *action, - GtkRadioAction *current, - EMsgComposer *composer) +action_charset_change_set_state_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - const gchar *charset; + EMsgComposer *composer = user_data; - if (action != current) - return; + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); - charset = g_object_get_data (G_OBJECT (action), "charset"); + e_ui_action_set_state (action, parameter); g_free (composer->priv->charset); - composer->priv->charset = g_strdup (charset); + composer->priv->charset = g_strdup (g_variant_get_string (parameter, NULL)); } static void -action_close_cb (GtkAction *action, - EMsgComposer *composer) +action_close_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; + + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + if (e_msg_composer_can_close (composer, TRUE)) { e_composer_emit_before_destroy (composer); gtk_widget_destroy (GTK_WIDGET (composer)); @@ -82,11 +90,15 @@ action_new_message_composer_created_cb (GObject *source_object, } static void -action_new_message_cb (GtkAction *action, - EMsgComposer *composer) +action_new_message_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; EShell *shell; + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + shell = e_msg_composer_get_shell (composer); e_msg_composer_new (shell, action_new_message_composer_created_cb, NULL); @@ -105,27 +117,17 @@ composer_set_content_editor_changed (EMsgComposer *composer) } static void -action_pgp_encrypt_cb (GtkToggleAction *action, - EMsgComposer *composer) -{ - composer_set_content_editor_changed (composer); -} - -static void -action_pgp_sign_cb (GtkToggleAction *action, - EMsgComposer *composer) -{ - composer_set_content_editor_changed (composer); -} - -static void -action_preferences_cb (GtkAction *action, - EMsgComposer *composer) +action_preferences_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; EShell *shell; GtkWidget *preferences_window; const gchar *page_name = "composer"; + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + shell = e_msg_composer_get_shell (composer); preferences_window = e_shell_get_preferences_window (shell); e_preferences_window_setup (E_PREFERENCES_WINDOW (preferences_window)); @@ -143,21 +145,29 @@ action_preferences_cb (GtkAction *action, } static void -action_print_cb (GtkAction *action, - EMsgComposer *composer) +action_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; GtkPrintOperationAction print_action; + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG; e_msg_composer_print (composer, print_action); } static void -action_print_preview_cb (GtkAction *action, - EMsgComposer *composer) +action_print_preview_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; GtkPrintOperationAction print_action; + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW; e_msg_composer_print (composer, print_action); } @@ -187,17 +197,21 @@ action_save_ready_cb (GObject *source_object, } static void -action_save_cb (GtkAction *action, - EMsgComposer *composer) +action_save_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; EHTMLEditor *editor; const gchar *filename; gint fd; + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + editor = e_msg_composer_get_editor (composer); filename = e_html_editor_get_filename (editor); if (filename == NULL) { - gtk_action_activate (ACTION (SAVE_AS)); + g_action_activate (G_ACTION (ACTION (SAVE_AS)), NULL); return; } @@ -229,13 +243,17 @@ action_save_cb (GtkAction *action, } static void -action_save_as_cb (GtkAction *action, - EMsgComposer *composer) +action_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; EHTMLEditor *editor; GtkFileChooserNative *native; gchar *filename; + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + native = gtk_file_chooser_native_new ( _("Save as…"), GTK_WINDOW (composer), GTK_FILE_CHOOSER_ACTION_SAVE, @@ -254,52 +272,58 @@ action_save_as_cb (GtkAction *action, e_html_editor_set_filename (editor, filename); g_free (filename); - gtk_action_activate (ACTION (SAVE)); + g_action_activate (G_ACTION (ACTION (SAVE)), NULL); } g_object_unref (native); } static void -action_save_draft_cb (GtkAction *action, - EMsgComposer *composer) +action_save_draft_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; + + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + e_msg_composer_save_to_drafts (composer); } static void -action_send_cb (GtkAction *action, - EMsgComposer *composer) +action_send_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; + + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + e_msg_composer_send (composer); } static void -action_smime_encrypt_cb (GtkToggleAction *action, - EMsgComposer *composer) +e_composer_set_action_state_with_changed_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; + + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + + e_ui_action_set_state (action, parameter); composer_set_content_editor_changed (composer); } static void -action_smime_sign_cb (GtkToggleAction *action, - EMsgComposer *composer) +composer_actions_toolbar_option_notify_active_cb (EUIAction *action, + GParamSpec *param, + gpointer user_data) { - composer_set_content_editor_changed (composer); -} - -static void -composer_actions_toolbar_option_toggled_cb (GtkToggleAction *toggle_action, - EMsgComposer *composer) -{ - GtkAction *action; - - action = GTK_ACTION (toggle_action); - /* Show the action only after the first time the option is used */ - if (!gtk_action_get_visible (action) && - gtk_toggle_action_get_active (toggle_action)) - gtk_action_set_visible (action, TRUE); + if (!e_ui_action_get_visible (action) && + e_ui_action_get_active (action)) + e_ui_action_set_visible (action, TRUE); } static gboolean @@ -319,285 +343,6 @@ composer_actions_accel_activate_cb (GtkAccelGroup *accel_group, return FALSE; } -static GtkActionEntry entries[] = { - - { "attach", - "mail-attachment", - N_("_Attachment…"), - "m", - N_("Attach a file"), - G_CALLBACK (action_attach_cb) }, - - { "close", - "window-close", - N_("_Close"), - "w", - N_("Close the current file"), - G_CALLBACK (action_close_cb) }, - - { "new-message", - "mail-message-new", - N_("New _Message"), - "n", - N_("Open New Message window"), - G_CALLBACK (action_new_message_cb) }, - - { "preferences", - "preferences-system", - N_("_Preferences"), - NULL, - N_("Configure Evolution"), - G_CALLBACK (action_preferences_cb) }, - - { "save", - "document-save", - N_("_Save"), - "s", - N_("Save the current file"), - G_CALLBACK (action_save_cb) }, - - { "save-as", - "document-save-as", - N_("Save _As…"), - NULL, - N_("Save the current file with a different name"), - G_CALLBACK (action_save_as_cb) }, - - /* Menus */ - - { "charset-menu", - NULL, - N_("Character _Encoding"), - NULL, - NULL, - NULL }, - - { "options-menu", - NULL, - N_("Option_s"), - NULL, - NULL, - NULL } -}; - -static GtkActionEntry async_entries[] = { - - { "print", - "document-print", - N_("_Print…"), - "p", - NULL, - G_CALLBACK (action_print_cb) }, - - { "print-preview", - "document-print-preview", - N_("Print Pre_view"), - "p", - NULL, - G_CALLBACK (action_print_preview_cb) }, - - { "save-draft", - "document-save", - N_("Save as _Draft"), - "s", - N_("Save as draft"), - G_CALLBACK (action_save_draft_cb) }, - - { "send", - "mail-send", - N_("S_end"), - "Return", - N_("Send this message"), - G_CALLBACK (action_send_cb) }, -}; - -static GtkToggleActionEntry toggle_entries[] = { - - { "toolbar-show-main", - NULL, - N_("_Main toolbar"), - NULL, - N_("Main toolbar"), - NULL, - FALSE }, - - { "toolbar-show-edit", - NULL, - N_("Edit _toolbar"), - NULL, - N_("Edit toolbar"), - NULL, - FALSE }, - - { "pgp-encrypt", - NULL, - N_("PGP _Encrypt"), - NULL, - N_("Encrypt this message with PGP"), - G_CALLBACK (action_pgp_encrypt_cb), - FALSE }, - - { "pgp-sign", - NULL, - N_("PGP _Sign"), - NULL, - N_("Sign this message with your PGP key"), - G_CALLBACK (action_pgp_sign_cb), - FALSE }, - - { "picture-gallery", - "emblem-photos", - N_("_Picture Gallery"), - NULL, - N_("Show a collection of pictures that you can drag to your message"), - NULL, /* no callback */ - FALSE }, - - { "prioritize-message", - "mail-mark-important", - N_("_Prioritize Message"), - NULL, - N_("Set the message priority to high"), - NULL, /* no callback */ - FALSE }, - - { "request-read-receipt", - "preferences-system-notifications", - N_("Re_quest Read Receipt"), - NULL, - N_("Get delivery notification when your message is read"), - NULL, /* no callback */ - FALSE }, - - { "delivery-status-notification", - NULL, - N_("Request _Delivery Status Notification"), - NULL, - N_("Get delivery status notification for the message"), - NULL, /* no callback */ - FALSE }, - - { "smime-encrypt", - NULL, - N_("S/MIME En_crypt"), - NULL, - N_("Encrypt this message with S/MIME"), - G_CALLBACK (action_smime_encrypt_cb), - FALSE }, - - { "smime-sign", - NULL, - N_("S/MIME Sig_n"), - NULL, - N_("Sign this message with your S/MIME Signature Certificate"), - G_CALLBACK (action_smime_sign_cb), - FALSE }, - - { "toolbar-pgp-encrypt", - "security-high", - NULL, - NULL, - NULL, - NULL, - FALSE }, - - { "toolbar-pgp-sign", - "stock_signature", - NULL, - NULL, - NULL, - NULL, - FALSE }, - - { "toolbar-prioritize-message", - "emblem-important", - NULL, - NULL, - NULL, - NULL, - FALSE }, - - { "toolbar-request-read-receipt", - "mail-forward", - NULL, - NULL, - NULL, - NULL, - FALSE }, - - { "toolbar-smime-encrypt", - "security-high", - NULL, - NULL, - NULL, - NULL, - FALSE }, - - { "toolbar-smime-sign", - "stock_signature", - NULL, - NULL, - NULL, - NULL, - FALSE }, - - { "view-bcc", - NULL, - N_("_Bcc Field"), - NULL, - N_("Toggles whether the BCC field is displayed"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "view-cc", - NULL, - N_("_Cc Field"), - NULL, - N_("Toggles whether the CC field is displayed"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "view-from-override", - NULL, - N_("_From Override Field"), - NULL, - N_("Toggles whether the From override field to change name or email address is displayed"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "view-mail-followup-to", - NULL, - N_("Mail-Follow_up-To Field"), - NULL, - N_("Toggles whether the Mail-Followup-To field is displayed"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "view-mail-reply-to", - NULL, - N_("Mail-R_eply-To Field"), - NULL, - N_("Toggles whether the Mail-Reply-To field is displayed"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "view-reply-to", - NULL, - N_("_Reply-To Field"), - NULL, - N_("Toggles whether the Reply-To field is displayed"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "visually-wrap-long-lines", - NULL, - N_("Visually _Wrap Long Lines"), - NULL, - N_("Whether to visually wrap long lines of text to avoid horizontal scrolling"), - NULL, - FALSE } -}; - static gboolean eca_transform_mode_html_to_boolean_cb (GBinding *binding, const GValue *source_value, @@ -630,15 +375,276 @@ eca_mode_to_bool_hide_in_markdown_cb (GBinding *binding, void e_composer_actions_init (EMsgComposer *composer) { - GtkActionGroup *action_group; + static const EUIActionEntry entries[] = { + + { "attach", + "mail-attachment", + N_("_Attachment…"), + "m", + N_("Attach a file"), + action_attach_cb, NULL, NULL, NULL }, + + { "close", + "window-close", + N_("_Close"), + "w", + N_("Close the current file"), + action_close_cb, NULL, NULL, NULL }, + + { "new-message", + "mail-message-new", + N_("New _Message"), + "n", + N_("Open New Message window"), + action_new_message_cb, NULL, NULL, NULL }, + + { "preferences", + "preferences-system", + N_("_Preferences"), + NULL, + N_("Configure Evolution"), + action_preferences_cb, NULL, NULL, NULL }, + + { "save", + "document-save", + N_("_Save"), + "s", + N_("Save the current file"), + action_save_cb, NULL, NULL, NULL }, + + { "save-as", + "document-save-as", + N_("Save _As…"), + NULL, + N_("Save the current file with a different name"), + action_save_as_cb, NULL, NULL, NULL }, + + /* Menus */ + + { "EMsgComposer::charset-menu", + NULL, + N_("Character _Encoding"), + NULL, + NULL, + NULL, "s", "''", action_charset_change_set_state_cb }, + + { "EMsgComposer::menu-button", + NULL, + N_("Menu"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, + + { "options-menu", + NULL, + N_("Option_s"), + NULL, + NULL, + NULL, NULL, NULL, NULL } + }; + + static const EUIActionEntry async_entries[] = { + + { "print", + "document-print", + N_("_Print…"), + "p", + NULL, + action_print_cb, NULL, NULL, NULL }, + + { "print-preview", + "document-print-preview", + N_("Print Pre_view"), + "p", + NULL, + action_print_preview_cb, NULL, NULL, NULL }, + + { "save-draft", + "document-save", + N_("Save as _Draft"), + "s", + N_("Save as draft"), + action_save_draft_cb, NULL, NULL, NULL }, + + { "send", + "mail-send", + N_("S_end"), + "Return", + N_("Send this message"), + action_send_cb, NULL, NULL, NULL }, + }; + + static const EUIActionEntry toggle_entries[] = { + + { "toolbar-show-main", + NULL, + N_("_Main toolbar"), + NULL, + N_("Main toolbar"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "toolbar-show-edit", + NULL, + N_("Edit _toolbar"), + NULL, + N_("Edit toolbar"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "pgp-encrypt", + NULL, + N_("PGP _Encrypt"), + NULL, + N_("Encrypt this message with PGP"), + NULL, NULL, "false", e_composer_set_action_state_with_changed_cb }, + + { "pgp-sign", + NULL, + N_("PGP _Sign"), + NULL, + N_("Sign this message with your PGP key"), + NULL, NULL, "false", e_composer_set_action_state_with_changed_cb }, + + { "picture-gallery", + "emblem-photos", + N_("_Picture Gallery"), + NULL, + N_("Show a collection of pictures that you can drag to your message"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "prioritize-message", + "mail-mark-important", + N_("_Prioritize Message"), + NULL, + N_("Set the message priority to high"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "request-read-receipt", + "preferences-system-notifications", + N_("Re_quest Read Receipt"), + NULL, + N_("Get delivery notification when your message is read"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "delivery-status-notification", + NULL, + N_("Request _Delivery Status Notification"), + NULL, + N_("Get delivery status notification for the message"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "smime-encrypt", + NULL, + N_("S/MIME En_crypt"), + NULL, + N_("Encrypt this message with S/MIME"), + NULL, NULL, "false", e_composer_set_action_state_with_changed_cb }, + + { "smime-sign", + NULL, + N_("S/MIME Sig_n"), + NULL, + N_("Sign this message with your S/MIME Signature Certificate"), + NULL, NULL, "false", e_composer_set_action_state_with_changed_cb }, + + { "toolbar-pgp-encrypt", + "gicon::EMsgComposer::pgp-encrypt", + N_("PGP _Encrypt"), + NULL, + N_("Encrypt this message with PGP"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "toolbar-pgp-sign", + "gicon::EMsgComposer::pgp-sign", + N_("PGP _Sign"), + NULL, + N_("Sign this message with your PGP key"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "toolbar-prioritize-message", + "emblem-important", + N_("_Prioritize Message"), + NULL, + N_("Set the message priority to high"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "toolbar-request-read-receipt", + "mail-forward", + N_("Re_quest Read Receipt"), + NULL, + N_("Get delivery notification when your message is read"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "toolbar-smime-encrypt", + "security-high", + N_("S/MIME En_crypt"), + NULL, + N_("Encrypt this message with S/MIME"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "toolbar-smime-sign", + "stock_signature", + N_("S/MIME Sig_n"), + NULL, + N_("Sign this message with your S/MIME Signature Certificate"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "view-bcc", + NULL, + N_("_Bcc Field"), + NULL, + N_("Toggles whether the BCC field is displayed"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "view-cc", + NULL, + N_("_Cc Field"), + NULL, + N_("Toggles whether the CC field is displayed"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "view-from-override", + NULL, + N_("_From Override Field"), + NULL, + N_("Toggles whether the From override field to change name or email address is displayed"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "view-mail-followup-to", + NULL, + N_("Mail-Follow_up-To Field"), + NULL, + N_("Toggles whether the Mail-Followup-To field is displayed"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "view-mail-reply-to", + NULL, + N_("Mail-R_eply-To Field"), + NULL, + N_("Toggles whether the Mail-Reply-To field is displayed"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "view-reply-to", + NULL, + N_("_Reply-To Field"), + NULL, + N_("Toggles whether the Reply-To field is displayed"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, + + { "visually-wrap-long-lines", + NULL, + N_("Visually _Wrap Long Lines"), + NULL, + N_("Whether to visually wrap long lines of text to avoid horizontal scrolling"), + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state } + }; + GtkAccelGroup *accel_group; - GtkUIManager *ui_manager; + EUIManager *ui_manager; EHTMLEditor *editor; EContentEditor *cnt_editor; gboolean visible; GSettings *settings; - GtkAction *action; - GIcon *gcr_gnupg_icon; + EUIAction *action; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); @@ -647,56 +653,27 @@ e_composer_actions_init (EMsgComposer *composer) ui_manager = e_html_editor_get_ui_manager (editor); /* Composer Actions */ - action_group = composer->priv->composer_actions; - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, entries, - G_N_ELEMENTS (entries), composer); - gtk_action_group_add_toggle_actions ( - action_group, toggle_entries, - G_N_ELEMENTS (toggle_entries), composer); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + e_ui_manager_add_actions (ui_manager, "composer", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), composer); + e_ui_manager_add_actions (ui_manager, "composer", GETTEXT_PACKAGE, + toggle_entries, G_N_ELEMENTS (toggle_entries), composer); /* Asynchronous Actions */ - action_group = composer->priv->async_actions; - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, async_entries, - G_N_ELEMENTS (async_entries), composer); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + e_ui_manager_add_actions (ui_manager, "async", GETTEXT_PACKAGE, + async_entries, G_N_ELEMENTS (async_entries), composer); - /* Character Set Actions */ - action_group = composer->priv->charset_actions; - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - e_charset_add_radio_actions ( - action_group, "charset-", composer->priv->charset, - G_CALLBACK (action_charset_cb), composer); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + action = e_ui_manager_get_action (ui_manager, "close"); + e_ui_action_add_secondary_accel (action, "Escape"); - /* Fine Tuning */ - - g_object_set ( - ACTION (ATTACH), "short-label", _("Attach"), NULL); - - g_object_set ( - ACTION (PICTURE_GALLERY), "is-important", TRUE, NULL); - - g_object_set ( - ACTION (SAVE_DRAFT), "short-label", _("Save Draft"), NULL); + action = e_ui_manager_get_action (ui_manager, "send"); + e_ui_action_add_secondary_accel (action, "Send"); #define init_toolbar_option(x, always_visible) \ - gtk_action_set_visible (ACTION (TOOLBAR_ ## x), always_visible); \ + e_ui_action_set_visible (ACTION (TOOLBAR_ ## x), always_visible); \ e_binding_bind_property ( \ ACTION (x), "active", \ ACTION (TOOLBAR_ ## x), "active", \ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); \ - e_binding_bind_property ( \ - ACTION (x), "label", \ - ACTION (TOOLBAR_ ## x), "label", \ - G_BINDING_SYNC_CREATE); \ e_binding_bind_property ( \ ACTION (x), "tooltip", \ ACTION (TOOLBAR_ ## x), "tooltip", \ @@ -705,8 +682,8 @@ e_composer_actions_init (EMsgComposer *composer) ACTION (x), "sensitive", \ ACTION (TOOLBAR_ ## x), "sensitive", \ G_BINDING_SYNC_CREATE); \ - g_signal_connect (ACTION (TOOLBAR_ ## x), "toggled", \ - G_CALLBACK (composer_actions_toolbar_option_toggled_cb), composer); + g_signal_connect (ACTION (TOOLBAR_ ## x), "notify::active", \ + G_CALLBACK (composer_actions_toolbar_option_notify_active_cb), composer); init_toolbar_option (PGP_SIGN, FALSE); init_toolbar_option (PGP_ENCRYPT, FALSE); @@ -733,35 +710,6 @@ e_composer_actions_init (EMsgComposer *composer) g_object_unref (settings); - /* Borrow a GnuPG icon from gcr to distinguish between GPG and S/MIME Sign/Encrypt actions */ - gcr_gnupg_icon = g_themed_icon_new ("gcr-gnupg"); - if (gcr_gnupg_icon) { - GIcon *temp_icon; - GIcon *action_icon; - GEmblem *emblem; - - emblem = g_emblem_new (gcr_gnupg_icon); - - action = ACTION (TOOLBAR_PGP_SIGN); - action_icon = g_themed_icon_new (gtk_action_get_icon_name (action)); - temp_icon = g_emblemed_icon_new (action_icon, emblem); - g_object_unref (action_icon); - - gtk_action_set_gicon (action, temp_icon); - g_object_unref (temp_icon); - - action = ACTION (TOOLBAR_PGP_ENCRYPT); - action_icon = g_themed_icon_new (gtk_action_get_icon_name (action)); - temp_icon = g_emblemed_icon_new (action_icon, emblem); - g_object_unref (action_icon); - - gtk_action_set_gicon (action, temp_icon); - g_object_unref (temp_icon); - - g_object_unref (emblem); - g_object_unref (gcr_gnupg_icon); - } - e_binding_bind_property_full ( editor, "mode", ACTION (PICTURE_GALLERY), "sensitive", @@ -812,10 +760,10 @@ e_composer_actions_init (EMsgComposer *composer) visible = FALSE; #endif - gtk_action_set_visible (ACTION (SMIME_ENCRYPT), visible); - gtk_action_set_visible (ACTION (SMIME_SIGN), visible); + e_ui_action_set_visible (ACTION (SMIME_ENCRYPT), visible); + e_ui_action_set_visible (ACTION (SMIME_SIGN), visible); - accel_group = gtk_ui_manager_get_accel_group (ui_manager); + accel_group = e_ui_manager_get_accel_group (ui_manager); g_signal_connect (accel_group, "accel-activate", G_CALLBACK (composer_actions_accel_activate_cb), composer); } diff --git a/src/composer/e-composer-private.c b/src/composer/e-composer-private.c index 604345694a..37a637e38a 100644 --- a/src/composer/e-composer-private.c +++ b/src/composer/e-composer-private.c @@ -26,99 +26,19 @@ /* Initial height of the picture gallery. */ #define GALLERY_INITIAL_HEIGHT 150 -static void -composer_setup_charset_menu (EMsgComposer *composer) -{ - EHTMLEditor *editor; - GtkUIManager *ui_manager; - const gchar *path; - GList *list; - guint merge_id; - - editor = e_msg_composer_get_editor (composer); - ui_manager = e_html_editor_get_ui_manager (editor); - path = "/main-menu/options-menu/charset-menu"; - merge_id = gtk_ui_manager_new_merge_id (ui_manager); - - list = gtk_action_group_list_actions (composer->priv->charset_actions); - list = g_list_sort (list, (GCompareFunc) e_action_compare_by_label); - - while (list != NULL) { - GtkAction *action = list->data; - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, path, - gtk_action_get_name (action), - gtk_action_get_name (action), - GTK_UI_MANAGER_AUTO, FALSE); - - list = g_list_delete_link (list, list); - } - - gtk_ui_manager_ensure_update (ui_manager); -} - static void composer_update_gallery_visibility (EMsgComposer *composer) { EHTMLEditor *editor; - GtkToggleAction *toggle_action; gboolean gallery_active; gboolean is_html; editor = e_msg_composer_get_editor (composer); is_html = e_html_editor_get_mode (editor) == E_CONTENT_EDITOR_MODE_HTML; + gallery_active = e_ui_action_get_active (ACTION (PICTURE_GALLERY)); - toggle_action = GTK_TOGGLE_ACTION (ACTION (PICTURE_GALLERY)); - gallery_active = gtk_toggle_action_get_active (toggle_action); - - if (is_html && gallery_active) { - gtk_widget_show (composer->priv->gallery_scrolled_window); - gtk_widget_show (composer->priv->gallery_icon_view); - } else { - gtk_widget_hide (composer->priv->gallery_scrolled_window); - gtk_widget_hide (composer->priv->gallery_icon_view); - } -} - -static GtkWidget * -composer_construct_header_bar (EMsgComposer *composer, - GtkWidget *menu_button) -{ - GtkWidget *widget; - GtkWidget *button; - GtkHeaderBar *header_bar; - - widget = gtk_header_bar_new (); - gtk_widget_show (widget); - header_bar = GTK_HEADER_BAR (widget); - gtk_header_bar_set_show_close_button (header_bar, TRUE); - - if (menu_button) - gtk_header_bar_pack_end (header_bar, menu_button); - - button = e_header_bar_button_new (_("Send"), ACTION (SEND)); - e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "suggested-action"); - e_header_bar_button_set_show_icon_only (E_HEADER_BAR_BUTTON (button), FALSE); - gtk_widget_show (button); - gtk_header_bar_pack_start (header_bar, button); - - button = e_header_bar_button_new (NULL, ACTION (SAVE_DRAFT)); - e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "flat"); - gtk_widget_show (button); - gtk_header_bar_pack_start (header_bar, button); - - button = e_header_bar_button_new (NULL, ACTION (PRIORITIZE_MESSAGE)); - e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "flat"); - gtk_widget_show (button); - gtk_header_bar_pack_end (header_bar, button); - - button = e_header_bar_button_new (NULL, ACTION (REQUEST_READ_RECEIPT)); - e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "flat"); - gtk_widget_show (button); - gtk_header_bar_pack_end (header_bar, button); - - return widget; + gtk_widget_set_visible (composer->priv->gallery_scrolled_window, is_html && gallery_active); + gtk_widget_set_visible (composer->priv->gallery_icon_view, is_html && gallery_active); } static gchar * @@ -220,6 +140,124 @@ e_composer_from_changed_cb (EComposerFromHeader *header, } } +static gchar * +e_composer_find_data_file (const gchar *basename) +{ + gchar *filename; + + g_return_val_if_fail (basename != NULL, NULL); + + /* Support running directly from the source tree. */ + filename = g_build_filename (".", basename, NULL); + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + return filename; + g_free (filename); + + filename = g_build_filename (".", "data", "ui", basename, NULL); + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + return filename; + g_free (filename); + + filename = g_build_filename ("..", "..", "..", "data", "ui", basename, NULL); + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + return filename; + g_free (filename); + + filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + return filename; + g_free (filename); + + g_critical ("Could not locate '%s'", basename); + + return NULL; +} + +static gboolean +e_composer_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EMsgComposer *self = user_data; + const gchar *name; + + g_return_val_if_fail (E_IS_MSG_COMPOSER (self), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "EMsgComposer::")) + return FALSE; + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (for_kind == E_UI_ELEMENT_KIND_MENU) { + if (is_action ("EMsgComposer::charset-menu")) + *out_item = G_OBJECT (g_menu_item_new_submenu (e_ui_action_get_label (action), G_MENU_MODEL (self->priv->charset_menu))); + else + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + if (is_action ("EMsgComposer::menu-button")) + *out_item = G_OBJECT (g_object_ref (self->priv->menu_button)); + else + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + #undef is_action + + return TRUE; +} + +static GIcon * /* (transfer full) */ +e_composer_mix_icons (const gchar *action_icon_name, + const gchar *emblem_icon_name) +{ + GIcon *action_icon; + GIcon *temp_icon; + GEmblem *emblem; + + temp_icon = g_themed_icon_new (emblem_icon_name); + emblem = g_emblem_new (temp_icon); + g_object_unref (temp_icon); + + action_icon = g_themed_icon_new (action_icon_name); + temp_icon = g_emblemed_icon_new (action_icon, emblem); + g_object_unref (action_icon); + + g_object_unref (emblem); + + return temp_icon; +} + +static gboolean +e_composer_ui_manager_create_gicon_cb (EUIManager *manager, + const gchar *name, + GIcon **out_gicon, + gpointer user_data) +{ + EMsgComposer *self = user_data; + + g_return_val_if_fail (E_IS_MSG_COMPOSER (self), FALSE); + + if (g_strcmp0 (name, "EMsgComposer::pgp-sign") == 0) { + /* Borrow a GnuPG icon from gcr to distinguish between GPG and S/MIME Sign/Encrypt actions */ + *out_gicon = e_composer_mix_icons ("stock_signature", "gcr-gnupg"); + return TRUE; + } else if (g_strcmp0 (name, "EMsgComposer::pgp-encrypt") == 0) { + /* Borrow a GnuPG icon from gcr to distinguish between GPG and S/MIME Sign/Encrypt actions */ + *out_gicon = e_composer_mix_icons ("security-high", "gcr-gnupg"); + return TRUE; + } + + return FALSE; +} + void e_composer_private_constructed (EMsgComposer *composer) { @@ -230,21 +268,26 @@ e_composer_private_constructed (EMsgComposer *composer) EClientCache *client_cache; EHTMLEditor *editor; EContentEditor *cnt_editor; - GtkUIManager *ui_manager; - GtkAction *action; + EUIManager *ui_manager; + EUIAction *action; GtkWidget *container; GtkWidget *widget; - GtkWidget *menu_button = NULL; GtkWindow *window; GSettings *settings; + GObject *ui_item; gchar *filename, *gallery_path; guint ii; - GError *error = NULL; + GError *local_error = NULL; editor = e_msg_composer_get_editor (composer); ui_manager = e_html_editor_get_ui_manager (editor); cnt_editor = e_html_editor_get_content_editor (editor); + g_signal_connect_object (ui_manager, "create-item", + G_CALLBACK (e_composer_ui_manager_create_item_cb), composer, 0); + g_signal_connect_object (ui_manager, "create-gicon", + G_CALLBACK (e_composer_ui_manager_create_gicon_cb), composer, 0); + settings = e_util_ref_settings ("org.gnome.evolution.mail"); shell = e_msg_composer_get_shell (composer); @@ -255,9 +298,11 @@ e_composer_private_constructed (EMsgComposer *composer) priv->window_group = gtk_window_group_new (); gtk_window_group_add_window (priv->window_group, window); - priv->async_actions = gtk_action_group_new ("async"); - priv->charset_actions = gtk_action_group_new ("charset"); - priv->composer_actions = gtk_action_group_new ("composer"); + priv->async_actions = e_ui_manager_get_action_group (ui_manager, "async"); + priv->composer_actions = e_ui_manager_get_action_group (ui_manager, "composer"); + + priv->charset_menu = g_menu_new (); + e_charset_add_to_g_menu (priv->charset_menu, "composer.EMsgComposer::charset-menu"); priv->extra_hdr_names = g_ptr_array_new (); priv->extra_hdr_values = g_ptr_array_new (); @@ -277,17 +322,15 @@ e_composer_private_constructed (EMsgComposer *composer) e_composer_actions_init (composer); - filename = e_composer_find_data_file ("evolution-composer.ui"); - gtk_ui_manager_add_ui_from_file (ui_manager, filename, &error); + filename = e_composer_find_data_file ("evolution-composer.eui"); + if (!e_ui_parser_merge_file (e_ui_manager_get_parser (ui_manager), filename, &local_error)) { + g_critical ("%s: Failed to merge .eui data: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error"); + } + g_clear_error (&local_error); g_free (filename); - composer_setup_charset_menu (composer); - - if (error != NULL) { - /* Henceforth, bad things start happening. */ - g_critical ("%s", error->message); - g_clear_error (&error); - } + action = e_ui_manager_get_action (ui_manager, "EMsgComposer::charset-menu"); + e_ui_action_set_state (action, g_variant_new_string (priv->charset)); /* Configure an EFocusTracker to manage selection actions. */ @@ -304,44 +347,21 @@ e_composer_private_constructed (EMsgComposer *composer) container = widget; /* Construct the main menu and headerbar. */ + ui_item = e_html_editor_get_ui_object (editor, E_HTML_EDITOR_UI_OBJECT_MAIN_MENU); + widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (ui_item)); - widget = e_html_editor_get_managed_widget (editor, "/main-menu"); - priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), window, &menu_button); + priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), window, &priv->menu_button); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); if (e_util_get_use_header_bar ()) { - const gchar *items[] = { - "/main-toolbar/pre-main-toolbar/send", - "/main-toolbar/pre-main-toolbar/send-separator", - "/main-toolbar/pre-main-toolbar/save-draft", - "/main-toolbar/pre-main-toolbar/save-draft-separator", - "/main-toolbar/prioritize-message-separator", - "/main-toolbar/toolbar-prioritize-message", - "/main-toolbar/toolbar-request-read-receipt" - }; - widget = composer_construct_header_bar (composer, menu_button); + ui_item = e_ui_manager_create_item (ui_manager, "main-headerbar"); + widget = GTK_WIDGET (ui_item); gtk_window_set_titlebar (window, widget); - - /* Destroy items from the toolbar, which are in the header bar */ - for (ii = 0; ii < G_N_ELEMENTS (items); ii++) { - widget = gtk_ui_manager_get_widget (ui_manager, items[ii]); - if (widget) - gtk_widget_destroy (widget); - } - } else { - /* We set the send button as important to have a label */ - widget = gtk_ui_manager_get_widget (ui_manager, "/main-toolbar/pre-main-toolbar/send"); - gtk_tool_item_set_is_important (GTK_TOOL_ITEM (widget), TRUE); - - if (menu_button) { - g_object_ref_sink (menu_button); - gtk_widget_destroy (menu_button); - } } - widget = e_html_editor_get_managed_widget (editor, "/main-toolbar"); + ui_item = e_html_editor_get_ui_object (editor, E_HTML_EDITOR_UI_OBJECT_MAIN_TOOLBAR); + widget = GTK_WIDGET (ui_item); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); e_binding_bind_property ( ACTION (TOOLBAR_SHOW_MAIN), "active", @@ -422,7 +442,7 @@ e_composer_private_constructed (EMsgComposer *composer) G_CALLBACK (composer_update_gallery_visibility), composer); g_signal_connect_swapped ( - ACTION (PICTURE_GALLERY), "toggled", + ACTION (PICTURE_GALLERY), "notify::active", G_CALLBACK (composer_update_gallery_visibility), composer); /* Initial sync */ @@ -553,12 +573,13 @@ e_composer_private_dispose (EMsgComposer *composer) g_clear_object (&composer->priv->attachment_paned); g_clear_object (&composer->priv->focus_tracker); g_clear_object (&composer->priv->window_group); - g_clear_object (&composer->priv->async_actions); - g_clear_object (&composer->priv->charset_actions); - g_clear_object (&composer->priv->composer_actions); + g_clear_object (&composer->priv->charset_menu); g_clear_object (&composer->priv->gallery_scrolled_window); g_clear_object (&composer->priv->redirect); g_clear_object (&composer->priv->menu_bar); + + composer->priv->async_actions = NULL; + composer->priv->composer_actions = NULL; } void @@ -584,30 +605,6 @@ e_composer_private_finalize (EMsgComposer *composer) g_clear_pointer (&composer->priv->content_hash, e_content_editor_util_free_content_hash); } -gchar * -e_composer_find_data_file (const gchar *basename) -{ - gchar *filename; - - g_return_val_if_fail (basename != NULL, NULL); - - /* Support running directly from the source tree. */ - filename = g_build_filename (".", basename, NULL); - if (g_file_test (filename, G_FILE_TEST_EXISTS)) - return filename; - g_free (filename); - - /* XXX This is kinda broken. */ - filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); - if (g_file_test (filename, G_FILE_TEST_EXISTS)) - return filename; - g_free (filename); - - g_critical ("Could not locate '%s'", basename); - - return NULL; -} - gchar * e_composer_get_default_charset (void) { diff --git a/src/composer/e-composer-private.h b/src/composer/e-composer-private.h index c6a7cd23c5..0414a9fce0 100644 --- a/src/composer/e-composer-private.h +++ b/src/composer/e-composer-private.h @@ -36,10 +36,6 @@ #include "e-composer-actions.h" #include "e-composer-header-table.h" -#ifdef HAVE_XFREE -#include -#endif - /* Shorthand, requires a variable named "composer". */ #define ACTION(name) (E_COMPOSER_ACTION_##name (composer)) @@ -65,9 +61,9 @@ struct _EMsgComposerPrivate { EFocusTracker *focus_tracker; GtkWindowGroup *window_group; - GtkActionGroup *async_actions; - GtkActionGroup *charset_actions; - GtkActionGroup *composer_actions; + GMenu *charset_menu; + EUIActionGroup *async_actions; /* owned by EHTMLEditor::ui-manager */ + EUIActionGroup *composer_actions; /* owned by EHTMLEditor::ui-manager */ GPtrArray *extra_hdr_names; GPtrArray *extra_hdr_values; @@ -80,6 +76,7 @@ struct _EMsgComposerPrivate { GtkWidget *address_dialog; EMenuBar *menu_bar; + GtkWidget *menu_button; /* owned by menu_bar */ gchar *mime_type; gchar *mime_body; @@ -138,7 +135,6 @@ void e_composer_private_finalize (EMsgComposer *composer); /* Private Utilities */ void e_composer_actions_init (EMsgComposer *composer); -gchar * e_composer_find_data_file (const gchar *basename); gchar * e_composer_get_default_charset (void); gchar * e_composer_decode_clue_value (const gchar *encoded_value); gchar * e_composer_encode_clue_value (const gchar *decoded_value); diff --git a/src/composer/e-msg-composer.c b/src/composer/e-msg-composer.c index 403eaaf255..6399861f0e 100644 --- a/src/composer/e-msg-composer.c +++ b/src/composer/e-msg-composer.c @@ -2136,7 +2136,7 @@ msg_composer_mail_identity_changed_cb (EMsgComposer *composer) ESourceSMIME *smime; EComposerHeaderTable *table; EContentEditor *cnt_editor; - GtkToggleAction *action; + EUIAction *action; ESource *source; gboolean active; gboolean can_sign; @@ -2200,25 +2200,25 @@ msg_composer_mail_identity_changed_cb (EMsgComposer *composer) to be set, when the default account has it set, but the other not. */ composer_realized = gtk_widget_get_realized (GTK_WIDGET (composer)); - action = GTK_TOGGLE_ACTION (ACTION (PGP_SIGN)); - active = composer_realized && gtk_toggle_action_get_active (action); + action = ACTION (PGP_SIGN); + active = composer_realized && e_ui_action_get_active (action); active |= (can_sign && pgp_sign); - gtk_toggle_action_set_active (action, active); + e_ui_action_set_active (action, active); - action = GTK_TOGGLE_ACTION (ACTION (PGP_ENCRYPT)); - active = composer_realized && gtk_toggle_action_get_active (action); + action = ACTION (PGP_ENCRYPT); + active = composer_realized && e_ui_action_get_active (action); active |= pgp_encrypt; - gtk_toggle_action_set_active (action, active); + e_ui_action_set_active (action, active); - action = GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN)); - active = composer_realized && gtk_toggle_action_get_active (action); + action = ACTION (SMIME_SIGN); + active = composer_realized && e_ui_action_get_active (action); active |= (can_sign && smime_sign); - gtk_toggle_action_set_active (action, active); + e_ui_action_set_active (action, active); - action = GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT)); - active = composer_realized && gtk_toggle_action_get_active (action); + action = ACTION (SMIME_ENCRYPT); + active = composer_realized && e_ui_action_get_active (action); active |= smime_encrypt; - gtk_toggle_action_set_active (action, active); + e_ui_action_set_active (action, active); was_disable_signature = composer->priv->disable_signature; @@ -2451,10 +2451,10 @@ msg_composer_delete_event_cb (EMsgComposer *composer) { /* If the "async" action group is insensitive, it means an * asynchronous operation is in progress. Block the event. */ - if (!gtk_action_group_get_sensitive (composer->priv->async_actions)) + if (!e_ui_action_group_get_sensitive (composer->priv->async_actions)) return TRUE; - gtk_action_activate (ACTION (CLOSE)); + g_action_activate (G_ACTION (ACTION (CLOSE)), NULL); return TRUE; } @@ -2463,25 +2463,25 @@ static void msg_composer_realize_cb (EMsgComposer *composer) { GSettings *settings; - GtkAction *action; + EUIAction *action; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); action = ACTION (TOOLBAR_PGP_SIGN); - if (gtk_action_get_visible (action) && !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) - gtk_action_set_visible (action, FALSE); + if (e_ui_action_get_visible (action) && !e_ui_action_get_active (action)) + e_ui_action_set_visible (action, FALSE); action = ACTION (TOOLBAR_PGP_ENCRYPT); - if (gtk_action_get_visible (action) && !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) - gtk_action_set_visible (action, FALSE); + if (e_ui_action_get_visible (action) && !e_ui_action_get_active (action)) + e_ui_action_set_visible (action, FALSE); action = ACTION (TOOLBAR_SMIME_SIGN); - if (gtk_action_get_visible (action) && !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) - gtk_action_set_visible (action, FALSE); + if (e_ui_action_get_visible (action) && !e_ui_action_get_active (action)) + e_ui_action_set_visible (action, FALSE); action = ACTION (TOOLBAR_SMIME_ENCRYPT); - if (gtk_action_get_visible (action) && !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) - gtk_action_set_visible (action, FALSE); + if (e_ui_action_get_visible (action) && !e_ui_action_get_active (action)) + e_ui_action_set_visible (action, FALSE); settings = e_util_ref_settings ("org.gnome.evolution.mail"); @@ -2501,11 +2501,8 @@ msg_composer_realize_cb (EMsgComposer *composer) key_id = e_source_openpgp_dup_key_id (e_source_get_extension (source, E_SOURCE_EXTENSION_OPENPGP)); if (key_id && *key_id) { - action = ACTION (TOOLBAR_PGP_SIGN); - gtk_action_set_visible (action, TRUE); - - action = ACTION (TOOLBAR_PGP_ENCRYPT); - gtk_action_set_visible (action, TRUE); + e_ui_action_set_visible (ACTION (TOOLBAR_PGP_SIGN), TRUE); + e_ui_action_set_visible (ACTION (TOOLBAR_PGP_ENCRYPT), TRUE); } g_free (key_id); @@ -2519,12 +2516,12 @@ msg_composer_realize_cb (EMsgComposer *composer) certificate = e_source_smime_dup_signing_certificate (smime_extension); if (certificate && *certificate) - gtk_action_set_visible (ACTION (TOOLBAR_SMIME_SIGN), TRUE); + e_ui_action_set_visible (ACTION (TOOLBAR_SMIME_SIGN), TRUE); g_free (certificate); certificate = e_source_smime_dup_encryption_certificate (smime_extension); if (certificate && *certificate) - gtk_action_set_visible (ACTION (TOOLBAR_SMIME_ENCRYPT), TRUE); + e_ui_action_set_visible (ACTION (TOOLBAR_SMIME_ENCRYPT), TRUE); g_free (certificate); } @@ -2548,7 +2545,7 @@ msg_composer_prepare_for_quit_cb (EShell *shell, g_object_weak_ref ( G_OBJECT (composer), (GWeakNotify) g_object_unref, activity); - gtk_action_activate (ACTION (SAVE_DRAFT)); + g_action_activate (G_ACTION (ACTION (SAVE_DRAFT)), NULL); } } @@ -2780,13 +2777,12 @@ msg_composer_constructed (GObject *object) EComposerHeaderTable *table; EHTMLEditor *editor; EContentEditor *cnt_editor; - GtkUIManager *ui_manager; - GtkToggleAction *action; + EUIManager *ui_manager; + EUIAction *action; GtkTargetList *target_list; GtkTargetEntry *targets; gint n_targets; GSettings *settings; - const gchar *id; gboolean active; /* Chain up to parent's constructed() method. */ @@ -2797,12 +2793,14 @@ msg_composer_constructed (GObject *object) g_return_if_fail (E_IS_HTML_EDITOR (composer->priv->editor)); shell = e_msg_composer_get_shell (composer); - - e_composer_private_constructed (composer); - editor = e_msg_composer_get_editor (composer); cnt_editor = e_html_editor_get_content_editor (editor); ui_manager = e_html_editor_get_ui_manager (editor); + + e_ui_manager_freeze (ui_manager); + + e_composer_private_constructed (composer); + attachment_view = e_msg_composer_get_attachment_view (composer); table = E_COMPOSER_HEADER_TABLE (composer->priv->header_table); @@ -2848,13 +2846,13 @@ msg_composer_constructed (GObject *object) /* FIXME This should be an EMsgComposer property. */ settings = e_util_ref_settings ("org.gnome.evolution.mail"); - action = GTK_TOGGLE_ACTION (ACTION (REQUEST_READ_RECEIPT)); + action = ACTION (REQUEST_READ_RECEIPT); active = g_settings_get_boolean (settings, "composer-request-receipt"); - gtk_toggle_action_set_active (action, active); + e_ui_action_set_active (action, active); - action = GTK_TOGGLE_ACTION (ACTION (DELIVERY_STATUS_NOTIFICATION)); + action = ACTION (DELIVERY_STATUS_NOTIFICATION); active = g_settings_get_boolean (settings, "composer-request-dsn"); - gtk_toggle_action_set_active (action, active); + e_ui_action_set_active (action, active); g_object_unref (settings); @@ -2951,12 +2949,12 @@ msg_composer_constructed (GObject *object) gtk_target_table_free (targets, n_targets); - id = "org.gnome.evolution.composer"; - e_plugin_ui_register_manager (ui_manager, id, composer); - e_plugin_ui_enable_manager (ui_manager, id); + e_plugin_ui_register_manager (ui_manager, "org.gnome.evolution.composer", composer); e_extensible_load_extensions (E_EXTENSIBLE (composer)); + e_ui_manager_thaw (ui_manager); + e_msg_composer_set_body_text (composer, "", TRUE); } @@ -3058,18 +3056,6 @@ msg_composer_key_press_event (GtkWidget *widget, e_msg_composer_get_header_table (composer), E_COMPOSER_HEADER_SUBJECT)->input_widget; -#ifdef HAVE_XFREE - if (event->keyval == XF86XK_Send) { - e_msg_composer_send (composer); - return TRUE; - } -#endif /* HAVE_XFREE */ - - if (event->keyval == GDK_KEY_Escape) { - gtk_action_activate (ACTION (CLOSE)); - return TRUE; - } - if (event->keyval == GDK_KEY_Tab && gtk_widget_is_focus (input_widget)) { e_content_editor_grab_focus (cnt_editor); return TRUE; @@ -3781,7 +3767,7 @@ handle_multipart_signed (EMsgComposer *composer, CamelContentType *content_type; CamelDataWrapper *content; CamelMimePart *mime_part; - GtkToggleAction *action = NULL; + EUIAction *action = NULL; const gchar *protocol; content = CAMEL_DATA_WRAPPER (multipart); @@ -3791,20 +3777,20 @@ handle_multipart_signed (EMsgComposer *composer, if (protocol == NULL) { action = NULL; } else if (g_ascii_strcasecmp (protocol, "application/pgp-signature") == 0) { - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN))) && - !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT)))) - action = GTK_TOGGLE_ACTION (ACTION (PGP_SIGN)); + if (!e_ui_action_get_active (ACTION (SMIME_SIGN)) && + !e_ui_action_get_active (ACTION (SMIME_ENCRYPT))) + action = ACTION (PGP_SIGN); } else if (g_ascii_strcasecmp (protocol, "application/pkcs7-signature") == 0 || g_ascii_strcasecmp (protocol, "application/xpkcs7signature") == 0 || g_ascii_strcasecmp (protocol, "application/xpkcs7-signature") == 0 || g_ascii_strcasecmp (protocol, "application/x-pkcs7-signature") == 0) { - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (PGP_SIGN))) && - !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (PGP_ENCRYPT)))) - action = GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN)); + if (!e_ui_action_get_active (ACTION (PGP_SIGN)) && + !e_ui_action_get_active (ACTION (PGP_ENCRYPT))) + action = ACTION (SMIME_SIGN); } if (action) - gtk_toggle_action_set_active (action, TRUE); + e_ui_action_set_active (action, TRUE); mime_part = camel_multipart_get_part ( multipart, CAMEL_MULTIPART_SIGNED_CONTENT); @@ -3881,28 +3867,28 @@ handle_multipart_encrypted (EMsgComposer *composer, CamelMimePart *mime_part; CamelSession *session; CamelCipherValidity *valid; - GtkToggleAction *action = NULL; + EUIAction *action = NULL; const gchar *protocol; content_type = camel_mime_part_get_content_type (multipart); protocol = camel_content_type_param (content_type, "protocol"); if (protocol && g_ascii_strcasecmp (protocol, "application/pgp-encrypted") == 0) { - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN))) && - !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT)))) - action = GTK_TOGGLE_ACTION (ACTION (PGP_ENCRYPT)); + if (!e_ui_action_get_active (ACTION (SMIME_SIGN)) && + !e_ui_action_get_active (ACTION (SMIME_ENCRYPT))) + action = ACTION (PGP_ENCRYPT); } else if (content_type && ( camel_content_type_is (content_type, "application", "pkcs7-mime") || camel_content_type_is (content_type, "application", "xpkcs7mime") || camel_content_type_is (content_type, "application", "xpkcs7-mime") || camel_content_type_is (content_type, "application", "x-pkcs7-mime"))) { - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (PGP_SIGN))) && - !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (PGP_ENCRYPT)))) - action = GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT)); + if (!e_ui_action_get_active (ACTION (PGP_SIGN)) && + !e_ui_action_get_active (ACTION (PGP_ENCRYPT))) + action = ACTION (SMIME_ENCRYPT); } if (action) - gtk_toggle_action_set_active (action, TRUE); + e_ui_action_set_active (action, TRUE); session = e_msg_composer_ref_session (composer); cipher = camel_gpg_context_new (session); @@ -4372,7 +4358,6 @@ e_msg_composer_setup_with_message (EMsgComposer *composer, ESource *source = NULL; EHTMLEditor *editor; EContentEditor *cnt_editor; - GtkToggleAction *action; gchar *identity_uid; gint len, i; guint jj, jjlen; @@ -4613,17 +4598,13 @@ e_msg_composer_setup_with_message (EMsgComposer *composer, e_html_editor_set_mode (editor, mode); } else if (g_ascii_strcasecmp (flags[i], "pgp-sign") == 0) { - action = GTK_TOGGLE_ACTION (ACTION (PGP_SIGN)); - gtk_toggle_action_set_active (action, TRUE); + e_ui_action_set_active (ACTION (PGP_SIGN), TRUE); } else if (g_ascii_strcasecmp (flags[i], "pgp-encrypt") == 0) { - action = GTK_TOGGLE_ACTION (ACTION (PGP_ENCRYPT)); - gtk_toggle_action_set_active (action, TRUE); + e_ui_action_set_active (ACTION (PGP_ENCRYPT), TRUE); } else if (g_ascii_strcasecmp (flags[i], "smime-sign") == 0) { - action = GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN)); - gtk_toggle_action_set_active (action, TRUE); + e_ui_action_set_active (ACTION (SMIME_SIGN), TRUE); } else if (g_ascii_strcasecmp (flags[i], "smime-encrypt") == 0) { - action = GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT)); - gtk_toggle_action_set_active (action, TRUE); + e_ui_action_set_active (ACTION (SMIME_ENCRYPT), TRUE); } } g_strfreev (flags); @@ -4666,24 +4647,20 @@ e_msg_composer_setup_with_message (EMsgComposer *composer, } if (g_strcmp0 (camel_medium_get_header (CAMEL_MEDIUM (message), "X-Evolution-Request-DSN"), "1") == 0) { - action = GTK_TOGGLE_ACTION (ACTION (DELIVERY_STATUS_NOTIFICATION)); - gtk_toggle_action_set_active (action, TRUE); + e_ui_action_set_active (ACTION (DELIVERY_STATUS_NOTIFICATION), TRUE); } /* Remove any other X-Evolution-* headers that may have been set */ camel_name_value_array_free (mail_tool_remove_xevolution_headers (message)); /* Check for receipt request */ - if (camel_medium_get_header ( - CAMEL_MEDIUM (message), "Disposition-Notification-To")) { - action = GTK_TOGGLE_ACTION (ACTION (REQUEST_READ_RECEIPT)); - gtk_toggle_action_set_active (action, TRUE); + if (camel_medium_get_header (CAMEL_MEDIUM (message), "Disposition-Notification-To")) { + e_ui_action_set_active (ACTION (REQUEST_READ_RECEIPT), TRUE); } /* Check for mail priority */ if (camel_medium_get_header (CAMEL_MEDIUM (message), "X-Priority")) { - action = GTK_TOGGLE_ACTION (ACTION (PRIORITIZE_MESSAGE)); - gtk_toggle_action_set_active (action, TRUE); + e_ui_action_set_active (ACTION (PRIORITIZE_MESSAGE), TRUE); } /* set extra headers */ @@ -4756,9 +4733,7 @@ e_msg_composer_setup_with_message (EMsgComposer *composer, camel_content_type_is (content_type, "application", "xpkcs7-mime") || camel_content_type_is (content_type, "application", "x-pkcs7-mime"))) { #ifdef ENABLE_SMIME - gtk_toggle_action_set_active ( - GTK_TOGGLE_ACTION ( - ACTION (SMIME_ENCRYPT)), TRUE); + e_ui_action_set_active (ACTION (SMIME_ENCRYPT), TRUE); is_smime_encrypted = TRUE; #endif } @@ -5076,16 +5051,13 @@ msg_composer_alert_response_cb (EAlert *alert, { if (response_id == GTK_RESPONSE_ACCEPT) { EMsgComposer *composer = user_data; - GtkAction *action; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); - action = ACTION (PGP_ENCRYPT); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE); + e_ui_action_set_active (ACTION (PGP_ENCRYPT), FALSE); #ifdef ENABLE_SMIME - action = ACTION (SMIME_ENCRYPT); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), FALSE); + e_ui_action_set_active (ACTION (SMIME_ENCRYPT), FALSE); #endif e_msg_composer_send (composer); @@ -5110,9 +5082,10 @@ e_msg_composer_claim_no_build_message_error (EMsgComposer *composer, alert = e_alert_new ("mail-composer:no-build-message", error->message, NULL); if (is_send_op && g_error_matches (error, CAMEL_CIPHER_CONTEXT_ERROR, CAMEL_CIPHER_CONTEXT_ERROR_KEY_NOT_FOUND)) { - GtkAction *action; + EUIAction *action; - action = gtk_action_new ("msg-composer-alert-action-0", _("Send _without encryption"), NULL, NULL); + action = e_ui_action_new ("msg-composer-map", "msg-composer-alert-action-0", NULL); + e_ui_action_set_label (action, _("Send _without encryption")); e_alert_add_action (alert, action, GTK_RESPONSE_ACCEPT, FALSE); g_object_unref (action); @@ -6043,13 +6016,8 @@ e_msg_composer_set_body (EMsgComposer *composer, priv->mime_type = g_strdup (mime_type); if (!msg_composer_get_can_sign (composer)) { - GtkToggleAction *action; - - action = GTK_TOGGLE_ACTION (ACTION (PGP_SIGN)); - gtk_toggle_action_set_active (action, FALSE); - - action = GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN)); - gtk_toggle_action_set_active (action, FALSE); + e_ui_action_set_active (ACTION (PGP_SIGN), FALSE); + e_ui_action_set_active (ACTION (SMIME_SIGN), FALSE); } } @@ -6386,7 +6354,6 @@ e_msg_composer_get_message (EMsgComposer *composer, gpointer user_data) { GTask *task; - GtkAction *action; ComposerFlags flags = 0; EHTMLEditor *editor; @@ -6398,33 +6365,26 @@ e_msg_composer_get_message (EMsgComposer *composer, e_html_editor_get_mode (editor) == E_CONTENT_EDITOR_MODE_MARKDOWN_HTML) flags |= COMPOSER_FLAG_HTML_CONTENT; - action = ACTION (PRIORITIZE_MESSAGE); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (PRIORITIZE_MESSAGE))) flags |= COMPOSER_FLAG_PRIORITIZE_MESSAGE; - action = ACTION (REQUEST_READ_RECEIPT); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (REQUEST_READ_RECEIPT))) flags |= COMPOSER_FLAG_REQUEST_READ_RECEIPT; - action = ACTION (DELIVERY_STATUS_NOTIFICATION); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (DELIVERY_STATUS_NOTIFICATION))) flags |= COMPOSER_FLAG_DELIVERY_STATUS_NOTIFICATION; - action = ACTION (PGP_SIGN); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (PGP_SIGN))) flags |= COMPOSER_FLAG_PGP_SIGN; - action = ACTION (PGP_ENCRYPT); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (PGP_ENCRYPT))) flags |= COMPOSER_FLAG_PGP_ENCRYPT; #ifdef ENABLE_SMIME - action = ACTION (SMIME_SIGN); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (SMIME_SIGN))) flags |= COMPOSER_FLAG_SMIME_SIGN; - action = ACTION (SMIME_ENCRYPT); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (SMIME_ENCRYPT))) flags |= COMPOSER_FLAG_SMIME_ENCRYPT; #endif @@ -6512,40 +6472,32 @@ e_msg_composer_get_message_draft (EMsgComposer *composer, { GTask *task; ComposerFlags flags = COMPOSER_FLAG_SAVE_DRAFT; - GtkAction *action; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); /* We want to save HTML content everytime when we save as draft */ flags |= COMPOSER_FLAG_SAVE_DRAFT; - action = ACTION (PRIORITIZE_MESSAGE); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (PRIORITIZE_MESSAGE))) flags |= COMPOSER_FLAG_PRIORITIZE_MESSAGE; - action = ACTION (REQUEST_READ_RECEIPT); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (REQUEST_READ_RECEIPT))) flags |= COMPOSER_FLAG_REQUEST_READ_RECEIPT; - action = ACTION (DELIVERY_STATUS_NOTIFICATION); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (DELIVERY_STATUS_NOTIFICATION))) flags |= COMPOSER_FLAG_DELIVERY_STATUS_NOTIFICATION; - action = ACTION (PGP_SIGN); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (PGP_SIGN))) flags |= COMPOSER_FLAG_PGP_SIGN; - action = ACTION (PGP_ENCRYPT); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (PGP_ENCRYPT))) flags |= COMPOSER_FLAG_PGP_ENCRYPT; #ifdef ENABLE_SMIME - action = ACTION (SMIME_SIGN); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (SMIME_SIGN))) flags |= COMPOSER_FLAG_SMIME_SIGN; - action = ACTION (SMIME_ENCRYPT); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) + if (e_ui_action_get_active (ACTION (SMIME_ENCRYPT))) flags |= COMPOSER_FLAG_SMIME_ENCRYPT; #endif @@ -6785,7 +6737,7 @@ e_msg_composer_can_close (EMsgComposer *composer, /* this means that there is an async operation running, * in which case the composer cannot be closed */ - if (!gtk_action_group_get_sensitive (composer->priv->async_actions)) + if (!e_ui_action_group_get_sensitive (composer->priv->async_actions)) return FALSE; if (!e_content_editor_get_changed (cnt_editor) || @@ -6812,7 +6764,7 @@ e_msg_composer_can_close (EMsgComposer *composer, case GTK_RESPONSE_YES: e_msg_composer_request_close (composer); if (can_save_draft) - gtk_action_activate (ACTION (SAVE_DRAFT)); + g_action_activate (G_ACTION (ACTION (SAVE_DRAFT)), NULL); break; case GTK_RESPONSE_NO: @@ -7113,8 +7065,8 @@ e_msg_composer_check_autocrypt (EMsgComposer *composer, if (alert_bar) e_alert_bar_remove_alert_by_tag (alert_bar, "mail-composer:info-autocrypt-header-too-large"); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN))) || - gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT)))) { + if (e_ui_action_get_active (ACTION (SMIME_SIGN)) || + e_ui_action_get_active (ACTION (SMIME_ENCRYPT))) { /* Autocrypt is about GPG, thus ignore it when the user uses S/MIME */ return; } @@ -7206,8 +7158,8 @@ e_msg_composer_check_autocrypt (EMsgComposer *composer, if (send_prefer_encrypt && sender_prefer_encrypt && msg_composer_get_can_sign (composer)) { /* Set both sign & encrypt, not only encrypt */ - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (ACTION (PGP_SIGN)), TRUE); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (ACTION (PGP_ENCRYPT)), TRUE); + e_ui_action_set_active (ACTION (PGP_SIGN), TRUE); + e_ui_action_set_active (ACTION (PGP_ENCRYPT), TRUE); } g_free (from_email); @@ -7223,19 +7175,10 @@ e_msg_composer_set_is_imip (EMsgComposer *composer, composer->priv->is_imip = is_imip; if (!msg_composer_get_can_sign (composer)) { - GtkToggleAction *action; - - action = GTK_TOGGLE_ACTION (ACTION (PGP_SIGN)); - gtk_toggle_action_set_active (action, FALSE); - - action = GTK_TOGGLE_ACTION (ACTION (PGP_ENCRYPT)); - gtk_toggle_action_set_active (action, FALSE); - - action = GTK_TOGGLE_ACTION (ACTION (SMIME_SIGN)); - gtk_toggle_action_set_active (action, FALSE); - - action = GTK_TOGGLE_ACTION (ACTION (SMIME_ENCRYPT)); - gtk_toggle_action_set_active (action, FALSE); + e_ui_action_set_active (ACTION (PGP_SIGN), FALSE); + e_ui_action_set_active (ACTION (PGP_ENCRYPT), FALSE); + e_ui_action_set_active (ACTION (SMIME_SIGN), FALSE); + e_ui_action_set_active (ACTION (SMIME_ENCRYPT), FALSE); } } diff --git a/src/composer/evolution-composer.ui b/src/composer/evolution-composer.ui deleted file mode 100644 index f46dd11269..0000000000 --- a/src/composer/evolution-composer.ui +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/e-util/CMakeLists.txt b/src/e-util/CMakeLists.txt index 326f2acae7..27d8ffcb6f 100644 --- a/src/e-util/CMakeLists.txt +++ b/src/e-util/CMakeLists.txt @@ -8,7 +8,6 @@ add_error_files(e-util ) set(uifiles - e-html-editor-manager.ui e-send-options.ui e-table-config.ui e-timezone-dialog.ui @@ -117,10 +116,8 @@ set(SOURCES e-dialog-utils.c e-dialog-widgets.c e-ellipsized-combo-box-text.c - e-emoticon-action.c e-emoticon-chooser-menu.c e-emoticon-chooser.c - e-emoticon-tool-button.c e-emoticon.c e-event.c e-file-request.c @@ -175,7 +172,6 @@ set(SOURCES e-markdown-utils.c e-marshal.c e-menu-bar.c - e-menu-tool-action.c e-menu-tool-button.c e-misc-utils.c e-mktemp.c @@ -194,7 +190,6 @@ set(SOURCES e-plugin-ui.c e-plugin.c e-poolv.c - e-popup-action.c e-popup-menu.c e-port-entry.c e-preferences-window.c @@ -278,6 +273,11 @@ set(SOURCES e-tree-table-adapter.c e-tree-view-frame.c e-tree.c + e-ui-action.c + e-ui-action-group.c + e-ui-manager.c + e-ui-menu.c + e-ui-parser.c e-unicode.c e-url-entry.c e-util-private.h @@ -402,10 +402,8 @@ set(HEADERS e-dialog-utils.h e-dialog-widgets.h e-ellipsized-combo-box-text.h - e-emoticon-action.h e-emoticon-chooser-menu.h e-emoticon-chooser.h - e-emoticon-tool-button.h e-emoticon.h e-event.h e-file-request.h @@ -456,7 +454,6 @@ set(HEADERS e-markdown-editor.h e-markdown-utils.h e-menu-bar.h - e-menu-tool-action.h e-menu-tool-button.h e-misc-utils.h e-mktemp.h @@ -475,7 +472,6 @@ set(HEADERS e-plugin-ui.h e-plugin.h e-poolv.h - e-popup-action.h e-popup-menu.h e-port-entry.h e-preferences-window.h @@ -561,6 +557,11 @@ set(HEADERS e-tree-table-adapter.h e-tree-view-frame.h e-tree.h + e-ui-action.h + e-ui-action-group.h + e-ui-manager.h + e-ui-menu.h + e-ui-parser.h e-unicode.h e-url-entry.h e-util-enums.h diff --git a/src/e-util/e-action-combo-box.c b/src/e-util/e-action-combo-box.c index cf05e1234e..135463a6c8 100644 --- a/src/e-util/e-action-combo-box.c +++ b/src/e-util/e-action-combo-box.c @@ -18,10 +18,13 @@ #include "evolution-config.h" -#include "e-action-combo-box.h" +#include + +#include "e-ui-action.h" +#include "e-ui-action-group.h" #include "e-misc-utils.h" -#include +#include "e-action-combo-box.h" enum { COLUMN_ACTION, @@ -30,14 +33,15 @@ enum { enum { PROP_0, - PROP_ACTION + PROP_ACTION, + PROP_CURRENT_VALUE }; struct _EActionComboBoxPrivate { - GtkRadioAction *action; - GtkActionGroup *action_group; + EUIAction *action; + EUIActionGroup *action_group; GHashTable *index; - guint changed_handler_id; /* action::changed */ + guint notify_state_handler_id; /* action::notify::state */ guint group_sensitive_handler_id; /* action-group::sensitive */ guint group_visible_handler_id; /* action-group::visible */ gboolean group_has_icons; @@ -47,20 +51,29 @@ struct _EActionComboBoxPrivate { G_DEFINE_TYPE_WITH_PRIVATE (EActionComboBox, e_action_combo_box, GTK_TYPE_COMBO_BOX) static void -action_combo_box_action_changed_cb (GtkRadioAction *action, - GtkRadioAction *current, - EActionComboBox *combo_box) +action_combo_box_action_notify_state_cb (EUIAction *action, + GParamSpec *param, + EActionComboBox *combo_box) { - GtkTreeRowReference *reference; + GtkTreeRowReference *reference = NULL; GtkTreeModel *model; GtkTreePath *path; + GVariant *state; GtkTreeIter iter; gboolean valid; - reference = g_hash_table_lookup ( - combo_box->priv->index, GINT_TO_POINTER ( - gtk_radio_action_get_current_value (current))); - g_return_if_fail (reference != NULL); + state = g_action_get_state (G_ACTION (action)); + if (state && g_variant_is_of_type (state, G_VARIANT_TYPE_INT32)) { + reference = g_hash_table_lookup (combo_box->priv->index, GINT_TO_POINTER (g_variant_get_int32 (state))); + g_return_if_fail (reference != NULL); + } else { + g_warn_if_reached (); + } + + g_clear_pointer (&state, g_variant_unref); + + if (!reference) + return; model = gtk_tree_row_reference_get_model (reference); path = gtk_tree_row_reference_get_path (reference); @@ -72,14 +85,14 @@ action_combo_box_action_changed_cb (GtkRadioAction *action, } static void -action_combo_box_action_group_notify_cb (GtkActionGroup *action_group, +action_combo_box_action_group_notify_cb (EUIActionGroup *action_group, GParamSpec *pspec, EActionComboBox *combo_box) { - g_object_set ( - combo_box, "sensitive", - gtk_action_group_get_sensitive (action_group), "visible", - gtk_action_group_get_visible (action_group), NULL); + g_object_set (combo_box, + "sensitive", e_ui_action_group_get_sensitive (action_group), + "visible", e_ui_action_group_get_visible (action_group), + NULL); } static void @@ -89,11 +102,7 @@ action_combo_box_render_pixbuf (GtkCellLayout *layout, GtkTreeIter *iter, EActionComboBox *combo_box) { - GtkRadioAction *action; - gchar *icon_name; - gchar *stock_id; - gboolean sensitive; - gboolean visible; + EUIAction *action; gint width; gtk_tree_model_get (model, iter, COLUMN_ACTION, &action, -1); @@ -102,14 +111,6 @@ action_combo_box_render_pixbuf (GtkCellLayout *layout, if (action == NULL) return; - g_object_get ( - G_OBJECT (action), - "icon-name", &icon_name, - "sensitive", &sensitive, - "stock-id", &stock_id, - "visible", &visible, - NULL); - /* If some action has an icon */ if (combo_box->priv->group_has_icons) /* Keep the pixbuf renderer a fixed size for proper alignment. */ @@ -117,34 +118,16 @@ action_combo_box_render_pixbuf (GtkCellLayout *layout, else width = 0; - /* We can't set both "icon-name" and "stock-id" because setting - * one unsets the other. So pick the one that has a non-NULL - * value. If both are non-NULL, "stock-id" wins. */ - - if (stock_id != NULL) - g_object_set ( - G_OBJECT (renderer), - "sensitive", sensitive, - "icon-name", NULL, - "stock-id", stock_id, - "stock-size", GTK_ICON_SIZE_MENU, - "visible", visible, - "width", width, - NULL); - else - g_object_set ( - G_OBJECT (renderer), - "sensitive", sensitive, - "icon-name", icon_name, - "stock-id", NULL, - "stock-size", GTK_ICON_SIZE_MENU, - "visible", visible, - "width", width, - NULL); + g_object_set ( + G_OBJECT (renderer), + "sensitive", e_ui_action_get_sensitive (action), + "icon-name", e_ui_action_get_icon_name (action), + "stock-size", GTK_ICON_SIZE_MENU, + "visible", e_ui_action_is_visible (action), + "width", width, + NULL); g_object_unref (action); - g_free (icon_name); - g_free (stock_id); } static void @@ -154,11 +137,9 @@ action_combo_box_render_text (GtkCellLayout *layout, GtkTreeIter *iter, EActionComboBox *combo_box) { - GtkRadioAction *action; - gchar **strv; - gchar *label; - gboolean sensitive; - gboolean visible; + EUIAction *action; + const gchar *const_label; + gchar *label = NULL; gint xpad; gtk_tree_model_get (model, iter, COLUMN_ACTION, &action, -1); @@ -167,26 +148,30 @@ action_combo_box_render_text (GtkCellLayout *layout, if (action == NULL) return; - g_object_get ( - G_OBJECT (action), - "label", &label, - "sensitive", &sensitive, - "visible", &visible, - NULL); + const_label = e_ui_action_get_label (action); + if (const_label && strchr (const_label, '_')) { + guint ii, wr = 0; - /* Strip out underscores. */ - strv = g_strsplit (label, "_", -1); - g_free (label); - label = g_strjoinv (NULL, strv); - g_strfreev (strv); + /* Strip out underscores. */ + label = g_strdup (const_label); + for (ii = 0; label[ii]; ii++) { + if (label[ii] != '_') { + if (wr != ii) + label[wr] = label[ii]; + wr++; + } + } + if (ii != wr) + label[wr] = '\0'; + } xpad = combo_box->priv->group_has_icons ? 3 : 0; g_object_set ( G_OBJECT (renderer), - "sensitive", sensitive, - "text", label, - "visible", visible, + "sensitive", e_ui_action_get_sensitive (action), + "text", label ? label : const_label, + "visible", e_ui_action_is_visible (action), "xpad", xpad, NULL); @@ -198,14 +183,13 @@ static gboolean action_combo_box_is_row_separator (GtkTreeModel *model, GtkTreeIter *iter) { - GtkAction *action; + EUIAction *action; gboolean separator; /* NULL actions are rendered as separators. */ gtk_tree_model_get (model, iter, COLUMN_ACTION, &action, -1); separator = (action == NULL); - if (action != NULL) - g_object_unref (action); + g_clear_object (&action); return separator; } @@ -214,7 +198,8 @@ static void action_combo_box_update_model (EActionComboBox *combo_box) { GtkListStore *list_store; - GSList *list; + GPtrArray *radio_group; + guint ii; g_hash_table_remove_all (combo_box->priv->index); @@ -227,45 +212,34 @@ action_combo_box_update_model (EActionComboBox *combo_box) * insert separators in between consecutive integer values and * still maintain the proper ordering. */ list_store = gtk_list_store_new ( - 2, GTK_TYPE_RADIO_ACTION, G_TYPE_FLOAT); + 2, E_TYPE_UI_ACTION, G_TYPE_FLOAT); - list = gtk_radio_action_get_group (combo_box->priv->action); + radio_group = e_ui_action_get_radio_group (combo_box->priv->action); combo_box->priv->group_has_icons = FALSE; - while (list != NULL) { + for (ii = 0; radio_group && ii < radio_group->len; ii++) { + EUIAction *action = g_ptr_array_index (radio_group, ii); GtkTreeRowReference *reference; - GtkRadioAction *action = list->data; GtkTreePath *path; GtkTreeIter iter; - gchar *icon_name = NULL; - gchar *stock_id = NULL; - gboolean visible = FALSE; - gint value; + GVariant *target; + gint value = G_MININT32; - g_object_get (action, - "icon-name", &icon_name, - "stock-id", &stock_id, - "visible", &visible, - NULL); - - if (!visible) { - g_free (icon_name); - g_free (stock_id); - - list = g_slist_next (list); + if (!e_ui_action_get_visible (action)) continue; - } - combo_box->priv->group_has_icons |= - (icon_name != NULL || stock_id != NULL); - g_free (icon_name); - g_free (stock_id); + combo_box->priv->group_has_icons |= e_ui_action_get_icon_name (action) != NULL; + + target = e_ui_action_ref_target (action); + if (target && g_variant_is_of_type (target, G_VARIANT_TYPE_INT32)) + value = g_variant_get_int32 (target); + g_clear_pointer (&target, g_variant_unref); gtk_list_store_append (list_store, &iter); - g_object_get (action, "value", &value, NULL); - gtk_list_store_set ( - list_store, &iter, COLUMN_ACTION, - list->data, COLUMN_SORT, (gfloat) value, -1); + gtk_list_store_set (list_store, &iter, + COLUMN_ACTION, action, + COLUMN_SORT, (gfloat) value, + -1); path = gtk_tree_model_get_path ( GTK_TREE_MODEL (list_store), &iter); @@ -275,8 +249,6 @@ action_combo_box_update_model (EActionComboBox *combo_box) combo_box->priv->index, GINT_TO_POINTER (value), reference); gtk_tree_path_free (path); - - list = g_slist_next (list); } gtk_tree_sortable_set_sort_column_id ( @@ -286,10 +258,7 @@ action_combo_box_update_model (EActionComboBox *combo_box) GTK_COMBO_BOX (combo_box), GTK_TREE_MODEL (list_store)); g_object_unref (list_store); - action_combo_box_action_changed_cb ( - combo_box->priv->action, - combo_box->priv->action, - combo_box); + action_combo_box_action_notify_state_cb (combo_box->priv->action, NULL, combo_box); } static void @@ -316,6 +285,11 @@ action_combo_box_set_property (GObject *object, E_ACTION_COMBO_BOX (object), g_value_get_object (value)); return; + case PROP_CURRENT_VALUE: + e_action_combo_box_set_current_value ( + E_ACTION_COMBO_BOX (object), + g_value_get_int (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -333,6 +307,11 @@ action_combo_box_get_property (GObject *object, value, e_action_combo_box_get_action ( E_ACTION_COMBO_BOX (object))); return; + case PROP_CURRENT_VALUE: + g_value_set_int ( + value, e_action_combo_box_get_current_value ( + E_ACTION_COMBO_BOX (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -343,6 +322,8 @@ action_combo_box_dispose (GObject *object) { EActionComboBox *self = E_ACTION_COMBO_BOX (object); + e_action_combo_box_set_action (self, NULL); + g_clear_object (&self->priv->action); g_clear_object (&self->priv->action_group); g_hash_table_remove_all (self->priv->index); @@ -400,10 +381,9 @@ action_combo_box_constructed (GObject *object) static void action_combo_box_changed (GtkComboBox *combo_box) { - GtkRadioAction *action; + EUIAction *action; GtkTreeModel *model; GtkTreeIter iter; - gint value; /* This method is virtual, so no need to chain up. */ @@ -412,8 +392,8 @@ action_combo_box_changed (GtkComboBox *combo_box) model = gtk_combo_box_get_model (combo_box); gtk_tree_model_get (model, &iter, COLUMN_ACTION, &action, -1); - g_object_get (action, "value", &value, NULL); - gtk_radio_action_set_current_value (action, value); + if (action != NULL) + e_ui_action_set_active (action, TRUE); g_object_unref (action); } @@ -443,8 +423,16 @@ e_action_combo_box_class_init (EActionComboBoxClass *class) g_param_spec_object ( "action", "Action", - "A GtkRadioAction", - GTK_TYPE_RADIO_ACTION, + "An EUIAction", + E_TYPE_UI_ACTION, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_CURRENT_VALUE, + g_param_spec_int ( + "current-value", NULL, NULL, + G_MININT32, G_MAXINT32, 0, G_PARAM_READWRITE)); } @@ -466,12 +454,12 @@ e_action_combo_box_new (void) } GtkWidget * -e_action_combo_box_new_with_action (GtkRadioAction *action) +e_action_combo_box_new_with_action (EUIAction *action) { return g_object_new (E_TYPE_ACTION_COMBO_BOX, "action", action, NULL); } -GtkRadioAction * +EUIAction * e_action_combo_box_get_action (EActionComboBox *combo_box) { g_return_val_if_fail (E_IS_ACTION_COMBO_BOX (combo_box), NULL); @@ -481,46 +469,60 @@ e_action_combo_box_get_action (EActionComboBox *combo_box) void e_action_combo_box_set_action (EActionComboBox *combo_box, - GtkRadioAction *action) + EUIAction *action) { + gboolean last_state_set = FALSE; + gint last_state; + g_return_if_fail (E_IS_ACTION_COMBO_BOX (combo_box)); if (action != NULL) - g_return_if_fail (GTK_IS_RADIO_ACTION (action)); + g_return_if_fail (E_IS_UI_ACTION (action)); - if (combo_box->priv->action != NULL) { - g_signal_handler_disconnect ( - combo_box->priv->action, - combo_box->priv->changed_handler_id); - g_object_unref (combo_box->priv->action); + if (action == combo_box->priv->action) + return; + + if (combo_box->priv->action) { + last_state_set = TRUE; + last_state = e_action_combo_box_get_current_value (combo_box); } - if (combo_box->priv->action_group != NULL) { + if (combo_box->priv->action_group) { g_signal_handler_disconnect ( combo_box->priv->action_group, combo_box->priv->group_sensitive_handler_id); g_signal_handler_disconnect ( combo_box->priv->action_group, combo_box->priv->group_visible_handler_id); - g_object_unref (combo_box->priv->action_group); - combo_box->priv->action_group = NULL; + g_clear_object (&combo_box->priv->action_group); + combo_box->priv->group_visible_handler_id = 0; + combo_box->priv->group_sensitive_handler_id = 0; } if (action != NULL) { - /* This also adds a reference to the combo_box->priv->action_group */ - g_object_get ( - g_object_ref (action), "action-group", - &combo_box->priv->action_group, NULL); + g_object_ref (action); + combo_box->priv->action_group = e_ui_action_get_action_group (action); + + if (combo_box->priv->action_group) + g_object_ref (combo_box->priv->action_group); + } + + if (combo_box->priv->action != NULL) { + g_signal_handler_disconnect ( + combo_box->priv->action, + combo_box->priv->notify_state_handler_id); + g_clear_object (&combo_box->priv->action); + combo_box->priv->notify_state_handler_id = 0; } combo_box->priv->action = action; action_combo_box_update_model (combo_box); - if (combo_box->priv->action != NULL) - combo_box->priv->changed_handler_id = g_signal_connect ( - combo_box->priv->action, "changed", - G_CALLBACK (action_combo_box_action_changed_cb), - combo_box); + if (combo_box->priv->action != NULL) { + combo_box->priv->notify_state_handler_id = g_signal_connect ( + combo_box->priv->action, "notify::state", + G_CALLBACK (action_combo_box_action_notify_state_cb), combo_box); + } if (combo_box->priv->action_group != NULL) { combo_box->priv->group_sensitive_handler_id = @@ -537,16 +539,33 @@ e_action_combo_box_set_action (EActionComboBox *combo_box, combo_box); } + if (action && last_state_set && g_hash_table_contains (combo_box->priv->index, GINT_TO_POINTER (last_state))) + e_action_combo_box_set_current_value (combo_box, last_state); + g_object_notify (G_OBJECT (combo_box), "action"); } gint e_action_combo_box_get_current_value (EActionComboBox *combo_box) { + GVariant *state; + gint value = 0; + g_return_val_if_fail (E_IS_ACTION_COMBO_BOX (combo_box), 0); g_return_val_if_fail (combo_box->priv->action != NULL, 0); - return gtk_radio_action_get_current_value (combo_box->priv->action); + state = g_action_get_state (G_ACTION (combo_box->priv->action)); + if (state && g_variant_is_of_type (state, G_VARIANT_TYPE_INT32)) { + value = g_variant_get_int32 (state); + } else if (state) { + g_warning ("%s: Action '%s' does not hold int32 state", G_STRFUNC, g_action_get_name (G_ACTION (combo_box->priv->action))); + } else { + g_warning ("%s: Action '%s' does not have state", G_STRFUNC, g_action_get_name (G_ACTION (combo_box->priv->action))); + } + + g_clear_pointer (&state, g_variant_unref); + + return value; } void @@ -556,8 +575,12 @@ e_action_combo_box_set_current_value (EActionComboBox *combo_box, g_return_if_fail (E_IS_ACTION_COMBO_BOX (combo_box)); g_return_if_fail (combo_box->priv->action != NULL); - gtk_radio_action_set_current_value ( - combo_box->priv->action, current_value); + if (current_value == e_action_combo_box_get_current_value (combo_box)) + return; + + e_ui_action_set_state (combo_box->priv->action, g_variant_new_int32 (current_value)); + + g_object_notify (G_OBJECT (combo_box), "current-value"); } void diff --git a/src/e-util/e-action-combo-box.h b/src/e-util/e-action-combo-box.h index 7ec81cda80..30131e33d6 100644 --- a/src/e-util/e-action-combo-box.h +++ b/src/e-util/e-action-combo-box.h @@ -23,11 +23,12 @@ #ifndef E_ACTION_COMBO_BOX_H #define E_ACTION_COMBO_BOX_H -/* This is a GtkComboBox that is driven by a group of GtkRadioActions. - * Just plug in a GtkRadioAction and the widget will handle the rest. +/* This is a GtkComboBox that is driven by a group of an EUIAction. + * Just plug in an EUIAction and the widget will handle the rest. * (Based on GtkhtmlComboBox.) */ #include +#include /* Standard GObject macros */ #define E_TYPE_ACTION_COMBO_BOX \ @@ -66,10 +67,10 @@ struct _EActionComboBoxClass { GType e_action_combo_box_get_type (void) G_GNUC_CONST; GtkWidget * e_action_combo_box_new (void); GtkWidget * e_action_combo_box_new_with_action - (GtkRadioAction *action); -GtkRadioAction *e_action_combo_box_get_action (EActionComboBox *combo_box); + (EUIAction *action); +EUIAction * e_action_combo_box_get_action (EActionComboBox *combo_box); void e_action_combo_box_set_action (EActionComboBox *combo_box, - GtkRadioAction *action); + EUIAction *action); gint e_action_combo_box_get_current_value (EActionComboBox *combo_box); void e_action_combo_box_set_current_value diff --git a/src/e-util/e-alert-bar.c b/src/e-util/e-alert-bar.c index ba94050036..e57cafe376 100644 --- a/src/e-util/e-alert-bar.c +++ b/src/e-util/e-alert-bar.c @@ -170,7 +170,7 @@ alert_bar_show_alert (EAlertBar *alert_bar) /* Add alert-specific buttons. */ link = e_alert_peek_actions (alert); while (link != NULL) { - GtkAction *action = GTK_ACTION (link->data); + EUIAction *action = E_UI_ACTION (link->data); /* These actions are already wired to trigger an * EAlert::response signal when activated, which @@ -178,13 +178,10 @@ alert_bar_show_alert (EAlertBar *alert_bar) * we can add buttons directly to the action * area without knowning their response IDs. */ - widget = gtk_button_new (); + widget = e_alert_create_button_for_action (action); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action); gtk_box_pack_end (GTK_BOX (action_area), widget, FALSE, FALSE, 0); - e_alert_update_destructive_action_style (action, widget); - link = g_list_next (link); } diff --git a/src/e-util/e-alert-dialog.c b/src/e-util/e-alert-dialog.c index 6dba243fdd..4901b52686 100644 --- a/src/e-util/e-alert-dialog.c +++ b/src/e-util/e-alert-dialog.c @@ -144,12 +144,12 @@ alert_dialog_constructed (GObject *object) /* Add buttons from actions. */ link = e_alert_peek_actions (alert); if (!link && !e_alert_peek_widgets (alert)) { - GtkAction *action; + EUIAction *action; /* Make sure there is at least one action, * thus the dialog can be closed. */ - action = gtk_action_new ( - "alert-response-0", _("_Dismiss"), NULL, NULL); + action = e_ui_action_new ("alert-dialog-map", "alert-response-0", NULL); + e_ui_action_set_label (action, _("_Dismiss")); e_alert_add_action (alert, action, GTK_RESPONSE_CLOSE, FALSE); g_object_unref (action); @@ -158,7 +158,7 @@ alert_dialog_constructed (GObject *object) while (link != NULL) { GtkWidget *button; - GtkAction *action = GTK_ACTION (link->data); + EUIAction *action = E_UI_ACTION (link->data); gpointer data; /* These actions are already wired to trigger an @@ -168,14 +168,11 @@ alert_dialog_constructed (GObject *object) * area without knowing their response IDs. * (XXX Well, kind of. See below.) */ - button = gtk_button_new (); + button = e_alert_create_button_for_action (action); gtk_widget_set_can_default (button, TRUE); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (button), action); gtk_box_pack_end (GTK_BOX (action_area), button, FALSE, FALSE, 0); - e_alert_update_destructive_action_style (action, button); - /* This is set in e_alert_add_action(). */ data = g_object_get_data (G_OBJECT (action), "e-alert-response-id"); diff --git a/src/e-util/e-alert.c b/src/e-util/e-alert.c index de78938f76..ccda2b1fd2 100644 --- a/src/e-util/e-alert.c +++ b/src/e-util/e-alert.c @@ -34,8 +34,10 @@ #include -#include "e-alert.h" #include "e-alert-sink.h" +#include "e-ui-action.h" + +#include "e-alert.h" #define d(x) @@ -91,8 +93,8 @@ struct _EAlertPrivate { gint default_response; guint timeout_id; - /* It may occur to one that we could use a GtkActionGroup here, - * but we need to preserve the button order and GtkActionGroup + /* It may occur to one that we could use a EUIActionGroup here, + * but we need to preserve the button order and EUIActionGroup * uses a hash table, which does not preserve order. */ GQueue actions; @@ -373,7 +375,8 @@ e_alert_load_tables (void) static void alert_action_activate (EAlert *alert, - GtkAction *action) + GVariant *parameter, + EUIAction *action) { GObject *object; gpointer data; @@ -552,7 +555,7 @@ alert_dispose (GObject *object) } while (!g_queue_is_empty (&alert->priv->actions)) { - GtkAction *action; + EUIAction *action; action = g_queue_pop_head (&alert->priv->actions); g_signal_handlers_disconnect_by_func ( @@ -604,23 +607,21 @@ alert_constructed (GObject *object) /* Build actions out of the button definitions. */ button = definition->buttons; while (button != NULL) { - GtkAction *action; + EUIAction *action; gchar *action_name; action_name = g_strdup_printf ("alert-response-%d", ii++); if (button->stock_id != NULL) { - action = gtk_action_new ( - action_name, NULL, NULL, button->stock_id); - e_alert_add_action ( - alert, action, button->response_id, button->destructive); + action = e_ui_action_new ("alert-map", action_name, NULL); + e_ui_action_set_icon_name (action, button->stock_id); + e_alert_add_action (alert, action, button->response_id, button->destructive); g_object_unref (action); } else if (button->label != NULL) { - action = gtk_action_new ( - action_name, button->label, NULL, NULL); - e_alert_add_action ( - alert, action, button->response_id, button->destructive); + action = e_ui_action_new ("alert-map", action_name, NULL); + e_ui_action_set_label (action, button->label); + e_alert_add_action (alert, action, button->response_id, button->destructive); g_object_unref (action); } @@ -937,12 +938,12 @@ e_alert_get_icon_name (EAlert *alert) void e_alert_add_action (EAlert *alert, - GtkAction *action, + EUIAction *action, gint response_id, gboolean is_destructive) { g_return_if_fail (E_IS_ALERT (alert)); - g_return_if_fail (GTK_IS_ACTION (action)); + g_return_if_fail (E_IS_UI_ACTION (action)); g_object_set_data ( G_OBJECT (action), "e-alert-response-id", @@ -958,7 +959,7 @@ e_alert_add_action (EAlert *alert, g_queue_push_tail (&alert->priv->actions, g_object_ref (action)); } -GList * +GList * /* EUIAction * */ e_alert_peek_actions (EAlert *alert) { g_return_val_if_fail (E_IS_ALERT (alert), NULL); @@ -1063,19 +1064,48 @@ e_alert_submit_valist (EAlertSink *alert_sink, g_object_unref (alert); } -void -e_alert_update_destructive_action_style (GtkAction *for_action, - GtkWidget *button) +static void +alert_action_button_clicked_cb (GtkButton *button, + gpointer user_data) { + EUIAction *action = user_data; + + g_action_activate (G_ACTION (action), NULL); +} + +GtkWidget * +e_alert_create_button_for_action (EUIAction *for_action) +{ + GtkWidget *widget; GtkStyleContext *style_context; - g_return_if_fail (GTK_IS_ACTION (for_action)); - g_return_if_fail (GTK_IS_WIDGET (button)); + g_return_val_if_fail (E_IS_UI_ACTION (for_action), NULL); - style_context = gtk_widget_get_style_context (button); + /* action's icon-name is stock_id */ + if (e_ui_action_get_icon_name (for_action)) { + widget = gtk_button_new_from_stock (e_ui_action_get_icon_name (for_action)); + if (e_ui_action_get_label (for_action)) { + gtk_button_set_use_underline (GTK_BUTTON (widget), TRUE); + gtk_button_set_label (GTK_BUTTON (widget), e_ui_action_get_label (for_action)); + } + } else { + widget = gtk_button_new_with_mnemonic (e_ui_action_get_label (for_action)); + } + + if (e_ui_action_get_tooltip (for_action)) + gtk_widget_set_tooltip_text (widget, e_ui_action_get_tooltip (for_action)); + + gtk_widget_set_visible (widget, TRUE); + + g_signal_connect_object (widget, "clicked", + G_CALLBACK (alert_action_button_clicked_cb), for_action, 0); + + style_context = gtk_widget_get_style_context (widget); if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (for_action), "e-alert-is-destructive")) != 0) gtk_style_context_add_class (style_context, "destructive-action"); else gtk_style_context_remove_class (style_context, "destructive-action"); + + return widget; } diff --git a/src/e-util/e-alert.h b/src/e-util/e-alert.h index 6463f03cb9..46af78dcad 100644 --- a/src/e-util/e-alert.h +++ b/src/e-util/e-alert.h @@ -31,6 +31,8 @@ #include #include +#include + /* Standard GObject macros */ #define E_TYPE_ALERT \ (e_alert_get_type ()) @@ -101,10 +103,10 @@ void e_alert_set_secondary_text (EAlert *alert, const gchar *secondary_text); const gchar * e_alert_get_icon_name (EAlert *alert); void e_alert_add_action (EAlert *alert, - GtkAction *action, + EUIAction *action, gint response_id, gboolean is_destructive); -GList * e_alert_peek_actions (EAlert *alert); +GList * e_alert_peek_actions (EAlert *alert); /* EUIAction * */ void e_alert_add_widget (EAlert *alert, GtkWidget *widget); GList * e_alert_peek_widgets (EAlert *alert); @@ -121,9 +123,7 @@ void e_alert_submit (struct _EAlertSink *alert_sink, void e_alert_submit_valist (struct _EAlertSink *alert_sink, const gchar *tag, va_list va); -void e_alert_update_destructive_action_style - (GtkAction *for_action, - GtkWidget *button); +GtkWidget * e_alert_create_button_for_action(EUIAction *for_action); G_END_DECLS diff --git a/src/e-util/e-attachment-bar.c b/src/e-util/e-attachment-bar.c index 3d86bf7bcd..ccf9cf5f55 100644 --- a/src/e-util/e-attachment-bar.c +++ b/src/e-util/e-attachment-bar.c @@ -76,8 +76,7 @@ static void attachment_bar_update_status (EAttachmentBar *bar) { EAttachmentStore *store; - GtkActivatable *activatable; - GtkAction *action; + EUIAction *action; GtkLabel *label; gint num_attachments; guint64 total_size; @@ -107,13 +106,11 @@ attachment_bar_update_status (EAttachmentBar *bar) gtk_label_set_markup (label, markup); g_free (markup); - activatable = GTK_ACTIVATABLE (bar->priv->save_all_button); - action = gtk_activatable_get_related_action (activatable); - gtk_action_set_visible (action, num_attachments > 1); + action = e_attachment_view_get_action (E_ATTACHMENT_VIEW (bar), "save-all"); + e_ui_action_set_visible (action, num_attachments > 1); - activatable = GTK_ACTIVATABLE (bar->priv->save_one_button); - action = gtk_activatable_get_related_action (activatable); - gtk_action_set_visible (action, (num_attachments == 1)); + action = e_attachment_view_get_action (E_ATTACHMENT_VIEW (bar), "save-one"); + e_ui_action_set_visible (action, (num_attachments == 1)); g_free (display_size); } @@ -667,7 +664,8 @@ e_attachment_bar_init (EAttachmentBar *bar) GtkSizeGroup *size_group; GtkWidget *container; GtkWidget *widget; - GtkAction *action; + EUIAction *action; + EUIManager *ui_manager; GtkAdjustment *adjustment; gtk_widget_set_name (GTK_WIDGET (bar), "e-attachment-bar"); @@ -738,7 +736,7 @@ e_attachment_bar_init (EAttachmentBar *bar) container = GTK_WIDGET (bar); - widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE); bar->priv->content_area = g_object_ref (widget); gtk_widget_show (widget); @@ -762,25 +760,33 @@ e_attachment_bar_init (EAttachmentBar *bar) /* The "Save All" button proxies the "save-all" action from * one of the two attachment views. Doesn't matter which. */ - widget = gtk_button_new (); view = E_ATTACHMENT_VIEW (bar->priv->icon_view); action = e_attachment_view_get_action (view, "save-all"); - gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ()); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action); + + widget = gtk_button_new_with_mnemonic (e_ui_action_get_label (action)); + if (e_ui_action_get_icon_name (action)) + gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new_from_icon_name (e_ui_action_get_icon_name (action), GTK_ICON_SIZE_BUTTON)); + e_ui_action_util_assign_to_widget (action, widget); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); bar->priv->save_all_button = g_object_ref (widget); gtk_widget_show (widget); /* Same deal with the "Save" button. */ - widget = gtk_button_new (); view = E_ATTACHMENT_VIEW (bar->priv->icon_view); action = e_attachment_view_get_action (view, "save-one"); - gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ()); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action); + + widget = gtk_button_new_with_mnemonic (e_ui_action_get_label (action)); + if (e_ui_action_get_icon_name (action)) + gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new_from_icon_name (e_ui_action_get_icon_name (action), GTK_ICON_SIZE_BUTTON)); + e_ui_action_util_assign_to_widget (action, widget); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); bar->priv->save_one_button = g_object_ref (widget); gtk_widget_show (widget); + /* needed to be able to click the buttons */ + ui_manager = e_attachment_view_get_ui_manager (view); + e_ui_manager_add_action_groups_to_widget (ui_manager, container); + widget = gtk_alignment_new (1.0, 0.5, 0.0, 0.0); gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); gtk_widget_show (widget); diff --git a/src/e-util/e-attachment-handler-image.c b/src/e-util/e-attachment-handler-image.c index 4d7081e588..93f4529318 100644 --- a/src/e-util/e-attachment-handler-image.c +++ b/src/e-util/e-attachment-handler-image.c @@ -31,15 +31,6 @@ struct _EAttachmentHandlerImagePrivate { gint placeholder; }; -static const gchar *ui = -"" -" " -" " -" " -" " -" " -""; - G_DEFINE_TYPE_WITH_PRIVATE (EAttachmentHandlerImage, e_attachment_handler_image, E_TYPE_ATTACHMENT_HANDLER) static void @@ -102,9 +93,11 @@ exit: } static void -action_image_set_as_background_cb (GtkAction *action, - EAttachmentHandler *handler) +action_image_set_as_background_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; EAttachmentView *view; EAttachment *attachment; GFile *destination; @@ -132,22 +125,12 @@ action_image_set_as_background_cb (GtkAction *action, g_list_free (selected); } -static GtkActionEntry standard_entries[] = { - - { "image-set-as-background", - NULL, - N_("Set as _Background"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_image_set_as_background_cb) } -}; - static void attachment_handler_image_update_actions_cb (EAttachmentView *view, EAttachmentHandler *handler) { EAttachment *attachment; - GtkActionGroup *action_group; + EUIActionGroup *action_group; gchar *mime_type; GList *selected; gboolean visible = FALSE; @@ -173,7 +156,7 @@ attachment_handler_image_update_actions_cb (EAttachmentView *view, exit: action_group = e_attachment_view_get_action_group (view, "image"); - gtk_action_group_set_visible (action_group, visible); + e_ui_action_group_set_visible (action_group, visible); g_list_foreach (selected, (GFunc) g_object_unref, NULL); g_list_free (selected); @@ -182,11 +165,28 @@ exit: static void attachment_handler_image_constructed (GObject *object) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry standard_entries[] = { + + { "image-set-as-background", + NULL, + N_("Set as _Background"), + NULL, + NULL, + action_image_set_as_background_cb, NULL, NULL, NULL } + }; + EAttachmentHandler *handler; EAttachmentView *view; - GtkActionGroup *action_group; - GtkUIManager *ui_manager; - GError *error = NULL; + EUIManager *ui_manager; handler = E_ATTACHMENT_HANDLER (object); @@ -194,19 +194,10 @@ attachment_handler_image_constructed (GObject *object) G_OBJECT_CLASS (e_attachment_handler_image_parent_class)->constructed (object); view = e_attachment_handler_get_view (handler); - - action_group = e_attachment_view_add_action_group (view, "image"); - gtk_action_group_add_actions ( - action_group, standard_entries, - G_N_ELEMENTS (standard_entries), object); - ui_manager = e_attachment_view_get_ui_manager (view); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "image", NULL, + standard_entries, G_N_ELEMENTS (standard_entries), handler, eui); g_signal_connect ( view, "update-actions", diff --git a/src/e-util/e-attachment-paned.c b/src/e-util/e-attachment-paned.c index 0d5f05e8ec..6a842441bf 100644 --- a/src/e-util/e-attachment-paned.c +++ b/src/e-util/e-attachment-paned.c @@ -553,7 +553,8 @@ e_attachment_paned_init (EAttachmentPaned *paned) GtkSizeGroup *size_group; GtkWidget *container; GtkWidget *widget; - GtkAction *action; + EUIAction *action; + EUIManager *ui_manager; paned->priv = e_attachment_paned_get_instance_private (paned); paned->priv->model = e_attachment_store_new (); @@ -650,14 +651,20 @@ e_attachment_paned_init (EAttachmentPaned *paned) /* The "Add Attachment" button proxies the "add" action from * one of the two attachment views. Doesn't matter which. */ - widget = gtk_button_new (); view = E_ATTACHMENT_VIEW (paned->priv->icon_view); action = e_attachment_view_get_action (view, "add"); - gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new ()); - gtk_activatable_set_related_action (GTK_ACTIVATABLE (widget), action); + + widget = gtk_button_new_with_mnemonic (e_ui_action_get_label (action)); + if (e_ui_action_get_icon_name (action)) + gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new_from_icon_name (e_ui_action_get_icon_name (action), GTK_ICON_SIZE_BUTTON)); + e_ui_action_util_assign_to_widget (action, widget); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); gtk_widget_show (widget); + /* needed to be able to click the button */ + ui_manager = e_attachment_view_get_ui_manager (view); + e_ui_manager_add_action_groups_to_widget (ui_manager, container); + widget = gtk_combo_box_text_new (); gtk_size_group_add_widget (size_group, widget); gtk_combo_box_text_append_text ( diff --git a/src/e-util/e-attachment-view.c b/src/e-util/e-attachment-view.c index 5565ce6133..2c9e1f9f59 100644 --- a/src/e-util/e-attachment-view.c +++ b/src/e-util/e-attachment-view.c @@ -42,27 +42,6 @@ static GtkTargetEntry target_table[] = { { (gchar *) "_NETSCAPE_URL", 0, 0 } }; -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; - static gulong signals[LAST_SIGNAL]; G_DEFINE_INTERFACE ( @@ -86,9 +65,11 @@ call_attachment_load_handle_error (GObject *source_object, } static void -action_add_cb (GtkAction *action, - EAttachmentView *view) +action_add_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; EAttachmentStore *store; gpointer parent; @@ -163,9 +144,11 @@ attachment_popover_popup (EAttachmentView *view, } static void -action_add_uri_cb (GtkAction *action, - EAttachmentView *view) +action_add_uri_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; EAttachmentPopover *popover; EAttachment *attachment; GFileInfo *file_info; @@ -197,9 +180,11 @@ action_add_uri_cb (GtkAction *action, } static void -action_cancel_cb (GtkAction *action, - EAttachmentView *view) +action_cancel_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; EAttachment *attachment; GList *list; @@ -214,9 +199,11 @@ action_cancel_cb (GtkAction *action, } static void -action_open_with_cb (GtkAction *action, - EAttachmentView *view) +action_open_with_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; EAttachment *attachment; EAttachmentStore *store; GtkWidget *dialog; @@ -267,9 +254,12 @@ action_open_with_cb (GtkAction *action, } static void -action_open_with_app_info_cb (GtkAction *action, - EAttachmentView *view) +action_open_with_app_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; + EAttachmentViewPrivate *priv = e_attachment_view_get_private (view); GAppInfo *app_info; GtkTreePath *path; GList *list; @@ -278,18 +268,19 @@ action_open_with_app_info_cb (GtkAction *action, g_return_if_fail (g_list_length (list) == 1); path = list->data; - app_info = g_object_get_data (G_OBJECT (action), "app-info"); + app_info = g_hash_table_lookup (priv->open_with_apps_hash, GINT_TO_POINTER (g_variant_get_int32 (parameter))); e_attachment_view_open_path (view, path, app_info); - g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL); - g_list_free (list); + g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free); } static void -action_properties_cb (GtkAction *action, - EAttachmentView *view) +action_properties_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; EAttachment *attachment; EAttachmentPopover *popover; GList *list; @@ -308,9 +299,11 @@ action_properties_cb (GtkAction *action, } static void -action_reload_cb (GtkAction *action, - EAttachmentView *view) +action_reload_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; GList *list, *link; gpointer parent; @@ -342,9 +335,12 @@ action_reload_cb (GtkAction *action, } static void -action_remove_cb (GtkAction *action, - EAttachmentView *view) +action_remove_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; + e_attachment_view_remove_selected (view, FALSE); } @@ -364,9 +360,11 @@ call_attachment_save_handle_error (GObject *source_object, } static void -action_save_all_cb (GtkAction *action, - EAttachmentView *view) +action_save_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; EAttachmentStore *store; GList *list, *iter; GFile *destination; @@ -406,9 +404,11 @@ exit: } static void -action_save_as_cb (GtkAction *action, - EAttachmentView *view) +action_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentView *view = user_data; EAttachmentStore *store; GList *list, *iter; GFile *destination; @@ -444,84 +444,6 @@ exit: g_list_free (list); } -static GtkActionEntry standard_entries[] = { - - { "cancel", - "process-stop", - N_("_Cancel"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_cancel_cb) }, - - { "open-with", - NULL, - N_("Open With Other Application…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_open_with_cb) }, - - { "save-all", - "document-save-as", - N_("S_ave All"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_save_all_cb) }, - - { "save-as", - "document-save-as", - N_("Sa_ve As"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_save_as_cb) }, - - /* Alternate "save-all" label, for when - * the attachment store has one row. */ - { "save-one", - "document-save-as", - N_("Save _As"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_save_all_cb) }, -}; - -static GtkActionEntry editable_entries[] = { - - { "add", - "list-add", - N_("A_dd Attachment…"), - NULL, - N_("Attach a file"), - G_CALLBACK (action_add_cb) }, - - { "add-uri", - "emblem-web", - N_("Add _URI…"), - NULL, - N_("Attach a URI"), - G_CALLBACK (action_add_uri_cb) }, - - { "properties", - "document-properties", - N_("_Properties"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_properties_cb) }, - - { "reload", - "view-refresh", - N_("Re_load"), - NULL, - N_("Reload attachment content"), - G_CALLBACK (action_reload_cb) }, - - { "remove", - "list-remove", - N_("_Remove"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_remove_cb) } -}; - static void attachment_view_handle_uri_with_title (EAttachmentView *view, GdkDragContext *drag_context, @@ -882,15 +804,42 @@ attachment_view_text_x_moz_url (EAttachmentView *view, g_free (uri_with_title); } +static gboolean +e_attachment_view_ui_manager_create_item_cb (EUIManager *manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EAttachmentView *self = user_data; + EAttachmentViewPrivate *priv; + + g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (self), FALSE); + + if (for_kind != E_UI_ELEMENT_KIND_MENU || + g_strcmp0 (g_action_get_name (G_ACTION (action)), "EAttachmentView::open-with-app") != 0) + return FALSE; + + priv = e_attachment_view_get_private (self); + + if (priv->open_with_apps_menu) + *out_item = G_OBJECT (g_menu_item_new_section (NULL, G_MENU_MODEL (priv->open_with_apps_menu))); + else + *out_item = NULL; + + return TRUE; +} + static void attachment_view_update_actions (EAttachmentView *view) { EAttachmentViewPrivate *priv; EAttachment *attachment; - GtkActionGroup *action_group; - GtkAction *action; + EUIAction *action; GList *list, *iter; guint n_selected; + gint op_id = 0; gboolean busy = FALSE; gboolean may_reload = FALSE; gboolean is_uri = FALSE; @@ -930,32 +879,29 @@ attachment_view_update_actions (EAttachmentView *view) g_list_free_full (list, g_object_unref); action = e_attachment_view_get_action (view, "cancel"); - gtk_action_set_visible (action, busy); + e_ui_action_set_visible (action, busy); action = e_attachment_view_get_action (view, "open-with"); - gtk_action_set_visible (action, !busy && n_selected == 1 && !e_util_is_running_flatpak ()); + e_ui_action_set_visible (action, !busy && n_selected == 1 && !e_util_is_running_flatpak ()); action = e_attachment_view_get_action (view, "properties"); - gtk_action_set_visible (action, !busy && n_selected == 1); + e_ui_action_set_visible (action, !busy && n_selected == 1); action = e_attachment_view_get_action (view, "reload"); - gtk_action_set_visible (action, may_reload && !is_uri); - gtk_action_set_sensitive (action, !busy); + e_ui_action_set_visible (action, may_reload && !is_uri); + e_ui_action_set_sensitive (action, !busy); action = e_attachment_view_get_action (view, "remove"); - gtk_action_set_visible (action, !busy && n_selected > 0); + e_ui_action_set_visible (action, !busy && n_selected > 0); action = e_attachment_view_get_action (view, "save-as"); - gtk_action_set_visible (action, !busy && !is_uri && n_selected > 0); + e_ui_action_set_visible (action, !busy && !is_uri && n_selected > 0); action = e_attachment_view_get_action (view, "add-uri"); - gtk_action_set_visible (action, priv->allow_uri); + e_ui_action_set_visible (action, priv->allow_uri); - /* Clear out the "openwith" action group. */ - gtk_ui_manager_remove_ui (priv->ui_manager, priv->merge_id); - action_group = e_attachment_view_get_action_group (view, "openwith"); - e_action_group_remove_all_actions (action_group); - gtk_ui_manager_ensure_update (priv->ui_manager); + g_menu_remove_all (priv->open_with_apps_menu); + g_hash_table_remove_all (priv->open_with_apps_hash); if (!attachment || busy) { g_clear_object (&attachment); @@ -969,12 +915,11 @@ attachment_view_update_actions (EAttachmentView *view) for (iter = list; iter != NULL; iter = iter->next) { GAppInfo *app_info = iter->data; + GMenuItem *menu_item; GIcon *app_icon; const gchar *app_id; const gchar *app_name; - gchar *action_tooltip; - gchar *action_label; - gchar *action_name; + gchar *label; if (app_info) { app_id = g_app_info_get_id (app_info); @@ -993,47 +938,23 @@ attachment_view_update_actions (EAttachmentView *view) if (g_str_equal (app_id, "org.gnome.Evolution.desktop")) continue; - action_name = g_strdup_printf ("open-with-%s", app_id); + if (app_info) + label = g_strdup_printf (_("Open With “%s”"), app_name); + else + label = g_strdup (_("Open With Default Application")); - if (app_info) { - action_label = g_strdup_printf (_("Open With “%s”"), app_name); - action_tooltip = g_strdup_printf (_("Open this attachment in %s"), app_name); - } else { - action_label = g_strdup (_("Open With Default Application")); - action_tooltip = g_strdup (_("Open this attachment in default application")); - } + menu_item = g_menu_item_new (label, NULL); + g_menu_item_set_action_and_target_value (menu_item, "standard.EAttachmentView::open-with-app", g_variant_new_int32 (op_id)); + g_menu_item_set_icon (menu_item, app_icon); + g_menu_append_item (priv->open_with_apps_menu, menu_item); + g_clear_object (&menu_item); - action = gtk_action_new ( - action_name, action_label, action_tooltip, NULL); + if (app_info) + g_hash_table_insert (priv->open_with_apps_hash, GINT_TO_POINTER (op_id), g_object_ref (app_info)); - gtk_action_set_gicon (action, app_icon); + op_id++; - if (app_info) { - g_object_set_data_full ( - G_OBJECT (action), - "app-info", g_object_ref (app_info), - (GDestroyNotify) g_object_unref); - } - - g_object_set_data_full ( - G_OBJECT (action), - "attachment", g_object_ref (attachment), - (GDestroyNotify) g_object_unref); - - g_signal_connect ( - action, "activate", - G_CALLBACK (action_open_with_app_info_cb), view); - - gtk_action_group_add_action (action_group, action); - - gtk_ui_manager_add_ui ( - priv->ui_manager, priv->merge_id, - "/context/open-actions", action_name, - action_name, GTK_UI_MANAGER_AUTO, FALSE); - - g_free (action_name); - g_free (action_label); - g_free (action_tooltip); + g_free (label); if (!app_info) { list = g_list_remove (list, app_info); @@ -1139,42 +1060,131 @@ e_attachment_view_default_init (EAttachmentViewInterface *iface) void e_attachment_view_init (EAttachmentView *view) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry standard_entries[] = { + + { "cancel", + "process-stop", + N_("_Cancel"), + NULL, + NULL, + action_cancel_cb, NULL, NULL, NULL }, + + { "open-with", + NULL, + N_("Open With Other Application…"), + NULL, + NULL, + action_open_with_cb, NULL, NULL, NULL }, + + { "save-all", + "document-save-as", + N_("S_ave All"), + NULL, + NULL, + action_save_all_cb, NULL, NULL, NULL }, + + { "save-as", + "document-save-as", + N_("Sa_ve As"), + NULL, + NULL, + action_save_as_cb, NULL, NULL, NULL }, + + /* Alternate "save-all" label, for when + * the attachment store has one row. */ + { "save-one", + "document-save-as", + N_("Save _As"), + NULL, + NULL, + action_save_all_cb, NULL, NULL, NULL }, + + { "EAttachmentView::open-with-app", + NULL, + N_("Open with…"), + NULL, + NULL, + action_open_with_app_cb, "i", NULL, NULL } + }; + + static const EUIActionEntry editable_entries[] = { + + { "add", + "list-add", + N_("A_dd Attachment…"), + NULL, + N_("Attach a file"), + action_add_cb, NULL, NULL, NULL }, + + { "add-uri", + "emblem-web", + N_("Add _URI…"), + NULL, + N_("Attach a URI"), + action_add_uri_cb, NULL, NULL, NULL }, + + { "properties", + "document-properties", + N_("_Properties"), + NULL, + NULL, + action_properties_cb, NULL, NULL, NULL }, + + { "reload", + "view-refresh", + N_("Re_load"), + NULL, + N_("Reload attachment content"), + action_reload_cb, NULL, NULL, NULL }, + + { "remove", + "list-remove", + N_("_Remove"), + NULL, + NULL, + action_remove_cb, NULL, NULL, NULL } + }; + EAttachmentViewPrivate *priv; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GError *error = NULL; priv = e_attachment_view_get_private (view); - ui_manager = gtk_ui_manager_new (); - priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager); - priv->ui_manager = ui_manager; + priv->ui_manager = e_ui_manager_new (); + priv->open_with_apps_menu = g_menu_new (); + priv->open_with_apps_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); - action_group = e_attachment_view_add_action_group (view, "standard"); + e_ui_manager_add_actions_with_eui_data (priv->ui_manager, "standard", NULL, + standard_entries, G_N_ELEMENTS (standard_entries), view, eui); - gtk_action_group_add_actions ( - action_group, standard_entries, - G_N_ELEMENTS (standard_entries), view); - - action_group = e_attachment_view_add_action_group (view, "editable"); + e_ui_manager_add_actions (priv->ui_manager, "editable", NULL, + editable_entries, G_N_ELEMENTS (editable_entries), view); e_binding_bind_property ( view, "editable", - action_group, "visible", + e_ui_manager_get_action_group (priv->ui_manager, "editable"), "visible", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); - gtk_action_group_add_actions ( - action_group, editable_entries, - G_N_ELEMENTS (editable_entries), view); - - e_attachment_view_add_action_group (view, "openwith"); - - /* Because we are loading from a hard-coded string, there is - * no chance of I/O errors. Failure here implies a malformed - * UI definition. Full stop. */ - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) - g_error ("%s", error->message); attachment_view_init_drag_dest (view); @@ -1205,6 +1215,11 @@ e_attachment_view_init (EAttachmentView *view) g_signal_connect ( view, "drag-data-received", G_CALLBACK (attachment_view_text_x_moz_url), NULL); + + g_signal_connect (priv->ui_manager, "create-item", + G_CALLBACK (e_attachment_view_ui_manager_create_item_cb), view); + + e_ui_manager_set_action_groups_widget (priv->ui_manager, GTK_WIDGET (view)); } void @@ -1215,6 +1230,8 @@ e_attachment_view_dispose (EAttachmentView *view) priv = e_attachment_view_get_private (view); g_clear_pointer (&priv->target_list, gtk_target_list_unref); + g_clear_pointer (&priv->open_with_apps_hash, g_hash_table_unref); + g_clear_object (&priv->open_with_apps_menu); g_clear_object (&priv->ui_manager); } @@ -2114,91 +2131,58 @@ e_attachment_view_drag_data_received (EAttachmentView *view, gtk_drag_finish (drag_context, FALSE, FALSE, time); } -GtkAction * +EUIAction * e_attachment_view_get_action (EAttachmentView *view, const gchar *action_name) { - GtkUIManager *ui_manager; + EUIManager *ui_manager; g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); g_return_val_if_fail (action_name != NULL, NULL); ui_manager = e_attachment_view_get_ui_manager (view); - return e_lookup_action (ui_manager, action_name); + return e_ui_manager_get_action (ui_manager, action_name); } -GtkActionGroup * -e_attachment_view_add_action_group (EAttachmentView *view, - const gchar *group_name) -{ - GtkActionGroup *action_group; - GtkUIManager *ui_manager; - const gchar *domain; - - g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); - g_return_val_if_fail (group_name != NULL, NULL); - - ui_manager = e_attachment_view_get_ui_manager (view); - domain = GETTEXT_PACKAGE; - - action_group = gtk_action_group_new (group_name); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - return action_group; -} - -GtkActionGroup * +EUIActionGroup * e_attachment_view_get_action_group (EAttachmentView *view, const gchar *group_name) { - GtkUIManager *ui_manager; + EUIManager *ui_manager; g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); g_return_val_if_fail (group_name != NULL, NULL); ui_manager = e_attachment_view_get_ui_manager (view); - return e_lookup_action_group (ui_manager, group_name); -} - -static void -e_attachment_view_menu_deactivate_cb (GtkMenu *popup_menu, - gpointer user_data) -{ - g_return_if_fail (GTK_IS_MENU (popup_menu)); - - g_signal_handlers_disconnect_by_func (popup_menu, e_attachment_view_menu_deactivate_cb, user_data); - gtk_menu_detach (popup_menu); + return e_ui_manager_get_action_group (ui_manager, group_name); } GtkWidget * e_attachment_view_get_popup_menu (EAttachmentView *view) { - GtkUIManager *ui_manager; - GtkWidget *menu; + EUIManager *ui_manager; + GObject *ui_object; + GtkMenu *menu; g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); ui_manager = e_attachment_view_get_ui_manager (view); - menu = gtk_ui_manager_get_widget (ui_manager, "/context"); - g_return_val_if_fail (GTK_IS_MENU (menu), NULL); + ui_object = e_ui_manager_create_item (ui_manager, "context"); + g_return_val_if_fail (G_IS_MENU_MODEL (ui_object), NULL); - if (!gtk_menu_get_attach_widget (GTK_MENU (menu))) { - gtk_menu_attach_to_widget (GTK_MENU (menu), - GTK_WIDGET (view), - NULL); - g_signal_connect ( - menu, "deactivate", - G_CALLBACK (e_attachment_view_menu_deactivate_cb), NULL); - } + menu = GTK_MENU (gtk_menu_new_from_model (G_MENU_MODEL (ui_object))); - return menu; + g_clear_object (&ui_object); + + gtk_menu_attach_to_widget (menu, GTK_WIDGET (view), NULL); + e_util_connect_menu_detach_after_deactivate (menu); + + return GTK_WIDGET (menu); } -GtkUIManager * +EUIManager * e_attachment_view_get_ui_manager (EAttachmentView *view) { EAttachmentViewPrivate *priv; diff --git a/src/e-util/e-attachment-view.h b/src/e-util/e-attachment-view.h index a3b4ec56bc..3c7c90f5aa 100644 --- a/src/e-util/e-attachment-view.h +++ b/src/e-util/e-attachment-view.h @@ -27,6 +27,9 @@ #include #include +#include +#include +#include /* Standard GObject macros */ #define E_TYPE_ATTACHMENT_VIEW \ @@ -104,8 +107,9 @@ struct _EAttachmentViewPrivate { GdkDragAction drag_actions; /* Popup Menu Management */ - GtkUIManager *ui_manager; - guint merge_id; + EUIManager *ui_manager; + GMenu *open_with_apps_menu; + GHashTable *open_with_apps_hash; /* gint index ~> GAppInfo * */ /* Multi-DnD State */ GList *event_list; @@ -228,17 +232,14 @@ void e_attachment_view_drag_data_received guint time); /* Popup Menu Management */ -GtkAction * e_attachment_view_get_action (EAttachmentView *view, +EUIAction * e_attachment_view_get_action (EAttachmentView *view, const gchar *action_name); -GtkActionGroup *e_attachment_view_add_action_group - (EAttachmentView *view, - const gchar *group_name); -GtkActionGroup *e_attachment_view_get_action_group +EUIActionGroup *e_attachment_view_get_action_group (EAttachmentView *view, const gchar *group_name); GtkWidget * e_attachment_view_get_popup_menu (EAttachmentView *view); -GtkUIManager * e_attachment_view_get_ui_manager +EUIManager * e_attachment_view_get_ui_manager (EAttachmentView *view); void e_attachment_view_update_actions (EAttachmentView *view); diff --git a/src/e-util/e-charset-combo-box.c b/src/e-util/e-charset-combo-box.c index 2f9001ee9d..11e59c4d02 100644 --- a/src/e-util/e-charset-combo-box.c +++ b/src/e-util/e-charset-combo-box.c @@ -20,24 +20,18 @@ #include "evolution-config.h" -#include "e-charset-combo-box.h" - #include #include "e-charset.h" -#include "e-misc-utils.h" -#define DEFAULT_CHARSET "UTF-8" -#define OTHER_VALUE G_MAXINT +#include "e-charset-combo-box.h" -struct _ECharsetComboBoxPrivate { - GtkActionGroup *action_group; - GtkRadioAction *other_action; - GHashTable *charset_index; +struct _ECharsetComboBox { + GtkComboBox parent; /* Used when the user clicks Cancel in the character set * dialog. Reverts to the previous combo box setting. */ - gint previous_index; + gchar *previous_id; /* When setting the character set programmatically, this * prevents the custom character set dialog from running. */ @@ -49,7 +43,7 @@ enum { PROP_CHARSET }; -G_DEFINE_TYPE_WITH_PRIVATE (ECharsetComboBox, e_charset_combo_box, E_TYPE_ACTION_COMBO_BOX) +G_DEFINE_TYPE (ECharsetComboBox, e_charset_combo_box, GTK_TYPE_COMBO_BOX) static void charset_combo_box_entry_changed_cb (GtkEntry *entry, @@ -70,7 +64,6 @@ charset_combo_box_run_dialog (ECharsetComboBox *combo_box) GtkEntry *entry; GtkWidget *container; GtkWidget *widget; - GObject *object; gpointer parent; const gchar *charset; @@ -83,8 +76,7 @@ charset_combo_box_run_dialog (ECharsetComboBox *combo_box) parent = gtk_widget_get_toplevel (GTK_WIDGET (combo_box)); parent = gtk_widget_is_toplevel (parent) ? parent : NULL; - object = G_OBJECT (combo_box->priv->other_action); - charset = g_object_get_data (object, "charset"); + charset = combo_box->previous_id; widget = gtk_dialog_new_with_buttons ( _("Character Encoding"), parent, @@ -135,43 +127,64 @@ charset_combo_box_run_dialog (ECharsetComboBox *combo_box) * This will initialize the "OK" button to the proper state. */ gtk_entry_set_text (entry, charset); - if (gtk_dialog_run (dialog) != GTK_RESPONSE_OK) { - gint active; + if (gtk_dialog_run (dialog) == GTK_RESPONSE_OK) { + charset = gtk_entry_get_text (entry); + g_return_if_fail (charset != NULL && *charset != '\0'); + /* for the cases where the user confirmed the choice without changing it, + it will force to set the correct id (from Other...) on the combo box */ + g_clear_pointer (&combo_box->previous_id, g_free); + + e_charset_combo_box_set_charset (combo_box, charset); + } else { /* Revert to the previously selected character set. */ - combo_box->priv->block_dialog = TRUE; - active = combo_box->priv->previous_index; - gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), active); - combo_box->priv->block_dialog = FALSE; - - goto exit; + combo_box->block_dialog = TRUE; + gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), combo_box->previous_id); + combo_box->block_dialog = FALSE; } - charset = gtk_entry_get_text (entry); - g_return_if_fail (charset != NULL && *charset != '\0'); - - g_object_set_data_full ( - object, "charset", g_strdup (charset), - (GDestroyNotify) g_free); - -exit: gtk_widget_destroy (GTK_WIDGET (dialog)); } static void -charset_combo_box_notify_charset_cb (ECharsetComboBox *combo_box) +charset_combo_box_changed (GtkComboBox *combo_box) { - GtkToggleAction *action; + ECharsetComboBox *self = E_CHARSET_COMBO_BOX (combo_box); + const gchar *charset; - action = GTK_TOGGLE_ACTION (combo_box->priv->other_action); - if (!gtk_toggle_action_get_active (action)) + /* Chain up to parent's changed() method. */ + if (GTK_COMBO_BOX_CLASS (e_charset_combo_box_parent_class)->changed) + GTK_COMBO_BOX_CLASS (e_charset_combo_box_parent_class)->changed (combo_box); + + if (self->block_dialog) return; - if (combo_box->priv->block_dialog) - return; + charset = e_charset_combo_box_get_charset (self); - /* "Other" action was selected by user. */ - charset_combo_box_run_dialog (combo_box); + /* the "Other..." value is an empty string */ + if (charset && !*charset) { + charset_combo_box_run_dialog (self); + } else { + g_clear_pointer (&self->previous_id, g_free); + self->previous_id = g_strdup (charset); + + g_object_notify (G_OBJECT (self), "charset"); + } +} + +static gboolean +charset_combo_box_is_row_separator (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + gchar *charset = NULL; + gboolean separator; + + gtk_tree_model_get (model, iter, E_CHARSET_COLUMN_VALUE, &charset, -1); + separator = (charset == NULL); + g_free (charset); + + return separator; } static void @@ -213,63 +226,12 @@ charset_combo_box_dispose (GObject *object) { ECharsetComboBox *self = E_CHARSET_COMBO_BOX (object); - g_clear_object (&self->priv->action_group); - g_clear_object (&self->priv->other_action); - - g_hash_table_remove_all (self->priv->charset_index); + g_clear_pointer (&self->previous_id, g_free); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_charset_combo_box_parent_class)->dispose (object); } -static void -charset_combo_box_finalize (GObject *object) -{ - ECharsetComboBox *self = E_CHARSET_COMBO_BOX (object); - - g_hash_table_destroy (self->priv->charset_index); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_charset_combo_box_parent_class)->finalize (object); -} - -static void -charset_combo_box_constructed (GObject *object) -{ - ECharsetComboBox *self = E_CHARSET_COMBO_BOX (object); - GtkRadioAction *radio_action; - GSList *group; - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_charset_combo_box_parent_class)->constructed (object); - - radio_action = self->priv->other_action; - group = gtk_radio_action_get_group (radio_action); - - e_action_combo_box_set_action ( - E_ACTION_COMBO_BOX (object), radio_action); - - e_action_combo_box_add_separator_after ( - E_ACTION_COMBO_BOX (object), g_slist_length (group)); - - e_signal_connect_notify ( - object, "notify::charset", - G_CALLBACK (charset_combo_box_notify_charset_cb), NULL); -} - -static void -charset_combo_box_changed (GtkComboBox *combo_box) -{ - ECharsetComboBox *self = E_CHARSET_COMBO_BOX (combo_box); - - /* Chain up to parent's changed() method. */ - GTK_COMBO_BOX_CLASS (e_charset_combo_box_parent_class)->changed (combo_box); - - /* Notify -before- updating previous index. */ - g_object_notify (G_OBJECT (combo_box), "charset"); - self->priv->previous_index = gtk_combo_box_get_active (combo_box); -} - static void e_charset_combo_box_class_init (ECharsetComboBoxClass *class) { @@ -280,8 +242,6 @@ e_charset_combo_box_class_init (ECharsetComboBoxClass *class) object_class->set_property = charset_combo_box_set_property; object_class->get_property = charset_combo_box_get_property; object_class->dispose = charset_combo_box_dispose; - object_class->finalize = charset_combo_box_finalize; - object_class->constructed = charset_combo_box_constructed; combo_box_class = GTK_COMBO_BOX_CLASS (class); combo_box_class->changed = charset_combo_box_changed; @@ -293,56 +253,40 @@ e_charset_combo_box_class_init (ECharsetComboBoxClass *class) "charset", "Charset", "The selected character set", - "UTF-8", - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT)); + "", + G_PARAM_READWRITE)); } static void -e_charset_combo_box_init (ECharsetComboBox *combo_box) +e_charset_combo_box_init (ECharsetComboBox *self) { - GtkActionGroup *action_group; - GtkRadioAction *radio_action; - GHashTable *charset_index; - GSList *group, *iter; + GtkComboBox *combo_box = GTK_COMBO_BOX (self); + GtkCellRenderer *renderer; + GtkListStore *list_store; + GtkTreeIter iter; - action_group = gtk_action_group_new ("charset-combo-box-internal"); + list_store = e_charset_create_list_store (); - charset_index = g_hash_table_new_full ( - g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); + /* separator, both label and value are NULL */ + gtk_list_store_append (list_store, &iter); - combo_box->priv = e_charset_combo_box_get_instance_private (combo_box); - combo_box->priv->action_group = action_group; - combo_box->priv->charset_index = charset_index; + /* other option */ + gtk_list_store_append (list_store, &iter); + gtk_list_store_set (list_store, &iter, + E_CHARSET_COLUMN_LABEL, _("Other…"), + E_CHARSET_COLUMN_VALUE, "", + -1); - group = e_charset_add_radio_actions ( - action_group, "charset-", NULL, NULL, NULL); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), renderer, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self), renderer, "text", E_CHARSET_COLUMN_LABEL); - /* Populate the character set index. */ - for (iter = group; iter != NULL; iter = iter->next) { - GObject *object = iter->data; - const gchar *charset; + gtk_combo_box_set_row_separator_func (combo_box, charset_combo_box_is_row_separator, NULL, NULL); - charset = g_object_get_data (object, "charset"); - g_return_if_fail (charset != NULL); + gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (list_store)); + gtk_combo_box_set_id_column (combo_box, E_CHARSET_COLUMN_VALUE); - g_hash_table_insert ( - charset_index, g_strdup (charset), - g_object_ref (object)); - } - - /* Note the "other" action is not included in the index. */ - - radio_action = gtk_radio_action_new ( - "charset-other", _("Other…"), NULL, NULL, OTHER_VALUE); - - g_object_set_data (G_OBJECT (radio_action), "charset", (gpointer) ""); - - gtk_radio_action_set_group (radio_action, group); - - combo_box->priv->other_action = radio_action; + g_object_unref (list_store); } GtkWidget * @@ -354,40 +298,53 @@ e_charset_combo_box_new (void) const gchar * e_charset_combo_box_get_charset (ECharsetComboBox *combo_box) { - GtkRadioAction *radio_action; - g_return_val_if_fail (E_IS_CHARSET_COMBO_BOX (combo_box), NULL); - radio_action = combo_box->priv->other_action; - radio_action = e_radio_action_get_current_action (radio_action); - - return g_object_get_data (G_OBJECT (radio_action), "charset"); + return gtk_combo_box_get_active_id (GTK_COMBO_BOX (combo_box)); } void e_charset_combo_box_set_charset (ECharsetComboBox *combo_box, const gchar *charset) { - GHashTable *charset_index; - GtkRadioAction *radio_action; - g_return_if_fail (E_IS_CHARSET_COMBO_BOX (combo_box)); if (charset == NULL || *charset == '\0') charset = "UTF-8"; - charset_index = combo_box->priv->charset_index; - radio_action = g_hash_table_lookup (charset_index, charset); + if (g_strcmp0 (charset, combo_box->previous_id) == 0) + return; - if (radio_action == NULL) { - radio_action = combo_box->priv->other_action; - g_object_set_data_full ( - G_OBJECT (radio_action), - "charset", g_strdup (charset), - (GDestroyNotify) g_free); + combo_box->block_dialog = TRUE; + + g_clear_pointer (&combo_box->previous_id, g_free); + combo_box->previous_id = g_strdup (charset); + + if (!gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), charset)) { + GtkListStore *list_store; + GtkTreeIter iter; + gchar *escaped_name; + gchar **str_array; + + /* Escape underlines in the character set name so + * they're not treated as GtkLabel mnemonics. */ + str_array = g_strsplit (charset, "_", -1); + escaped_name = g_strjoinv ("__", str_array); + g_strfreev (str_array); + + list_store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box))); + gtk_list_store_prepend (list_store, &iter); + gtk_list_store_set (list_store, &iter, + E_CHARSET_COLUMN_LABEL, escaped_name, + E_CHARSET_COLUMN_VALUE, charset, + -1); + + g_free (escaped_name); + + gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), charset); } - combo_box->priv->block_dialog = TRUE; - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (radio_action), TRUE); - combo_box->priv->block_dialog = FALSE; + g_object_notify (G_OBJECT (combo_box), "charset"); + + combo_box->block_dialog = FALSE; } diff --git a/src/e-util/e-charset-combo-box.h b/src/e-util/e-charset-combo-box.h index 52076d34c4..65ddb73e66 100644 --- a/src/e-util/e-charset-combo-box.h +++ b/src/e-util/e-charset-combo-box.h @@ -25,43 +25,13 @@ #ifndef E_CHARSET_COMBO_BOX_H #define E_CHARSET_COMBO_BOX_H -#include - -/* Standard GObject macros */ -#define E_TYPE_CHARSET_COMBO_BOX \ - (e_charset_combo_box_get_type ()) -#define E_CHARSET_COMBO_BOX(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_CHARSET_COMBO_BOX, ECharsetComboBox)) -#define E_CHARSET_COMBO_BOX_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_CHARSET_COMBO_BOX, ECharsetComboBoxClass)) -#define E_IS_CHARSET_COMBO_BOX(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_CHARSET_COMBO_BOX)) -#define E_IS_CHARSET_COMBO_BOX_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_CHARSET_COMBO_BOX)) -#define E_CHARSET_COMBO_BOX_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_CHARSET_COMBO_BOX, ECharsetComboBoxClass)) +#include G_BEGIN_DECLS -typedef struct _ECharsetComboBox ECharsetComboBox; -typedef struct _ECharsetComboBoxClass ECharsetComboBoxClass; -typedef struct _ECharsetComboBoxPrivate ECharsetComboBoxPrivate; +#define E_TYPE_CHARSET_COMBO_BOX (e_charset_combo_box_get_type ()) +G_DECLARE_FINAL_TYPE (ECharsetComboBox, e_charset_combo_box, E, CHARSET_COMBO_BOX, GtkComboBox) -struct _ECharsetComboBox { - EActionComboBox parent; - ECharsetComboBoxPrivate *priv; -}; - -struct _ECharsetComboBoxClass { - EActionComboBoxClass parent_class; -}; - -GType e_charset_combo_box_get_type (void) G_GNUC_CONST; GtkWidget * e_charset_combo_box_new (void); const gchar * e_charset_combo_box_get_charset (ECharsetComboBox *combo_box); void e_charset_combo_box_set_charset (ECharsetComboBox *combo_box, diff --git a/src/e-util/e-charset.c b/src/e-util/e-charset.c index 9e51f69735..1e4d448837 100644 --- a/src/e-util/e-charset.c +++ b/src/e-util/e-charset.c @@ -112,155 +112,36 @@ static ECharset charsets[] = { { "ISO-8859-15", E_CHARSET_WESTERN_EUROPEAN_NEW, NULL }, }; -/** - * e_charset_add_radio_actions: - * @action_group: a #GtkActionGroup - * @action_prefix: a prefix for action names, or %NULL - * @default_charset: the default character set, or %NULL to use the - * locale character set - * @callback: a callback function for actions in the group, or %NULL - * @user_data: user data to be passed to @callback, or %NULL - * - * Adds a set of #GtkRadioActions for available character sets to - * @action_group. The @default_charset (or locale character set if - * @default_charset is %NULL) will be added first, and selected by - * default (except that ISO-8859-1 will always be used instead of - * US-ASCII). Any other character sets of the same language class as - * the default will be added next, followed by the remaining character - * sets. - * - * Returns: the radio action group - **/ -GSList * -e_charset_add_radio_actions (GtkActionGroup *action_group, - const gchar *action_prefix, - const gchar *default_charset, - GCallback callback, - gpointer user_data) +static gchar * +e_charset_labelize (const ECharset *charset) { - GtkRadioAction *action = NULL; - GSList *group = NULL; - const gchar *locale_charset; - gint def, ii; + gchar *escaped_name; + gchar *charset_label; + gchar **str_array; - g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL); + /* Escape underlines in the character set name so + * they're not treated as GtkLabel mnemonics. */ + str_array = g_strsplit (charset->name, "_", -1); + escaped_name = g_strjoinv ("__", str_array); + g_strfreev (str_array); - if (action_prefix == NULL) - action_prefix = ""; + if (charset->subclass != NULL) + charset_label = g_strdup_printf ( + "%s, %s (%s)", + gettext (classnames[charset->class]), + gettext (charset->subclass), + escaped_name); + else if (charsets->class != E_CHARSET_UNKNOWN) + charset_label = g_strdup_printf ( + "%s (%s)", + gettext (classnames[charset->class]), + escaped_name); + else + charset_label = g_steal_pointer (&escaped_name); - g_get_charset (&locale_charset); - if (!g_ascii_strcasecmp (locale_charset, "US-ASCII")) - locale_charset = "ISO-8859-1"; + g_free (escaped_name); - if (default_charset == NULL) - default_charset = locale_charset; - for (def = 0; def < G_N_ELEMENTS (charsets); def++) - if (!g_ascii_strcasecmp (charsets[def].name, default_charset)) - break; - - for (ii = 0; ii < G_N_ELEMENTS (charsets); ii++) { - const gchar *charset_name; - gchar *action_name; - gchar *escaped_name; - gchar *charset_label; - gchar **str_array; - - charset_name = charsets[ii].name; - action_name = g_strconcat (action_prefix, charset_name, NULL); - - /* Escape underlines in the character set name so - * they're not treated as GtkLabel mnemonics. */ - str_array = g_strsplit (charset_name, "_", -1); - escaped_name = g_strjoinv ("__", str_array); - g_strfreev (str_array); - - if (charsets[ii].subclass != NULL) - charset_label = g_strdup_printf ( - "%s, %s (%s)", - gettext (classnames[charsets[ii].class]), - gettext (charsets[ii].subclass), - escaped_name); - else if (charsets[ii].class != E_CHARSET_UNKNOWN) - charset_label = g_strdup_printf ( - "%s (%s)", - gettext (classnames[charsets[ii].class]), - escaped_name); - else - charset_label = g_strdup (escaped_name); - - /* XXX Add a tooltip! */ - action = gtk_radio_action_new ( - action_name, charset_label, NULL, NULL, ii); - - /* Character set name is static so no need to free it. */ - g_object_set_data ( - G_OBJECT (action), "charset", - (gpointer) charset_name); - - gtk_radio_action_set_group (action, group); - group = gtk_radio_action_get_group (action); - - if (callback != NULL) - g_signal_connect ( - action, "changed", callback, user_data); - - gtk_action_group_add_action ( - action_group, GTK_ACTION (action)); - - g_object_unref (action); - - g_free (action_name); - g_free (escaped_name); - g_free (charset_label); - } - - if (def == G_N_ELEMENTS (charsets)) { - const gchar *charset_name; - gchar *action_name; - gchar *charset_label; - gchar **str_array; - - charset_name = default_charset; - action_name = g_strconcat (action_prefix, charset_name, NULL); - - /* Escape underlines in the character set name so - * they're not treated as GtkLabel mnemonics. */ - str_array = g_strsplit (charset_name, "_", -1); - charset_label = g_strjoinv ("__", str_array); - g_strfreev (str_array); - - /* XXX Add a tooltip! */ - action = gtk_radio_action_new ( - action_name, charset_label, NULL, NULL, def); - - /* Character set name may NOT be static, - * so we do need to duplicate the string. */ - g_object_set_data_full ( - G_OBJECT (action), "charset", - g_strdup (charset_name), - (GDestroyNotify) g_free); - - gtk_radio_action_set_group (action, group); - group = gtk_radio_action_get_group (action); - - if (callback != NULL) - g_signal_connect ( - action, "changed", callback, user_data); - - gtk_action_group_add_action ( - action_group, GTK_ACTION (action)); - - g_object_unref (action); - - g_free (action_name); - g_free (charset_label); - } - - /* Any of the actions in the action group will do. */ - if (action != NULL) - gtk_radio_action_set_current_value (action, def); - - return group; + return charset_label; } /** @@ -274,7 +155,7 @@ e_charset_add_radio_actions (GtkActionGroup *action_group, * * This does not add a "Default" option. * - * Since: 3.54 + * Since: 3.56 **/ void e_charset_add_to_g_menu (GMenu *menu, @@ -291,31 +172,10 @@ e_charset_add_to_g_menu (GMenu *menu, for (ii = 0; ii < G_N_ELEMENTS (charsets); ii++) { GMenuItem *menu_item; const gchar *charset_name; - gchar *escaped_name; gchar *charset_label; - gchar **str_array; charset_name = charsets[ii].name; - - /* Escape underlines in the character set name so - * they're not treated as GtkLabel mnemonics. */ - str_array = g_strsplit (charset_name, "_", -1); - escaped_name = g_strjoinv ("__", str_array); - g_strfreev (str_array); - - if (charsets[ii].subclass != NULL) - charset_label = g_strdup_printf ( - "%s, %s (%s)", - gettext (classnames[charsets[ii].class]), - gettext (charsets[ii].subclass), - escaped_name); - else if (charsets[ii].class != E_CHARSET_UNKNOWN) - charset_label = g_strdup_printf ( - "%s (%s)", - gettext (classnames[charsets[ii].class]), - escaped_name); - else - charset_label = g_strdup (escaped_name); + charset_label = e_charset_labelize (&(charsets[ii])); menu_item = g_menu_item_new (charset_label, NULL); g_menu_item_set_action_and_target (menu_item, action_name, "s", charset_name); @@ -323,7 +183,6 @@ e_charset_add_to_g_menu (GMenu *menu, g_object_unref (menu_item); - g_free (escaped_name); g_free (charset_label); } @@ -331,3 +190,42 @@ e_charset_add_to_g_menu (GMenu *menu, g_clear_object (§ion); } + +/** + * e_charset_create_list_store: + * + * Creates a new #GtkListStore containing two columns, E_CHARSET_COLUMN_LABEL with the label + * of the charset, to be shown tin the GUI, and E_CHARSET_COLUMN_VALUE with the actual + * charset value. + * + * Returns: (transfer full): newly created #GtkListStore + * + * Since: 3.56 + **/ +GtkListStore * +e_charset_create_list_store (void) +{ + GtkListStore *list_store; + guint ii; + + list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + + for (ii = 0; ii < G_N_ELEMENTS (charsets); ii++) { + GtkTreeIter iter; + const gchar *charset_name; + gchar *charset_label; + + charset_name = charsets[ii].name; + charset_label = e_charset_labelize (&(charsets[ii])); + + gtk_list_store_append (list_store, &iter); + gtk_list_store_set (list_store, &iter, + E_CHARSET_COLUMN_LABEL, charset_label, + E_CHARSET_COLUMN_VALUE, charset_name, + -1); + + g_free (charset_label); + } + + return list_store; +} diff --git a/src/e-util/e-charset.h b/src/e-util/e-charset.h index 1d2ca50368..a3c702e6eb 100644 --- a/src/e-util/e-charset.h +++ b/src/e-util/e-charset.h @@ -28,15 +28,14 @@ G_BEGIN_DECLS -GSList * e_charset_add_radio_actions (GtkActionGroup *action_group, - const gchar *action_prefix, - const gchar *default_charset, - GCallback callback, - gpointer user_data); - void e_charset_add_to_g_menu (GMenu *menu, const gchar *action_name); +#define E_CHARSET_COLUMN_LABEL 0 +#define E_CHARSET_COLUMN_VALUE 1 + +GtkListStore * e_charset_create_list_store (void); + G_END_DECLS #endif /* E_CHARSET_H */ diff --git a/src/e-util/e-content-editor.c b/src/e-util/e-content-editor.c index 18119143a0..1acebe5040 100644 --- a/src/e-util/e-content-editor.c +++ b/src/e-util/e-content-editor.c @@ -1972,7 +1972,7 @@ e_content_editor_insert_image (EContentEditor *editor, void e_content_editor_insert_emoticon (EContentEditor *editor, - EEmoticon *emoticon) + const EEmoticon *emoticon) { EContentEditorInterface *iface; diff --git a/src/e-util/e-content-editor.h b/src/e-util/e-content-editor.h index 6a34193406..b729846785 100644 --- a/src/e-util/e-content-editor.h +++ b/src/e-util/e-content-editor.h @@ -83,7 +83,7 @@ struct _EContentEditorInterface { const gchar *uri); void (*insert_emoticon) (EContentEditor *editor, - EEmoticon *emoticon); + const EEmoticon *emoticon); void (*move_caret_on_coordinates) (EContentEditor *editor, gint x, @@ -586,7 +586,7 @@ void e_content_editor_insert_image (EContentEditor *editor, const gchar *uri); void e_content_editor_insert_emoticon (EContentEditor *editor, - EEmoticon *emoticon); + const EEmoticon *emoticon); void e_content_editor_move_caret_on_coordinates (EContentEditor *editor, diff --git a/src/e-util/e-emoticon-action.c b/src/e-util/e-emoticon-action.c deleted file mode 100644 index 51ff5fb538..0000000000 --- a/src/e-util/e-emoticon-action.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * e-emoticon-action.c - * - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2012 Dan Vrátil - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU Lesser General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "e-emoticon-action.h" - -#include "e-emoticon-chooser.h" -#include "e-emoticon-chooser-menu.h" -#include "e-emoticon-tool-button.h" - -struct _EEmoticonActionPrivate { - GList *choosers; - EEmoticonChooser *current_chooser; -}; - -enum { - PROP_0, - PROP_CURRENT_FACE -}; - -/* Forward Declarations */ -static void e_emoticon_action_interface_init - (EEmoticonChooserInterface *interface); - -G_DEFINE_TYPE_WITH_CODE (EEmoticonAction, e_emoticon_action, GTK_TYPE_ACTION, - G_ADD_PRIVATE (EEmoticonAction) - G_IMPLEMENT_INTERFACE (E_TYPE_EMOTICON_CHOOSER, e_emoticon_action_interface_init)) - -static void -emoticon_action_proxy_item_activated_cb (EEmoticonAction *action, - EEmoticonChooser *chooser) -{ - action->priv->current_chooser = chooser; - - g_signal_emit_by_name (action, "item-activated"); -} - -static void -emoticon_action_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CURRENT_FACE: - e_emoticon_chooser_set_current_emoticon ( - E_EMOTICON_CHOOSER (object), - g_value_get_boxed (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -emoticon_action_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CURRENT_FACE: - g_value_set_boxed ( - value, e_emoticon_chooser_get_current_emoticon ( - E_EMOTICON_CHOOSER (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -emoticon_action_finalize (GObject *object) -{ - EEmoticonAction *self = E_EMOTICON_ACTION (object); - - g_list_free (self->priv->choosers); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (e_emoticon_action_parent_class)->finalize (object); -} - -static void -emoticon_action_activate (GtkAction *action) -{ - EEmoticonAction *self = E_EMOTICON_ACTION (action); - - self->priv->current_chooser = NULL; -} - -static GtkWidget * -emoticon_action_create_menu_item (GtkAction *action) -{ - GtkWidget *item; - GtkWidget *menu; - - item = gtk_image_menu_item_new (); - menu = gtk_action_create_menu (action); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu); - gtk_widget_show (menu); - - return item; -} - -static GtkWidget * -emoticon_action_create_tool_item (GtkAction *action) -{ - return GTK_WIDGET (e_emoticon_tool_button_new ()); -} - -static void -emoticon_action_connect_proxy (GtkAction *action, - GtkWidget *proxy) -{ - EEmoticonAction *self = E_EMOTICON_ACTION (action); - - if (!E_IS_EMOTICON_CHOOSER (proxy)) - goto chainup; - - if (g_list_find (self->priv->choosers, proxy) != NULL) - goto chainup; - - g_signal_connect_swapped ( - proxy, "item-activated", - G_CALLBACK (emoticon_action_proxy_item_activated_cb), action); - -chainup: - /* Chain up to parent's connect_proxy() method. */ - GTK_ACTION_CLASS (e_emoticon_action_parent_class)->connect_proxy (action, proxy); -} - -static void -emoticon_action_disconnect_proxy (GtkAction *action, - GtkWidget *proxy) -{ - EEmoticonAction *self = E_EMOTICON_ACTION (action); - - self->priv->choosers = g_list_remove (self->priv->choosers, proxy); - - /* Chain up to parent's disconnect_proxy() method. */ - GTK_ACTION_CLASS (e_emoticon_action_parent_class)->disconnect_proxy (action, proxy); -} - -static GtkWidget * -emoticon_action_create_menu (GtkAction *action) -{ - EEmoticonAction *self = E_EMOTICON_ACTION (action); - GtkWidget *widget; - - widget = e_emoticon_chooser_menu_new (); - - g_signal_connect_swapped ( - widget, "item-activated", - G_CALLBACK (emoticon_action_proxy_item_activated_cb), action); - - self->priv->choosers = g_list_prepend (self->priv->choosers, widget); - - return widget; -} - -static EEmoticon * -emoticon_action_get_current_emoticon (EEmoticonChooser *chooser) -{ - EEmoticonAction *self = E_EMOTICON_ACTION (chooser); - EEmoticon *emoticon = NULL; - - if (self->priv->current_chooser) - emoticon = e_emoticon_chooser_get_current_emoticon (self->priv->current_chooser); - - return emoticon; -} - -static void -emoticon_action_set_current_emoticon (EEmoticonChooser *chooser, - EEmoticon *emoticon) -{ - EEmoticonAction *self = E_EMOTICON_ACTION (chooser); - GList *iter; - - for (iter = self->priv->choosers; iter != NULL; iter = iter->next) { - EEmoticonChooser *proxy_chooser = iter->data; - - e_emoticon_chooser_set_current_emoticon (proxy_chooser, emoticon); - } -} - -static void -e_emoticon_action_class_init (EEmoticonActionClass *class) -{ - GObjectClass *object_class; - GtkActionClass *action_class; - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = emoticon_action_set_property; - object_class->get_property = emoticon_action_get_property; - object_class->finalize = emoticon_action_finalize; - - action_class = GTK_ACTION_CLASS (class); - action_class->activate = emoticon_action_activate; - action_class->create_menu_item = emoticon_action_create_menu_item; - action_class->create_tool_item = emoticon_action_create_tool_item; - action_class->connect_proxy = emoticon_action_connect_proxy; - action_class->disconnect_proxy = emoticon_action_disconnect_proxy; - action_class->create_menu = emoticon_action_create_menu; - - g_object_class_override_property ( - object_class, PROP_CURRENT_FACE, "current-emoticon"); -} - -static void -e_emoticon_action_interface_init (EEmoticonChooserInterface *interface) -{ - interface->get_current_emoticon = emoticon_action_get_current_emoticon; - interface->set_current_emoticon = emoticon_action_set_current_emoticon; -} - -static void -e_emoticon_action_init (EEmoticonAction *action) -{ - action->priv = e_emoticon_action_get_instance_private (action); -} - -GtkAction * -e_emoticon_action_new (const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id) -{ - g_return_val_if_fail (name != NULL, NULL); - - return g_object_new ( - E_TYPE_EMOTICON_ACTION, "name", name, "label", label, - "tooltip", tooltip, "stock-id", stock_id, NULL); -} diff --git a/src/e-util/e-emoticon-action.h b/src/e-util/e-emoticon-action.h deleted file mode 100644 index 0e450e8750..0000000000 --- a/src/e-util/e-emoticon-action.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * e-emoticon-action.h - * - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2012 Dan Vrátil - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU Lesser General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) -#error "Only should be included directly." -#endif - -#ifndef E_EMOTICON_ACTION_H -#define E_EMOTICON_ACTION_H - -#include - -/* Standard GObject macros */ -#define E_TYPE_EMOTICON_ACTION \ - (e_emoticon_action_get_type ()) -#define E_EMOTICON_ACTION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_EMOTICON_ACTION, EEmoticonAction)) -#define E_EMOTICON_ACTION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_EMOTICON_ACTION, EEmoticonActionClass)) -#define E_IS_EMOTICON_ACTION(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_EMOTICON_ACTION)) -#define E_IS_EMOTICON_ACTION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_EMOTICON_ACTION)) -#define E_EMOTICON_ACTION_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_EMOTICON_ACTION, EEmoticonActionClass)) - -G_BEGIN_DECLS - -typedef struct _EEmoticonAction EEmoticonAction; -typedef struct _EEmoticonActionClass EEmoticonActionClass; -typedef struct _EEmoticonActionPrivate EEmoticonActionPrivate; - -struct _EEmoticonAction { - GtkAction parent; - EEmoticonActionPrivate *priv; -}; - -struct _EEmoticonActionClass { - GtkActionClass parent_class; -}; - -GType e_emoticon_action_get_type (void) G_GNUC_CONST; -GtkAction * e_emoticon_action_new (const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id); - -G_END_DECLS - -#endif /* E_EMOTICON_ACTION_H */ diff --git a/src/e-util/e-emoticon-tool-button.c b/src/e-util/e-emoticon-tool-button.c deleted file mode 100644 index 3221320377..0000000000 --- a/src/e-util/e-emoticon-tool-button.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * e-emoticon-tool-button.c - * - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2012 Dan Vrátil - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU Lesser General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "evolution-config.h" - -#include "e-emoticon-tool-button.h" - -/* XXX The "button" aspects of this widget are based heavily on the - * GtkComboBox tree-view implementation. Consider splitting it - * into a reusable "button-with-an-empty-window" widget. */ - -#include -#include - -#include "e-emoticon-chooser.h" - -/* XXX Should calculate this dynamically. */ -#define NUM_ROWS 7 -#define NUM_COLS 3 - -enum { - PROP_0, - PROP_CURRENT_EMOTICON, - PROP_POPUP_SHOWN -}; - -enum { - POPUP, - POPDOWN, - LAST_SIGNAL -}; - -struct _EEmoticonToolButtonPrivate { - GtkWidget *active_button; /* not referenced */ - GtkWidget *table; - GtkWidget *popover; - - guint popup_shown : 1; - guint popup_in_progress : 1; -}; - -static guint signals[LAST_SIGNAL]; - -/* Forward Declarations */ -static void e_emoticon_tool_button_interface_init - (EEmoticonChooserInterface *interface); - -G_DEFINE_TYPE_WITH_CODE (EEmoticonToolButton, e_emoticon_tool_button, GTK_TYPE_TOGGLE_TOOL_BUTTON, - G_ADD_PRIVATE (EEmoticonToolButton) - G_IMPLEMENT_INTERFACE (E_TYPE_EMOTICON_CHOOSER, e_emoticon_tool_button_interface_init)) - -/* XXX Copied from _gtk_toolbar_elide_underscores() */ -static gchar * -emoticon_tool_button_elide_underscores (const gchar *original) -{ - gchar *q, *result; - const gchar *p, *end; - gsize len; - gboolean last_underscore; - - if (!original) - return NULL; - - len = strlen (original); - q = result = g_malloc (len + 1); - last_underscore = FALSE; - - end = original + len; - for (p = original; p < end; p++) { - if (!last_underscore && *p == '_') - last_underscore = TRUE; - else { - last_underscore = FALSE; - if (original + 2 <= p && p + 1 <= end && - p[-2] == '(' && p[-1] == '_' && - p[0] != '_' && p[1] == ')') { - q--; - *q = '\0'; - p++; - } else - *q++ = *p; - } - } - - if (last_underscore) - *q++ = '_'; - - *q = '\0'; - - return result; -} - -static void -emoticon_tool_button_emoticon_clicked_cb (EEmoticonToolButton *button, - GtkWidget *emoticon_button) -{ - button->priv->active_button = emoticon_button; - e_emoticon_tool_button_popdown (button); -} - -static gboolean -emoticon_tool_button_emoticon_release_event_cb (EEmoticonToolButton *button, - GdkEventButton *event, - GtkButton *emoticon_button) -{ - GtkStateFlags state; - - state = gtk_widget_get_state_flags (GTK_WIDGET (button)); - - if (state != GTK_STATE_FLAG_NORMAL) - gtk_button_clicked (emoticon_button); - - return FALSE; -} - -static gboolean -emoticon_tool_button_button_release_event_cb (EEmoticonToolButton *button, - GdkEventButton *event) -{ - GtkToggleToolButton *tool_button; - GtkWidget *event_widget; - gboolean popup_in_progress; - - tool_button = GTK_TOGGLE_TOOL_BUTTON (button); - event_widget = gtk_get_event_widget ((GdkEvent *) event); - - popup_in_progress = button->priv->popup_in_progress; - button->priv->popup_in_progress = FALSE; - - if (event_widget != GTK_WIDGET (button)) - goto popdown; - - if (popup_in_progress) - return FALSE; - - if (gtk_toggle_tool_button_get_active (tool_button)) - goto popdown; - - return FALSE; - -popdown: - e_emoticon_tool_button_popdown (button); - - return TRUE; -} - -static void -emoticon_tool_button_child_show_cb (EEmoticonToolButton *button) -{ - button->priv->popup_shown = TRUE; - g_object_notify (G_OBJECT (button), "popup-shown"); -} - -static void -emoticon_tool_button_child_hide_cb (EEmoticonToolButton *button) -{ - button->priv->popup_shown = FALSE; - g_object_notify (G_OBJECT (button), "popup-shown"); -} - -static gboolean -emoticon_tool_button_child_key_press_event_cb (EEmoticonToolButton *button, - GdkEventKey *event) -{ - GtkWidget *popover = button->priv->popover; - - return gtk_bindings_activate_event (G_OBJECT (popover), event) || - gtk_bindings_activate_event (G_OBJECT (button), event); -} - -static void -emoticon_tool_button_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_CURRENT_EMOTICON: - e_emoticon_chooser_set_current_emoticon ( - E_EMOTICON_CHOOSER (object), - g_value_get_boxed (value)); - return; - - case PROP_POPUP_SHOWN: - if (g_value_get_boolean (value)) - e_emoticon_tool_button_popup ( - E_EMOTICON_TOOL_BUTTON (object)); - else - e_emoticon_tool_button_popdown ( - E_EMOTICON_TOOL_BUTTON (object)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -emoticon_tool_button_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - EEmoticonToolButton *self = E_EMOTICON_TOOL_BUTTON (object); - - switch (property_id) { - case PROP_CURRENT_EMOTICON: - g_value_set_boxed ( - value, - e_emoticon_chooser_get_current_emoticon ( - E_EMOTICON_CHOOSER (object))); - return; - - case PROP_POPUP_SHOWN: - g_value_set_boolean (value, self->priv->popup_shown); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -emoticon_tool_button_dispose (GObject *object) -{ - EEmoticonToolButton *self = E_EMOTICON_TOOL_BUTTON (object); - - g_clear_pointer (&self->priv->popover, gtk_widget_destroy); - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_emoticon_tool_button_parent_class)->dispose (object); -} - -static gboolean -emoticon_tool_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - EEmoticonToolButton *button; - GtkToggleToolButton *toggle_button; - GtkWidget *event_widget; - - button = E_EMOTICON_TOOL_BUTTON (widget); - - event_widget = gtk_get_event_widget ((GdkEvent *) event); - - if (event_widget == button->priv->popover) - return TRUE; - - if (event_widget != widget) - return FALSE; - - toggle_button = GTK_TOGGLE_TOOL_BUTTON (widget); - if (gtk_toggle_tool_button_get_active (toggle_button)) - return FALSE; - - e_emoticon_tool_button_popup (button); - - button->priv->popup_in_progress = TRUE; - - return TRUE; -} - -static void -emoticon_tool_button_toggled (GtkToggleToolButton *button) -{ - if (gtk_toggle_tool_button_get_active (button)) - e_emoticon_tool_button_popup ( - E_EMOTICON_TOOL_BUTTON (button)); - else - e_emoticon_tool_button_popdown ( - E_EMOTICON_TOOL_BUTTON (button)); -} - -static void -emoticon_tool_button_popup (EEmoticonToolButton *button) -{ - GtkToggleToolButton *tool_button; - - if (!gtk_widget_get_realized (GTK_WIDGET (button))) - return; - - if (button->priv->popup_shown) - return; - - /* Activate the tool button. */ - tool_button = GTK_TOGGLE_TOOL_BUTTON (button); - gtk_toggle_tool_button_set_active (tool_button, TRUE); - - /* Show the pop-up. */ - gtk_widget_show (button->priv->popover); - gtk_widget_grab_focus (button->priv->table); -} - -static void -emoticon_tool_button_popdown (EEmoticonToolButton *button) -{ - GtkToggleToolButton *tool_button; - - if (!gtk_widget_get_realized (GTK_WIDGET (button))) - return; - - if (!button->priv->popup_shown) - return; - - gtk_widget_hide (button->priv->popover); - - /* Deactivate the tool button. */ - tool_button = GTK_TOGGLE_TOOL_BUTTON (button); - gtk_toggle_tool_button_set_active (tool_button, FALSE); -} - -static EEmoticon * -emoticon_tool_button_get_current_emoticon (EEmoticonChooser *chooser) -{ - EEmoticonToolButton *self = E_EMOTICON_TOOL_BUTTON (chooser); - - if (!self->priv->active_button) - return NULL; - - return g_object_get_data (G_OBJECT (self->priv->active_button), "emoticon"); -} - -static void -emoticon_tool_button_set_current_emoticon (EEmoticonChooser *chooser, - EEmoticon *emoticon) -{ - EEmoticonToolButton *self = E_EMOTICON_TOOL_BUTTON (chooser); - GList *list, *iter; - - list = gtk_container_get_children (GTK_CONTAINER (self->priv->table)); - - for (iter = list; iter != NULL; iter = iter->next) { - GtkWidget *item = iter->data; - EEmoticon *candidate; - - candidate = g_object_get_data (G_OBJECT (item), "emoticon"); - if (candidate == NULL) - continue; - - if (e_emoticon_equal (emoticon, candidate)) { - gtk_button_clicked (GTK_BUTTON (item)); - break; - } - } - - g_list_free (list); -} - -static void -e_emoticon_tool_button_class_init (EEmoticonToolButtonClass *class) -{ - GObjectClass *object_class; - GtkWidgetClass *widget_class; - GtkToggleToolButtonClass *toggle_tool_button_class; - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = emoticon_tool_button_set_property; - object_class->get_property = emoticon_tool_button_get_property; - object_class->dispose = emoticon_tool_button_dispose; - - widget_class = GTK_WIDGET_CLASS (class); - widget_class->button_press_event = emoticon_tool_button_press_event; - - toggle_tool_button_class = GTK_TOGGLE_TOOL_BUTTON_CLASS (class); - toggle_tool_button_class->toggled = emoticon_tool_button_toggled; - - class->popup = emoticon_tool_button_popup; - class->popdown = emoticon_tool_button_popdown; - - g_object_class_override_property ( - object_class, PROP_CURRENT_EMOTICON, "current-emoticon"); - - g_object_class_install_property ( - object_class, - PROP_POPUP_SHOWN, - g_param_spec_boolean ( - "popup-shown", - "Popup Shown", - "Whether the button's dropdown is shown", - FALSE, - G_PARAM_READWRITE)); - - signals[POPUP] = g_signal_new ( - "popup", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EEmoticonToolButtonClass, popup), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[POPDOWN] = g_signal_new ( - "popdown", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EEmoticonToolButtonClass, popdown), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - gtk_binding_entry_add_signal ( - gtk_binding_set_by_class (class), - GDK_KEY_Down, GDK_MOD1_MASK, "popup", 0); - gtk_binding_entry_add_signal ( - gtk_binding_set_by_class (class), - GDK_KEY_KP_Down, GDK_MOD1_MASK, "popup", 0); - - gtk_binding_entry_add_signal ( - gtk_binding_set_by_class (class), - GDK_KEY_Up, GDK_MOD1_MASK, "popdown", 0); - gtk_binding_entry_add_signal ( - gtk_binding_set_by_class (class), - GDK_KEY_KP_Up, GDK_MOD1_MASK, "popdown", 0); - gtk_binding_entry_add_signal ( - gtk_binding_set_by_class (class), - GDK_KEY_Escape, 0, "popdown", 0); -} - -static void -e_emoticon_tool_button_interface_init (EEmoticonChooserInterface *interface) -{ - interface->get_current_emoticon = - emoticon_tool_button_get_current_emoticon; - interface->set_current_emoticon = - emoticon_tool_button_set_current_emoticon; -} - -static void -e_emoticon_tool_button_init (EEmoticonToolButton *button) -{ - EEmoticonChooser *chooser; - GtkWidget *container; - GtkWidget *widget; - GtkWidget *popover; - GList *list, *iter; - gint ii; - - button->priv = e_emoticon_tool_button_get_instance_private (button); - - /* Build the popover. */ - popover = gtk_popover_new (GTK_WIDGET (button)); - gtk_popover_set_position (GTK_POPOVER (popover), GTK_POS_BOTTOM); - gtk_popover_set_modal (GTK_POPOVER (popover), TRUE); - button->priv->popover = g_object_ref_sink (popover); - - g_signal_connect_swapped ( - popover, "show", - G_CALLBACK (emoticon_tool_button_child_show_cb), button); - g_signal_connect_swapped ( - popover, "hide", - G_CALLBACK (emoticon_tool_button_child_hide_cb), button); - g_signal_connect_swapped ( - popover, "button-release-event", - G_CALLBACK (emoticon_tool_button_button_release_event_cb), - button); - g_signal_connect_swapped ( - popover, "key-press-event", - G_CALLBACK (emoticon_tool_button_child_key_press_event_cb), - button); - - /* Build the popover content. */ - container = popover; - - widget = gtk_table_new (NUM_ROWS, NUM_COLS, TRUE); - gtk_table_set_row_spacings (GTK_TABLE (widget), 0); - gtk_table_set_col_spacings (GTK_TABLE (widget), 0); - gtk_container_add (GTK_CONTAINER (container), widget); - button->priv->table = g_object_ref (widget); - gtk_widget_show (widget); - - container = widget; - - chooser = E_EMOTICON_CHOOSER (button); - list = e_emoticon_chooser_get_items (); - g_return_if_fail (g_list_length (list) <= NUM_ROWS * NUM_COLS); - - for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) { - EEmoticon *emoticon = iter->data; - guint left = ii % NUM_COLS; - guint top = ii / NUM_COLS; - gchar *tooltip; - - tooltip = emoticon_tool_button_elide_underscores ( - gettext (emoticon->label)); - - widget = gtk_button_new (); - gtk_button_set_image ( - GTK_BUTTON (widget), - gtk_image_new_from_icon_name ( - emoticon->icon_name, GTK_ICON_SIZE_BUTTON)); - gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE); - gtk_widget_set_tooltip_text (widget, tooltip); - gtk_widget_show (widget); - - g_object_set_data_full ( - G_OBJECT (widget), "emoticon", - e_emoticon_copy (emoticon), - (GDestroyNotify) e_emoticon_free); - - g_signal_connect_swapped ( - widget, "clicked", - G_CALLBACK (emoticon_tool_button_emoticon_clicked_cb), - button); - - g_signal_connect_swapped ( - widget, "clicked", - G_CALLBACK (e_emoticon_chooser_item_activated), - chooser); - - g_signal_connect_swapped ( - widget, "button-release-event", - G_CALLBACK (emoticon_tool_button_emoticon_release_event_cb), - button); - - gtk_table_attach ( - GTK_TABLE (container), widget, - left, left + 1, top, top + 1, 0, 0, 0, 0); - - g_free (tooltip); - } - - g_list_free (list); -} - -GtkToolItem * -e_emoticon_tool_button_new (void) -{ - return g_object_new (E_TYPE_EMOTICON_TOOL_BUTTON, NULL); -} - -void -e_emoticon_tool_button_popup (EEmoticonToolButton *button) -{ - g_return_if_fail (E_IS_EMOTICON_TOOL_BUTTON (button)); - - g_signal_emit (button, signals[POPUP], 0); -} - -void -e_emoticon_tool_button_popdown (EEmoticonToolButton *button) -{ - g_return_if_fail (E_IS_EMOTICON_TOOL_BUTTON (button)); - - g_signal_emit (button, signals[POPDOWN], 0); -} diff --git a/src/e-util/e-emoticon-tool-button.h b/src/e-util/e-emoticon-tool-button.h deleted file mode 100644 index fc7dc8ef64..0000000000 --- a/src/e-util/e-emoticon-tool-button.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * e-emoticon-tool-button.h - * - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2012 Dan Vrátil - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU Lesser General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) -#error "Only should be included directly." -#endif - -#ifndef E_EMOTICON_TOOL_BUTTON_H -#define E_EMOTICON_TOOL_BUTTON_H - -#include - -/* Standard GObject macros */ -#define E_TYPE_EMOTICON_TOOL_BUTTON \ - (e_emoticon_tool_button_get_type ()) -#define E_EMOTICON_TOOL_BUTTON(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_EMOTICON_TOOL_BUTTON, EEmoticonToolButton)) -#define E_EMOTICON_TOOL_BUTTON_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_EMOTICON_TOOL_BUTTON, EEmoticonToolButtonClass)) -#define E_IS_EMOTICON_TOOL_BUTTON(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_EMOTICON_TOOL_BUTTON)) -#define E_IS_EMOTICON_TOOL_BUTTON_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_EMOTICON_TOOL_BUTTON)) -#define E_EMOTICON_TOOL_BUTTON_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_EMOTICON_TOOL_BUTTON, EEmoticonToolButtonClass)) - -G_BEGIN_DECLS - -typedef struct _EEmoticonToolButton EEmoticonToolButton; -typedef struct _EEmoticonToolButtonClass EEmoticonToolButtonClass; -typedef struct _EEmoticonToolButtonPrivate EEmoticonToolButtonPrivate; - -struct _EEmoticonToolButton { - GtkToggleToolButton parent; - EEmoticonToolButtonPrivate *priv; -}; - -struct _EEmoticonToolButtonClass { - GtkToggleToolButtonClass parent_class; - - void (*popup) (EEmoticonToolButton *button); - void (*popdown) (EEmoticonToolButton *button); -}; - -GType e_emoticon_tool_button_get_type (void) G_GNUC_CONST; -GtkToolItem * e_emoticon_tool_button_new (void); -void e_emoticon_tool_button_popup (EEmoticonToolButton *button); -void e_emoticon_tool_button_popdown (EEmoticonToolButton *button); - -G_END_DECLS - -#endif /* E_EMOTICON_TOOL_BUTTON_H */ diff --git a/src/e-util/e-emoticon.c b/src/e-util/e-emoticon.c index 53a9f494f6..8082e7238b 100644 --- a/src/e-util/e-emoticon.c +++ b/src/e-util/e-emoticon.c @@ -24,7 +24,7 @@ #include static EEmoticon * -emoticon_copy (EEmoticon *emoticon) +emoticon_copy (const EEmoticon *emoticon) { EEmoticon *copy; @@ -62,8 +62,8 @@ e_emoticon_get_type (void) } gboolean -e_emoticon_equal (EEmoticon *emoticon_a, - EEmoticon *emoticon_b) +e_emoticon_equal (const EEmoticon *emoticon_a, + const EEmoticon *emoticon_b) { if (((emoticon_a == NULL) && (emoticon_b != NULL)) || ((emoticon_a != NULL) && (emoticon_b == NULL))) @@ -88,7 +88,7 @@ e_emoticon_equal (EEmoticon *emoticon_a, } EEmoticon * -e_emoticon_copy (EEmoticon *emoticon) +e_emoticon_copy (const EEmoticon *emoticon) { return g_boxed_copy (E_TYPE_EMOTICON, emoticon); } @@ -100,7 +100,7 @@ e_emoticon_free (EEmoticon *emoticon) } gchar * -e_emoticon_get_uri (EEmoticon *emoticon) +e_emoticon_dup_uri (const EEmoticon *emoticon) { GtkIconInfo *icon_info; GtkIconTheme *icon_theme; @@ -123,7 +123,7 @@ e_emoticon_get_uri (EEmoticon *emoticon) } const gchar * -e_emoticon_get_name (EEmoticon *emoticon) +e_emoticon_get_name (const EEmoticon *emoticon) { return emoticon->icon_name; } diff --git a/src/e-util/e-emoticon.h b/src/e-util/e-emoticon.h index 3b9e8c0a8f..0d4a90a609 100644 --- a/src/e-util/e-emoticon.h +++ b/src/e-util/e-emoticon.h @@ -43,12 +43,12 @@ struct _EEmoticon { }; GType e_emoticon_get_type (void) G_GNUC_CONST; -gboolean e_emoticon_equal (EEmoticon *emoticon_a, - EEmoticon *emoticon_b); -EEmoticon * e_emoticon_copy (EEmoticon *emoticon); +gboolean e_emoticon_equal (const EEmoticon *emoticon_a, + const EEmoticon *emoticon_b); +EEmoticon * e_emoticon_copy (const EEmoticon *emoticon); void e_emoticon_free (EEmoticon *emoticon); -gchar * e_emoticon_get_uri (EEmoticon *emoticon); -const gchar * e_emoticon_get_name (EEmoticon *emoticon); +gchar * e_emoticon_dup_uri (const EEmoticon *emoticon); +const gchar * e_emoticon_get_name (const EEmoticon *emoticon); G_END_DECLS diff --git a/src/e-util/e-focus-tracker.c b/src/e-util/e-focus-tracker.c index e742da3c32..e73c7a77f9 100644 --- a/src/e-util/e-focus-tracker.c +++ b/src/e-util/e-focus-tracker.c @@ -20,25 +20,52 @@ #include "evolution-config.h" -#include "e-focus-tracker.h" - #include -#include "e-selectable.h" -#include "e-widget-undo.h" #include "e-content-editor.h" +#include "e-selectable.h" +#include "e-ui-action.h" +#include "e-widget-undo.h" + +#include "e-focus-tracker.h" + +#define disconnect_and_unref(_x) G_STMT_START { \ + if (_x != NULL) { \ + g_signal_handlers_disconnect_matched ( \ + _x, G_SIGNAL_MATCH_DATA, \ + 0, 0, NULL, NULL, focus_tracker); \ + g_clear_object (&(_x)); \ + } \ +} G_STMT_END + +#define replace_action(_priv_member, _arg, _cb, _prop_name) G_STMT_START { \ + g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker)); \ + if (_arg != NULL) { \ + g_return_if_fail (E_IS_UI_ACTION (_arg)); \ + g_object_ref (_arg); \ + } \ + disconnect_and_unref (_priv_member); \ + _priv_member = _arg; \ + if (_arg != NULL) { \ + g_signal_connect_swapped ( \ + _arg, "activate", \ + G_CALLBACK (_cb), \ + focus_tracker); \ + } \ + g_object_notify (G_OBJECT (focus_tracker), _prop_name); \ +} G_STMT_END struct _EFocusTrackerPrivate { GtkWidget *focus; /* not referenced */ GtkWindow *window; - GtkAction *cut_clipboard; - GtkAction *copy_clipboard; - GtkAction *paste_clipboard; - GtkAction *delete_selection; - GtkAction *select_all; - GtkAction *undo; - GtkAction *redo; + EUIAction *cut_clipboard; + EUIAction *copy_clipboard; + EUIAction *paste_clipboard; + EUIAction *delete_selection; + EUIAction *select_all; + EUIAction *undo; + EUIAction *redo; }; enum { @@ -59,35 +86,35 @@ G_DEFINE_TYPE_WITH_PRIVATE (EFocusTracker, e_focus_tracker, G_TYPE_OBJECT) static void focus_tracker_disable_actions (EFocusTracker *focus_tracker) { - GtkAction *action; + EUIAction *action; action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); if (action != NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); if (action != NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); if (action != NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_delete_selection_action (focus_tracker); if (action != NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_select_all_action (focus_tracker); if (action != NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_undo_action (focus_tracker); if (action != NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_redo_action (focus_tracker); if (action != NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); } static gboolean @@ -125,38 +152,38 @@ focus_tracker_update_undo_redo (EFocusTracker *focus_tracker, GtkWidget *widget, gboolean can_edit_text) { - GtkAction *action; + EUIAction *action; gboolean sensitive; action = e_focus_tracker_get_undo_action (focus_tracker); if (action != NULL) { sensitive = can_edit_text && focus_tracker_get_has_undo (widget); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); if (sensitive) { gchar *description; description = e_widget_undo_describe_undo (widget); - gtk_action_set_tooltip (action, description && *description ? description : _("Undo")); + e_ui_action_set_tooltip (action, description && *description ? description : _("Undo")); g_free (description); } else { - gtk_action_set_tooltip (action, _("Undo")); + e_ui_action_set_tooltip (action, _("Undo")); } } action = e_focus_tracker_get_redo_action (focus_tracker); if (action != NULL) { sensitive = can_edit_text && focus_tracker_get_has_redo (widget); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); if (sensitive) { gchar *description; description = e_widget_undo_describe_redo (widget); - gtk_action_set_tooltip (action, description && *description ? description : _("Redo")); + e_ui_action_set_tooltip (action, description && *description ? description : _("Redo")); g_free (description); } else { - gtk_action_set_tooltip (action, _("Redo")); + e_ui_action_set_tooltip (action, _("Redo")); } } } @@ -167,7 +194,7 @@ focus_tracker_editable_update_actions (EFocusTracker *focus_tracker, GdkAtom *targets, gint n_targets) { - GtkAction *action; + EUIAction *action; gboolean can_edit_text; gboolean clipboard_has_text; gboolean text_is_selected; @@ -185,36 +212,36 @@ focus_tracker_editable_update_actions (EFocusTracker *focus_tracker, action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); if (action != NULL) { sensitive = can_edit_text && text_is_selected; - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Cut the selection")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Cut the selection")); } action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); if (action != NULL) { sensitive = text_is_selected; - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Copy the selection")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Copy the selection")); } action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); if (action != NULL) { sensitive = can_edit_text && clipboard_has_text; - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Paste the clipboard")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Paste the clipboard")); } action = e_focus_tracker_get_delete_selection_action (focus_tracker); if (action != NULL) { sensitive = can_edit_text && text_is_selected; - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Delete the selection")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Delete the selection")); } action = e_focus_tracker_get_select_all_action (focus_tracker); if (action != NULL) { sensitive = TRUE; /* always enabled */ - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Select all text")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Select all text")); } focus_tracker_update_undo_redo (focus_tracker, GTK_WIDGET (editable), can_edit_text); @@ -226,7 +253,7 @@ focus_tracker_text_view_update_actions (EFocusTracker *focus_tracker, GdkAtom *targets, gint n_targets) { - GtkAction *action; + EUIAction *action; GtkTextBuffer *buffer; gboolean can_edit_text; gboolean clipboard_has_text; @@ -241,36 +268,36 @@ focus_tracker_text_view_update_actions (EFocusTracker *focus_tracker, action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); if (action != NULL) { sensitive = can_edit_text && text_is_selected; - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Cut the selection")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Cut the selection")); } action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); if (action != NULL) { sensitive = text_is_selected; - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Copy the selection")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Copy the selection")); } action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); if (action != NULL) { sensitive = can_edit_text && clipboard_has_text; - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Paste the clipboard")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Paste the clipboard")); } action = e_focus_tracker_get_delete_selection_action (focus_tracker); if (action != NULL) { sensitive = can_edit_text && text_is_selected; - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Delete the selection")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Delete the selection")); } action = e_focus_tracker_get_select_all_action (focus_tracker); if (action != NULL) { sensitive = TRUE; /* always enabled */ - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_tooltip (action, _("Select all text")); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_tooltip (action, _("Select all text")); } focus_tracker_update_undo_redo (focus_tracker, GTK_WIDGET (text_view), can_edit_text); @@ -282,7 +309,7 @@ focus_tracker_editor_update_actions (EFocusTracker *focus_tracker, GdkAtom *targets, gint n_targets) { - GtkAction *action; + EUIAction *action; gboolean can_copy; gboolean can_cut; gboolean can_paste; @@ -295,20 +322,20 @@ focus_tracker_editor_update_actions (EFocusTracker *focus_tracker, action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); if (action != NULL) { - gtk_action_set_sensitive (action, can_cut); - gtk_action_set_tooltip (action, _("Cut the selection")); + e_ui_action_set_sensitive (action, can_cut); + e_ui_action_set_tooltip (action, _("Cut the selection")); } action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); if (action != NULL) { - gtk_action_set_sensitive (action, can_copy); - gtk_action_set_tooltip (action, _("Copy the selection")); + e_ui_action_set_sensitive (action, can_copy); + e_ui_action_set_tooltip (action, _("Copy the selection")); } action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); if (action != NULL) { - gtk_action_set_sensitive (action, can_paste); - gtk_action_set_tooltip (action, _("Paste the clipboard")); + e_ui_action_set_sensitive (action, can_paste); + e_ui_action_set_tooltip (action, _("Paste the clipboard")); } focus_tracker_update_undo_redo (focus_tracker, GTK_WIDGET (cnt_editor), @@ -322,7 +349,7 @@ focus_tracker_selectable_update_actions (EFocusTracker *focus_tracker, gint n_targets) { ESelectableInterface *iface; - GtkAction *action; + EUIAction *action; iface = E_SELECTABLE_GET_INTERFACE (selectable); @@ -337,31 +364,31 @@ focus_tracker_selectable_update_actions (EFocusTracker *focus_tracker, action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); if (action != NULL && iface->cut_clipboard == NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); if (action != NULL && iface->copy_clipboard == NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); if (action != NULL && iface->paste_clipboard == NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_delete_selection_action (focus_tracker); if (action != NULL && iface->delete_selection == NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_select_all_action (focus_tracker); if (action != NULL && iface->select_all == NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_undo_action (focus_tracker); if (action != NULL && iface->undo == NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_redo_action (focus_tracker); if (action != NULL && iface->redo == NULL) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); } static void @@ -589,57 +616,24 @@ focus_tracker_get_property (GObject *object, static void focus_tracker_dispose (GObject *object) { - EFocusTracker *self = E_FOCUS_TRACKER (object); + EFocusTracker *focus_tracker = E_FOCUS_TRACKER (object); g_signal_handlers_disconnect_matched ( gtk_clipboard_get (GDK_SELECTION_PRIMARY), - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); + G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, focus_tracker); g_signal_handlers_disconnect_matched ( gtk_clipboard_get (GDK_SELECTION_CLIPBOARD), - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); + G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, focus_tracker); - if (self->priv->window != NULL) { - g_signal_handlers_disconnect_matched ( - self->priv->window, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - g_clear_object (&self->priv->window); - } - - if (self->priv->cut_clipboard != NULL) { - g_signal_handlers_disconnect_matched ( - self->priv->cut_clipboard, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - g_clear_object (&self->priv->cut_clipboard); - } - - if (self->priv->copy_clipboard != NULL) { - g_signal_handlers_disconnect_matched ( - self->priv->copy_clipboard, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - g_clear_object (&self->priv->copy_clipboard); - } - - if (self->priv->paste_clipboard != NULL) { - g_signal_handlers_disconnect_matched ( - self->priv->paste_clipboard, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - g_clear_object (&self->priv->paste_clipboard); - } - - if (self->priv->delete_selection != NULL) { - g_signal_handlers_disconnect_matched ( - self->priv->delete_selection, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - g_clear_object (&self->priv->delete_selection); - } - - if (self->priv->select_all != NULL) { - g_signal_handlers_disconnect_matched ( - self->priv->select_all, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, object); - g_clear_object (&self->priv->select_all); - } + disconnect_and_unref (focus_tracker->priv->window); + disconnect_and_unref (focus_tracker->priv->cut_clipboard); + disconnect_and_unref (focus_tracker->priv->copy_clipboard); + disconnect_and_unref (focus_tracker->priv->paste_clipboard); + disconnect_and_unref (focus_tracker->priv->delete_selection); + disconnect_and_unref (focus_tracker->priv->select_all); + disconnect_and_unref (focus_tracker->priv->undo); + disconnect_and_unref (focus_tracker->priv->redo); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_focus_tracker_parent_class)->dispose (object); @@ -714,7 +708,7 @@ e_focus_tracker_class_init (EFocusTrackerClass *class) "cut-clipboard-action", "Cut Clipboard Action", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -724,7 +718,7 @@ e_focus_tracker_class_init (EFocusTrackerClass *class) "copy-clipboard-action", "Copy Clipboard Action", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -734,7 +728,7 @@ e_focus_tracker_class_init (EFocusTrackerClass *class) "paste-clipboard-action", "Paste Clipboard Action", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -744,7 +738,7 @@ e_focus_tracker_class_init (EFocusTrackerClass *class) "delete-selection-action", "Delete Selection Action", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -754,7 +748,7 @@ e_focus_tracker_class_init (EFocusTrackerClass *class) "select-all-action", "Select All Action", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -764,7 +758,7 @@ e_focus_tracker_class_init (EFocusTrackerClass *class) "undo-action", "Undo Action", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -774,45 +768,14 @@ e_focus_tracker_class_init (EFocusTrackerClass *class) "redo-action", "Redo Action", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); } static void e_focus_tracker_init (EFocusTracker *focus_tracker) { - GtkAction *action; - focus_tracker->priv = e_focus_tracker_get_instance_private (focus_tracker); - - /* Define dummy actions. These will most likely be overridden, - * but for cases where they're not it ensures ESelectable objects - * will always get a valid GtkAction when they ask us for one. */ - - action = gtk_action_new ( - "cut-clipboard", _("Cu_t"), - _("Cut the selection"), "edit-cut"); - focus_tracker->priv->cut_clipboard = action; - - action = gtk_action_new ( - "copy-clipboard", _("_Copy"), - _("Copy the selection"), "edit-copy"); - focus_tracker->priv->copy_clipboard = action; - - action = gtk_action_new ( - "paste-clipboard", _("_Paste"), - _("Paste the clipboard"), "edit-paste"); - focus_tracker->priv->paste_clipboard = action; - - action = gtk_action_new ( - "delete-selection", _("_Delete"), - _("Delete the selection"), "edit-delete"); - focus_tracker->priv->delete_selection = action; - - action = gtk_action_new ( - "select-all", _("Select _All"), - _("Select all text"), "edit-select-all"); - focus_tracker->priv->select_all = action; } EFocusTracker * @@ -839,7 +802,7 @@ e_focus_tracker_get_window (EFocusTracker *focus_tracker) return focus_tracker->priv->window; } -GtkAction * +EUIAction * e_focus_tracker_get_cut_clipboard_action (EFocusTracker *focus_tracker) { g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL); @@ -849,35 +812,12 @@ e_focus_tracker_get_cut_clipboard_action (EFocusTracker *focus_tracker) void e_focus_tracker_set_cut_clipboard_action (EFocusTracker *focus_tracker, - GtkAction *cut_clipboard) + EUIAction *cut_clipboard) { - g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker)); - - if (cut_clipboard != NULL) { - g_return_if_fail (GTK_IS_ACTION (cut_clipboard)); - g_object_ref (cut_clipboard); - } - - if (focus_tracker->priv->cut_clipboard != NULL) { - g_signal_handlers_disconnect_matched ( - focus_tracker->priv->cut_clipboard, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, - focus_tracker); - g_object_unref (focus_tracker->priv->cut_clipboard); - } - - focus_tracker->priv->cut_clipboard = cut_clipboard; - - if (cut_clipboard != NULL) - g_signal_connect_swapped ( - cut_clipboard, "activate", - G_CALLBACK (e_focus_tracker_cut_clipboard), - focus_tracker); - - g_object_notify (G_OBJECT (focus_tracker), "cut-clipboard-action"); + replace_action (focus_tracker->priv->cut_clipboard, cut_clipboard, e_focus_tracker_cut_clipboard, "cut-clipboard-action"); } -GtkAction * +EUIAction * e_focus_tracker_get_copy_clipboard_action (EFocusTracker *focus_tracker) { g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL); @@ -887,35 +827,12 @@ e_focus_tracker_get_copy_clipboard_action (EFocusTracker *focus_tracker) void e_focus_tracker_set_copy_clipboard_action (EFocusTracker *focus_tracker, - GtkAction *copy_clipboard) + EUIAction *copy_clipboard) { - g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker)); - - if (copy_clipboard != NULL) { - g_return_if_fail (GTK_IS_ACTION (copy_clipboard)); - g_object_ref (copy_clipboard); - } - - if (focus_tracker->priv->copy_clipboard != NULL) { - g_signal_handlers_disconnect_matched ( - focus_tracker->priv->copy_clipboard, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, - focus_tracker); - g_object_unref (focus_tracker->priv->copy_clipboard); - } - - focus_tracker->priv->copy_clipboard = copy_clipboard; - - if (copy_clipboard != NULL) - g_signal_connect_swapped ( - copy_clipboard, "activate", - G_CALLBACK (e_focus_tracker_copy_clipboard), - focus_tracker); - - g_object_notify (G_OBJECT (focus_tracker), "copy-clipboard-action"); + replace_action (focus_tracker->priv->copy_clipboard, copy_clipboard, e_focus_tracker_copy_clipboard, "copy-clipboard-action"); } -GtkAction * +EUIAction * e_focus_tracker_get_paste_clipboard_action (EFocusTracker *focus_tracker) { g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL); @@ -925,35 +842,12 @@ e_focus_tracker_get_paste_clipboard_action (EFocusTracker *focus_tracker) void e_focus_tracker_set_paste_clipboard_action (EFocusTracker *focus_tracker, - GtkAction *paste_clipboard) + EUIAction *paste_clipboard) { - g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker)); - - if (paste_clipboard != NULL) { - g_return_if_fail (GTK_IS_ACTION (paste_clipboard)); - g_object_ref (paste_clipboard); - } - - if (focus_tracker->priv->paste_clipboard != NULL) { - g_signal_handlers_disconnect_matched ( - focus_tracker->priv->paste_clipboard, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, - focus_tracker); - g_object_unref (focus_tracker->priv->paste_clipboard); - } - - focus_tracker->priv->paste_clipboard = paste_clipboard; - - if (paste_clipboard != NULL) - g_signal_connect_swapped ( - paste_clipboard, "activate", - G_CALLBACK (e_focus_tracker_paste_clipboard), - focus_tracker); - - g_object_notify (G_OBJECT (focus_tracker), "paste-clipboard-action"); + replace_action (focus_tracker->priv->paste_clipboard, paste_clipboard, e_focus_tracker_paste_clipboard, "paste-clipboard-action"); } -GtkAction * +EUIAction * e_focus_tracker_get_delete_selection_action (EFocusTracker *focus_tracker) { g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL); @@ -963,35 +857,12 @@ e_focus_tracker_get_delete_selection_action (EFocusTracker *focus_tracker) void e_focus_tracker_set_delete_selection_action (EFocusTracker *focus_tracker, - GtkAction *delete_selection) + EUIAction *delete_selection) { - g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker)); - - if (delete_selection != NULL) { - g_return_if_fail (GTK_IS_ACTION (delete_selection)); - g_object_ref (delete_selection); - } - - if (focus_tracker->priv->delete_selection != NULL) { - g_signal_handlers_disconnect_matched ( - focus_tracker->priv->delete_selection, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, - focus_tracker); - g_object_unref (focus_tracker->priv->delete_selection); - } - - focus_tracker->priv->delete_selection = delete_selection; - - if (delete_selection != NULL) - g_signal_connect_swapped ( - delete_selection, "activate", - G_CALLBACK (e_focus_tracker_delete_selection), - focus_tracker); - - g_object_notify (G_OBJECT (focus_tracker), "delete-selection-action"); + replace_action (focus_tracker->priv->delete_selection, delete_selection, e_focus_tracker_delete_selection, "delete-selection-action"); } -GtkAction * +EUIAction * e_focus_tracker_get_select_all_action (EFocusTracker *focus_tracker) { g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL); @@ -1001,35 +872,12 @@ e_focus_tracker_get_select_all_action (EFocusTracker *focus_tracker) void e_focus_tracker_set_select_all_action (EFocusTracker *focus_tracker, - GtkAction *select_all) + EUIAction *select_all) { - g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker)); - - if (select_all != NULL) { - g_return_if_fail (GTK_IS_ACTION (select_all)); - g_object_ref (select_all); - } - - if (focus_tracker->priv->select_all != NULL) { - g_signal_handlers_disconnect_matched ( - focus_tracker->priv->select_all, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, - focus_tracker); - g_object_unref (focus_tracker->priv->select_all); - } - - focus_tracker->priv->select_all = select_all; - - if (select_all != NULL) - g_signal_connect_swapped ( - select_all, "activate", - G_CALLBACK (e_focus_tracker_select_all), - focus_tracker); - - g_object_notify (G_OBJECT (focus_tracker), "select-all-action"); + replace_action (focus_tracker->priv->select_all, select_all, e_focus_tracker_select_all, "select-all-action"); } -GtkAction * +EUIAction * e_focus_tracker_get_undo_action (EFocusTracker *focus_tracker) { g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL); @@ -1039,35 +887,12 @@ e_focus_tracker_get_undo_action (EFocusTracker *focus_tracker) void e_focus_tracker_set_undo_action (EFocusTracker *focus_tracker, - GtkAction *undo) + EUIAction *undo) { - g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker)); - - if (undo != NULL) { - g_return_if_fail (GTK_IS_ACTION (undo)); - g_object_ref (undo); - } - - if (focus_tracker->priv->undo != NULL) { - g_signal_handlers_disconnect_matched ( - focus_tracker->priv->undo, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, - focus_tracker); - g_object_unref (focus_tracker->priv->undo); - } - - focus_tracker->priv->undo = undo; - - if (undo != NULL) - g_signal_connect_swapped ( - undo, "activate", - G_CALLBACK (e_focus_tracker_undo), - focus_tracker); - - g_object_notify (G_OBJECT (focus_tracker), "undo-action"); + replace_action (focus_tracker->priv->undo, undo, e_focus_tracker_undo, "undo-action"); } -GtkAction * +EUIAction * e_focus_tracker_get_redo_action (EFocusTracker *focus_tracker) { g_return_val_if_fail (E_IS_FOCUS_TRACKER (focus_tracker), NULL); @@ -1077,32 +902,9 @@ e_focus_tracker_get_redo_action (EFocusTracker *focus_tracker) void e_focus_tracker_set_redo_action (EFocusTracker *focus_tracker, - GtkAction *redo) + EUIAction *redo) { - g_return_if_fail (E_IS_FOCUS_TRACKER (focus_tracker)); - - if (redo != NULL) { - g_return_if_fail (GTK_IS_ACTION (redo)); - g_object_ref (redo); - } - - if (focus_tracker->priv->redo != NULL) { - g_signal_handlers_disconnect_matched ( - focus_tracker->priv->redo, - G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, - focus_tracker); - g_object_unref (focus_tracker->priv->redo); - } - - focus_tracker->priv->redo = redo; - - if (redo != NULL) - g_signal_connect_swapped ( - redo, "activate", - G_CALLBACK (e_focus_tracker_redo), - focus_tracker); - - g_object_notify (G_OBJECT (focus_tracker), "redo-action"); + replace_action (focus_tracker->priv->redo, redo, e_focus_tracker_redo, "redo-action"); } void diff --git a/src/e-util/e-focus-tracker.h b/src/e-util/e-focus-tracker.h index a4e5a4e210..f35f2e82f7 100644 --- a/src/e-util/e-focus-tracker.h +++ b/src/e-util/e-focus-tracker.h @@ -27,6 +27,8 @@ #include +#include + /* Standard GObject macros */ #define E_TYPE_FOCUS_TRACKER \ (e_focus_tracker_get_type ()) @@ -65,37 +67,37 @@ GType e_focus_tracker_get_type (void) G_GNUC_CONST; EFocusTracker * e_focus_tracker_new (GtkWindow *window); GtkWidget * e_focus_tracker_get_focus (EFocusTracker *focus_tracker); GtkWindow * e_focus_tracker_get_window (EFocusTracker *focus_tracker); -GtkAction * e_focus_tracker_get_cut_clipboard_action +EUIAction * e_focus_tracker_get_cut_clipboard_action (EFocusTracker *focus_tracker); void e_focus_tracker_set_cut_clipboard_action (EFocusTracker *focus_tracker, - GtkAction *cut_clipboard); -GtkAction * e_focus_tracker_get_copy_clipboard_action + EUIAction *cut_clipboard); +EUIAction * e_focus_tracker_get_copy_clipboard_action (EFocusTracker *focus_tracker); void e_focus_tracker_set_copy_clipboard_action (EFocusTracker *focus_tracker, - GtkAction *copy_clipboard); -GtkAction * e_focus_tracker_get_paste_clipboard_action + EUIAction *copy_clipboard); +EUIAction * e_focus_tracker_get_paste_clipboard_action (EFocusTracker *focus_tracker); void e_focus_tracker_set_paste_clipboard_action (EFocusTracker *focus_tracker, - GtkAction *paste_clipboard); -GtkAction * e_focus_tracker_get_delete_selection_action + EUIAction *paste_clipboard); +EUIAction * e_focus_tracker_get_delete_selection_action (EFocusTracker *focus_tracker); void e_focus_tracker_set_delete_selection_action (EFocusTracker *focus_tracker, - GtkAction *delete_selection); -GtkAction * e_focus_tracker_get_select_all_action + EUIAction *delete_selection); +EUIAction * e_focus_tracker_get_select_all_action (EFocusTracker *focus_tracker); void e_focus_tracker_set_select_all_action (EFocusTracker *focus_tracker, - GtkAction *select_all); -GtkAction * e_focus_tracker_get_undo_action (EFocusTracker *focus_tracker); + EUIAction *select_all); +EUIAction * e_focus_tracker_get_undo_action (EFocusTracker *focus_tracker); void e_focus_tracker_set_undo_action (EFocusTracker *focus_tracker, - GtkAction *undo); -GtkAction * e_focus_tracker_get_redo_action (EFocusTracker *focus_tracker); + EUIAction *undo); +EUIAction * e_focus_tracker_get_redo_action (EFocusTracker *focus_tracker); void e_focus_tracker_set_redo_action (EFocusTracker *focus_tracker, - GtkAction *redo); + EUIAction *redo); void e_focus_tracker_update_actions (EFocusTracker *focus_tracker); void e_focus_tracker_cut_clipboard (EFocusTracker *focus_tracker); void e_focus_tracker_copy_clipboard (EFocusTracker *focus_tracker); diff --git a/src/e-util/e-headerbar-button.c b/src/e-util/e-headerbar-button.c index 433cd351bb..a235971114 100644 --- a/src/e-util/e-headerbar-button.c +++ b/src/e-util/e-headerbar-button.c @@ -14,17 +14,21 @@ #include "evolution-config.h" -#include "e-headerbar-button.h" -#include "e-misc-utils.h" - #include +#include "e-misc-utils.h" +#include "e-ui-action.h" +#include "e-ui-manager.h" + +#include "e-headerbar-button.h" + struct _EHeaderBarButtonPrivate { GtkWidget *labeled_button; GtkWidget *icon_only_button; GtkWidget *dropdown_button; - GtkAction *action; + EUIManager *ui_manager; + EUIAction *action; gchar *label; gchar *prefer_item; gint last_labeled_button_width; @@ -35,86 +39,52 @@ enum { PROP_0, PROP_PREFER_ITEM, PROP_LABEL, - PROP_ACTION + PROP_ACTION, + PROP_UI_MANAGER }; G_DEFINE_TYPE_WITH_CODE (EHeaderBarButton, e_header_bar_button, GTK_TYPE_BOX, G_ADD_PRIVATE (EHeaderBarButton)) -static GtkAction * +static EUIAction * header_bar_button_get_prefer_action (EHeaderBarButton *header_bar_button) { - GtkMenu *menu; - GList *children; - GtkAction *action = NULL; - GList *link; - const gchar *prefer_item; - - if (header_bar_button->priv->dropdown_button == NULL) + if (!header_bar_button->priv->ui_manager || + !header_bar_button->priv->prefer_item) return NULL; - menu = gtk_menu_button_get_popup ( GTK_MENU_BUTTON (header_bar_button->priv->dropdown_button)); - g_return_val_if_fail (menu != NULL, NULL); - - children = gtk_container_get_children (GTK_CONTAINER (menu)); - g_return_val_if_fail (children != NULL, NULL); - - prefer_item = header_bar_button->priv->prefer_item; - - for (link = children; link != NULL; link = g_list_next (link)) { - GtkWidget *child; - const gchar *name; - - child = GTK_WIDGET (link->data); - - if (!GTK_IS_MENU_ITEM (child)) - continue; - - action = gtk_activatable_get_related_action ( - GTK_ACTIVATABLE (child)); - - if (action == NULL) - continue; - - name = gtk_action_get_name (action); - - if (prefer_item == NULL || - *prefer_item == '\0' || - g_strcmp0 (name, prefer_item) == 0) { - break; - } - } - - g_list_free (children); - - return action; + return e_ui_manager_get_action (header_bar_button->priv->ui_manager, header_bar_button->priv->prefer_item); } static void -header_bar_button_update_button_for_action (GtkButton *button, - GtkAction *action) +header_bar_button_update_button_for_action (EHeaderBarButton *self, + GtkButton *button, + EUIAction *action, + EUIManager *ui_manager) { - GtkWidget *image; GtkStyleContext *style_context; - const gchar *tooltip; - const gchar *icon_name; + const gchar *value; g_return_if_fail (button != NULL); g_return_if_fail (action != NULL); - tooltip = gtk_action_get_tooltip (action); - gtk_widget_set_tooltip_text (GTK_WIDGET (button), tooltip); + if (ui_manager) { + const gchar *const_label = gtk_button_get_label (button); + gchar *revert_label = const_label ? e_str_without_underscores (const_label) : NULL; + gboolean revert_visible = gtk_widget_get_visible (GTK_WIDGET (button)); - icon_name = gtk_action_get_icon_name (action); - if (icon_name == NULL) { - GIcon *icon = gtk_action_get_gicon (action); - image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON); + e_ui_manager_update_item_from_action (ui_manager, button, action); + + /* The e_ui_manager_update_item_from_action() sets also the label from the action, + but the header bar buttons can have a different label and there can be buttons + with icons only too. */ + gtk_widget_set_visible (GTK_WIDGET (button), revert_visible); + gtk_button_set_label (button, revert_label); + g_free (revert_label); } else { - image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON); + value = e_ui_action_get_tooltip (action); + gtk_widget_set_tooltip_text (GTK_WIDGET (button), value); } - gtk_widget_set_margin_end (image, 2); - gtk_button_set_image (GTK_BUTTON (button), image); - gtk_widget_show (image); /* Force text button class to fix some themes */ style_context = gtk_widget_get_style_context (GTK_WIDGET (button)); @@ -124,7 +94,7 @@ header_bar_button_update_button_for_action (GtkButton *button, static void header_bar_button_update_button (EHeaderBarButton *header_bar_button) { - GtkAction *action; + EUIAction *action; if (header_bar_button->priv->action == NULL) action = header_bar_button_get_prefer_action (header_bar_button); @@ -132,42 +102,17 @@ header_bar_button_update_button (EHeaderBarButton *header_bar_button) action = header_bar_button->priv->action; if (action != NULL) { - header_bar_button_update_button_for_action ( + header_bar_button_update_button_for_action (header_bar_button, GTK_BUTTON (header_bar_button->priv->labeled_button), - action); + action, header_bar_button->priv->ui_manager); if (header_bar_button->priv->icon_only_button) { - header_bar_button_update_button_for_action ( + header_bar_button_update_button_for_action (NULL, GTK_BUTTON (header_bar_button->priv->icon_only_button), - action); + action, header_bar_button->priv->ui_manager); } } } -static void -header_bar_button_clicked (GtkWidget *button, - gpointer user_data) -{ - EHeaderBarButton *header_bar_button = user_data; - GtkAction *action; - - if (header_bar_button->priv->action == NULL) - action = header_bar_button_get_prefer_action (header_bar_button); - else - action = header_bar_button->priv->action; - - if (action != NULL) - gtk_action_activate (action); -} - -static void -header_bar_button_action_activate_cb (GObject *button, - gpointer user_data) -{ - GtkAction *action = user_data; - - gtk_action_activate (action); -} - static void header_bar_button_set_prefer_item (EHeaderBarButton *self, const gchar *prefer_item) @@ -178,119 +123,39 @@ header_bar_button_set_prefer_item (EHeaderBarButton *self, return; g_free (self->priv->prefer_item); - self->priv->prefer_item = g_strdup (prefer_item); + header_bar_button_update_button (self); } -static gboolean -header_bar_button_transform_sensitive_cb (GBinding *binding, - const GValue *from_value, - GValue *to_value, - gpointer user_data) -{ - /* The GtkAction::sensitive property does not take into the consideration - also the group's sensitivity, thus use the gtk_action_is_sensitive() function. */ - - g_value_set_boolean (to_value, gtk_action_is_sensitive (GTK_ACTION (g_binding_get_source (binding)))); - - return TRUE; -} - -typedef struct _ToggleActionData { - GWeakRef *button_weakref; - gulong handler_id; -} ToggleActionData; - -static void -toggle_action_data_free (gpointer ptr, - GClosure *closure) -{ - ToggleActionData *tad = ptr; - - if (tad) { - e_weak_ref_free (tad->button_weakref); - g_free (tad); - } -} - -static void -header_button_action_notify_active_cb (GObject *action, - GParamSpec *param, - gpointer user_data) -{ - ToggleActionData *tad = user_data; - GtkToggleButton *button; - gboolean active = FALSE; - - button = g_weak_ref_get (tad->button_weakref); - if (!button) - return; - - g_object_get (action, "active", &active, NULL); - - /* The "clicked" callback calls gtk_action_activate(), which, in case - of the toggle action, means to flip the option, thus it calls a notification - about action's 'active' property change, which leads back here, causing - a busy loop though the signal handlers. Blocking the handler breaks the loop. */ - if (tad->handler_id) - g_signal_handler_block (button, tad->handler_id); - - if ((gtk_toggle_button_get_active (button) ? 1 : 0) != (active ? 1 : 0)) - gtk_toggle_button_set_active (button, active); - - if (tad->handler_id) - g_signal_handler_unblock (button, tad->handler_id); - - g_clear_object (&button); -} - static GtkWidget * header_bar_button_add_action_button (EHeaderBarButton *header_bar_button, const gchar *label, - GtkAction *action, - GCallback clicked_cb, - gpointer clicked_cb_user_data) + EUIAction *action) { GtkWidget *button; - gulong clicked_handler = 0; - if (GTK_IS_TOGGLE_ACTION (action)) - button = gtk_toggle_button_new_with_label (label); - else + if (!action) { button = gtk_button_new_with_label (label); + } else if (e_ui_action_get_radio_group (action)) { + button = gtk_toggle_button_new_with_label (label); + } else { + GVariant *state; + + state = g_action_get_state (G_ACTION (action)); + + if (state && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) + button = gtk_toggle_button_new_with_label (label); + else + button = gtk_button_new_with_label (label); + + g_clear_pointer (&state, g_variant_unref); + } gtk_box_pack_start (GTK_BOX (header_bar_button), button, FALSE, FALSE, 0); - if (clicked_cb) { - clicked_handler = g_signal_connect_object ( - button, "clicked", clicked_cb, clicked_cb_user_data, 0); - } - - if (action) { - e_binding_bind_property_full ( - action, "sensitive", - button, "sensitive", - G_BINDING_SYNC_CREATE, - header_bar_button_transform_sensitive_cb, - NULL, NULL, NULL); - - if (GTK_IS_TOGGLE_ACTION (action)) { - ToggleActionData *tad; - - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), - gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); - - tad = g_new0 (ToggleActionData, 1); - tad->button_weakref = e_weak_ref_new (button); - tad->handler_id = clicked_handler; - - g_signal_connect_data (action, "notify::active", - G_CALLBACK (header_button_action_notify_active_cb), tad, toggle_action_data_free, 0); - } - - header_bar_button_update_button_for_action (GTK_BUTTON (button), action); - } + if (action) + header_bar_button_update_button_for_action (header_bar_button, GTK_BUTTON (button), action, header_bar_button->priv->ui_manager); return button; } @@ -298,20 +163,19 @@ header_bar_button_add_action_button (EHeaderBarButton *header_bar_button, static void header_bar_button_add_action (EHeaderBarButton *header_bar_button, const gchar *label, - GtkAction *action, - GCallback clicked_cb, - gpointer clicked_cb_user_data, + EUIAction *action, GtkWidget **out_labeled_button, GtkWidget **out_icon_only_button) { GtkWidget *labeled_button; GtkWidget *icon_only_button; - labeled_button = header_bar_button_add_action_button (header_bar_button, label, action, clicked_cb, clicked_cb_user_data); + labeled_button = header_bar_button_add_action_button (header_bar_button, label, action); if (label) { - icon_only_button = header_bar_button_add_action_button (header_bar_button, NULL, action, clicked_cb, clicked_cb_user_data); + icon_only_button = header_bar_button_add_action_button (header_bar_button, NULL, action); gtk_widget_show (icon_only_button); + gtk_widget_hide (labeled_button); e_binding_bind_property ( labeled_button, "sensitive", @@ -341,6 +205,24 @@ header_bar_button_style_updated (GtkWidget *widget) self->priv->last_icon_only_button_width = -1; } +static void +header_bar_button_show_all (GtkWidget *widget) +{ + /* visibility of the labeled/only-icon buttons already set, thus do not change them both */ +} + +static void +header_bar_button_unmap (GtkWidget *widget) +{ + EHeaderBarButton *self = E_HEADER_BAR_BUTTON (widget); + + /* Chain up to parent's method. */ + GTK_WIDGET_CLASS (e_header_bar_button_parent_class)->unmap (widget); + + self->priv->last_labeled_button_width = -1; + self->priv->last_icon_only_button_width = -1; +} + static void header_bar_button_set_property (GObject *object, guint property_id, @@ -360,9 +242,12 @@ header_bar_button_set_property (GObject *object, header_bar_button->priv->label = g_value_dup_string (value); return; case PROP_ACTION: - header_bar_button->priv->action = g_value_get_object (value); - if (header_bar_button->priv->action != NULL) - g_object_ref (header_bar_button->priv->action); + g_clear_object (&header_bar_button->priv->action); + header_bar_button->priv->action = g_value_dup_object (value); + return; + case PROP_UI_MANAGER: + g_clear_object (&header_bar_button->priv->ui_manager); + header_bar_button->priv->ui_manager = g_value_dup_object (value); return; } @@ -388,6 +273,9 @@ header_bar_button_get_property (GObject *object, case PROP_ACTION: g_value_set_object (value, header_bar_button->priv->action); return; + case PROP_UI_MANAGER: + g_value_set_object (value, header_bar_button->priv->ui_manager); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -405,8 +293,6 @@ header_bar_button_constructed (GObject *object) header_bar_button_add_action (header_bar_button, header_bar_button->priv->label, header_bar_button->priv->action, - G_CALLBACK (header_bar_button_clicked), - header_bar_button, &header_bar_button->priv->labeled_button, &header_bar_button->priv->icon_only_button); @@ -424,8 +310,8 @@ header_bar_button_finalize (GObject *object) g_free (header_bar_button->priv->prefer_item); g_free (header_bar_button->priv->label); - if (header_bar_button->priv->action != NULL) - g_object_unref (header_bar_button->priv->action); + g_clear_object (&header_bar_button->priv->action); + g_clear_object (&header_bar_button->priv->ui_manager); /* Chain up to parent's method. */ G_OBJECT_CLASS (e_header_bar_button_parent_class)->finalize (object); @@ -445,6 +331,8 @@ e_header_bar_button_class_init (EHeaderBarButtonClass *class) widget_class = GTK_WIDGET_CLASS (class); widget_class->style_updated = header_bar_button_style_updated; + widget_class->show_all = header_bar_button_show_all; + widget_class->unmap = header_bar_button_unmap; g_object_class_install_property ( object_class, @@ -473,7 +361,17 @@ e_header_bar_button_class_init (EHeaderBarButtonClass *class) "action", "Action", "Button action", - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property ( + object_class, + PROP_UI_MANAGER, + g_param_spec_object ( + "ui-manager", + "EUIManager", + NULL, + E_TYPE_UI_MANAGER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } @@ -491,7 +389,9 @@ e_header_bar_button_init (EHeaderBarButton *self) /** * e_header_bar_button_new: - * @action: An action overriding menu default action + * @label: a button label + * @action: an #EUIAction overriding menu default action + * @ui_manager: an #EUIManager to get an icon for the @action * * Creates a new #EHeaderBarButton labeled with @label. * If action is %NULL, button will use default preferred menu action if available, @@ -499,15 +399,18 @@ e_header_bar_button_init (EHeaderBarButton *self) * * Returns: (transfer full): a new #EHeaderBarButton * - * Since: 3.46 + * Since: 3.56 **/ -GtkWidget* +GtkWidget * e_header_bar_button_new (const gchar *label, - GtkAction *action) + EUIAction *action, + EUIManager *ui_manager) { return g_object_new (E_TYPE_HEADER_BAR_BUTTON, "label", label, - "action", action, NULL); + "action", action, + "ui-manager", ui_manager, + NULL); } /** @@ -518,18 +421,18 @@ e_header_bar_button_new (const gchar *label, * * Adds a new button with a related action. * - * Since: 3.46 + * Since: 3.56 **/ void e_header_bar_button_add_action (EHeaderBarButton *header_bar_button, const gchar *label, - GtkAction *action) + EUIAction *action) { g_return_if_fail (E_IS_HEADER_BAR_BUTTON (header_bar_button)); - g_return_if_fail (GTK_IS_ACTION (action)); + g_return_if_fail (E_IS_UI_ACTION (action)); header_bar_button_add_action (header_bar_button, label, action, - G_CALLBACK (header_bar_button_action_activate_cb), action, NULL, NULL); + NULL, NULL); } /** @@ -623,7 +526,7 @@ e_header_bar_button_css_add_class (EHeaderBarButton *header_bar_button, **/ void e_header_bar_button_add_accelerator (EHeaderBarButton *header_bar_button, - GtkAccelGroup* accel_group, + GtkAccelGroup *accel_group, guint accel_key, GdkModifierType accel_mods, GtkAccelFlags accel_flags) diff --git a/src/e-util/e-headerbar-button.h b/src/e-util/e-headerbar-button.h index 87a998e9a2..5109104d28 100644 --- a/src/e-util/e-headerbar-button.h +++ b/src/e-util/e-headerbar-button.h @@ -14,6 +14,9 @@ #include +#include +#include + /* Standard GObject macros */ #define E_TYPE_HEADER_BAR_BUTTON \ (e_header_bar_button_get_type ()) @@ -49,11 +52,12 @@ struct _EHeaderBarButtonClass { }; GType e_header_bar_button_get_type (void) G_GNUC_CONST; -GtkWidget* e_header_bar_button_new (const gchar *label, - GtkAction *action); +GtkWidget * e_header_bar_button_new (const gchar *label, + EUIAction *action, + EUIManager *ui_manager); void e_header_bar_button_add_action (EHeaderBarButton *header_bar_button, const gchar *label, - GtkAction *action); + EUIAction *action); void e_header_bar_button_take_menu (EHeaderBarButton *header_bar_button, GtkWidget *menu); void e_header_bar_button_css_add_class (EHeaderBarButton *header_bar_button, diff --git a/src/e-util/e-headerbar.c b/src/e-util/e-headerbar.c index e9c75e57d6..4dfaf77f5c 100644 --- a/src/e-util/e-headerbar.c +++ b/src/e-util/e-headerbar.c @@ -384,6 +384,15 @@ header_bar_realize (GtkWidget *widget) header_bar_update_buttons (E_HEADER_BAR (widget), -1); } +static void +header_bar_map (GtkWidget *widget) +{ + /* Chain up to parent's method. */ + GTK_WIDGET_CLASS (e_header_bar_parent_class)->map (widget); + + header_bar_update_buttons (E_HEADER_BAR (widget), -1); +} + static void header_bar_get_preferred_width (GtkWidget *in_widget, gint *minimum_width, @@ -449,6 +458,8 @@ header_bar_constructed (GObject *object) self->priv->end_buttons = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, BUTTON_SPACING); gtk_header_bar_pack_end (GTK_HEADER_BAR (self), self->priv->end_buttons); gtk_widget_show (self->priv->end_buttons); + + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (self)), "titlebar"); } static void @@ -481,6 +492,7 @@ e_header_bar_class_init (EHeaderBarClass *klass) widget_class = GTK_WIDGET_CLASS (klass); widget_class->size_allocate = header_bar_size_allocate; widget_class->realize = header_bar_realize; + widget_class->map = header_bar_map; widget_class->get_preferred_width = header_bar_get_preferred_width; object_class = G_OBJECT_CLASS (klass); @@ -566,6 +578,38 @@ e_header_bar_pack_end (EHeaderBar *self, header_bar_set_label_priority (self, widget, label_priority); } +/** + * e_header_bar_remove_all: + * @self: an #EHeaderBar + * + * Removes all children of the @self added by e_header_bar_pack_start() + * and e_header_bar_pack_end(). + * + * Since: 3.56 + **/ +void +e_header_bar_remove_all (EHeaderBar *self) +{ + GtkContainer *container; + GList *children, *link; + + g_return_if_fail (E_IS_HEADER_BAR (self)); + + container = GTK_CONTAINER (self->priv->start_buttons); + children = gtk_container_get_children (container); + for (link = children; link; link = g_list_next (link)) { + gtk_container_remove (container, link->data); + } + g_list_free (children); + + container = GTK_CONTAINER (self->priv->end_buttons); + children = gtk_container_get_children (container); + for (link = children; link; link = g_list_next (link)) { + gtk_container_remove (container, link->data); + } + g_list_free (children); +} + /** * e_header_bar_get_start_widgets: * @self: an #EHeaderBar diff --git a/src/e-util/e-headerbar.h b/src/e-util/e-headerbar.h index 92b6b21959..d6bd8f2c72 100644 --- a/src/e-util/e-headerbar.h +++ b/src/e-util/e-headerbar.h @@ -54,6 +54,7 @@ void e_header_bar_pack_start (EHeaderBar *self, void e_header_bar_pack_end (EHeaderBar *self, GtkWidget *widget, guint label_priority); +void e_header_bar_remove_all (EHeaderBar *self); GList * e_header_bar_get_start_widgets (EHeaderBar *self); GList * e_header_bar_get_end_widgets (EHeaderBar *self); diff --git a/src/e-util/e-html-editor-actions.c b/src/e-util/e-html-editor-actions.c index aa80657afc..4f7e11c248 100644 --- a/src/e-util/e-html-editor-actions.c +++ b/src/e-util/e-html-editor-actions.c @@ -27,7 +27,6 @@ #include "e-html-editor.h" #include "e-html-editor-private.h" #include "e-html-editor-actions.h" -#include "e-emoticon-action.h" #include "e-emoticon-chooser.h" #include "e-gtkemojichooser.h" #include "e-image-chooser-dialog.h" @@ -141,9 +140,11 @@ insert_text_file_ready_cb (GFile *file, *****************************************************************************/ static void -action_copy_link_cb (GtkAction *action, - EHTMLEditor *editor) +action_copy_link_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; GtkClipboard *clipboard; if (!editor->priv->context_hover_uri) @@ -159,9 +160,11 @@ action_copy_link_cb (GtkAction *action, } static void -action_open_link_cb (GtkAction *action, - EHTMLEditor *editor) +action_open_link_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; gpointer parent; if (!editor->priv->context_hover_uri) @@ -174,9 +177,11 @@ action_open_link_cb (GtkAction *action, } static void -action_context_delete_cell_contents_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_delete_cell_contents_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -184,9 +189,11 @@ action_context_delete_cell_contents_cb (GtkAction *action, } static void -action_context_delete_column_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_delete_column_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -194,9 +201,11 @@ action_context_delete_column_cb (GtkAction *action, } static void -action_context_delete_row_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_delete_row_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -204,9 +213,11 @@ action_context_delete_row_cb (GtkAction *action, } static void -action_context_delete_table_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_delete_table_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -214,9 +225,11 @@ action_context_delete_table_cb (GtkAction *action, } static void -action_context_delete_hrule_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_delete_hrule_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -224,9 +237,11 @@ action_context_delete_hrule_cb (GtkAction *action, } static void -action_context_delete_image_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_delete_image_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -234,9 +249,11 @@ action_context_delete_image_cb (GtkAction *action, } static void -action_context_insert_column_after_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_insert_column_after_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -244,9 +261,11 @@ action_context_insert_column_after_cb (GtkAction *action, } static void -action_context_insert_column_before_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_insert_column_before_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -254,9 +273,11 @@ action_context_insert_column_before_cb (GtkAction *action, } static void -action_context_insert_row_above_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_insert_row_above_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -264,9 +285,11 @@ action_context_insert_row_above_cb (GtkAction *action, } static void -action_context_insert_row_below_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_insert_row_below_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -274,9 +297,11 @@ action_context_insert_row_below_cb (GtkAction *action, } static void -action_context_remove_link_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_remove_link_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -284,9 +309,11 @@ action_context_remove_link_cb (GtkAction *action, } static void -action_context_spell_add_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_spell_add_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; ESpellChecker *spell_checker; gchar *word; @@ -301,9 +328,46 @@ action_context_spell_add_cb (GtkAction *action, } static void -action_context_spell_ignore_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_spell_add_to_dict_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + EContentEditor *cnt_editor; + ESpellChecker *spell_checker; + ESpellDictionary *dictionary; + GVariant *state; + + state = g_action_get_state (G_ACTION (action)); + g_warn_if_fail (state != NULL); + + if (!state) + return; + + cnt_editor = e_html_editor_get_content_editor (editor); + spell_checker = e_content_editor_ref_spell_checker (cnt_editor); + dictionary = e_spell_checker_ref_dictionary (spell_checker, g_variant_get_string (state, NULL)); + + if (dictionary) { + gchar *word; + + word = e_content_editor_get_caret_word (cnt_editor); + if (word && *word) + e_spell_dictionary_learn_word (dictionary, word, -1); + g_free (word); + } + + g_clear_object (&dictionary); + g_clear_object (&spell_checker); + g_variant_unref (state); +} + +static void +action_context_spell_ignore_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; ESpellChecker *spell_checker; gchar *word; @@ -318,9 +382,11 @@ action_context_spell_ignore_cb (GtkAction *action, } static void -action_indent_cb (GtkAction *action, - EHTMLEditor *editor) +action_indent_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -344,9 +410,11 @@ emoji_chooser_emoji_picked_cb (EHTMLEditor *editor, } static void -action_insert_emoji_cb (GtkAction *action, - EHTMLEditor *editor) +action_insert_emoji_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; GtkPopover *popover; GtkWidget *relative_to; @@ -387,13 +455,20 @@ action_insert_emoji_cb (GtkAction *action, } static void -action_insert_emoticon_cb (GtkAction *action, - EHTMLEditor *editor) +action_insert_emoticon_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; - EEmoticon *emoticon; + const EEmoticon *emoticon; + const gchar *icon_name; + + g_return_if_fail (parameter != NULL); + + icon_name = g_variant_get_string (parameter, NULL); + emoticon = e_emoticon_chooser_lookup_emoticon (icon_name); - emoticon = e_emoticon_chooser_get_current_emoticon (E_EMOTICON_CHOOSER (action)); g_return_if_fail (emoticon != NULL); cnt_editor = e_html_editor_get_content_editor (editor); @@ -401,9 +476,11 @@ action_insert_emoticon_cb (GtkAction *action, } static void -action_insert_html_file_cb (GtkToggleAction *action, - EHTMLEditor *editor) +action_insert_html_file_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; GtkFileChooserNative *native; GtkFileFilter *filter; GtkWidget *toplevel; @@ -441,9 +518,11 @@ action_insert_html_file_cb (GtkToggleAction *action, } static void -action_insert_image_cb (GtkAction *action, - EHTMLEditor *editor) +action_insert_image_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; GtkWidget *dialog = NULL; GtkFileChooserNative *native = NULL; GtkWidget *toplevel; @@ -515,9 +594,12 @@ action_insert_image_cb (GtkAction *action, } static void -action_insert_link_cb (GtkAction *action, - EHTMLEditor *editor) +action_insert_link_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (!editor->priv->link_popover) editor->priv->link_popover = e_html_editor_link_popover_new (editor); @@ -525,9 +607,12 @@ action_insert_link_cb (GtkAction *action, } static void -action_insert_rule_cb (GtkAction *action, - EHTMLEditor *editor) +action_insert_rule_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->hrule_dialog == NULL) editor->priv->hrule_dialog = e_html_editor_hrule_dialog_new (editor); @@ -536,9 +621,12 @@ action_insert_rule_cb (GtkAction *action, } static void -action_insert_table_cb (GtkAction *action, - EHTMLEditor *editor) +action_insert_table_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->table_dialog == NULL) editor->priv->table_dialog = e_html_editor_table_dialog_new (editor); @@ -547,9 +635,11 @@ action_insert_table_cb (GtkAction *action, } static void -action_insert_text_file_cb (GtkAction *action, - EHTMLEditor *editor) +action_insert_text_file_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; GtkFileChooserNative *native; GtkWidget *toplevel; GtkFileFilter *filter; @@ -591,29 +681,32 @@ editor_actions_add_to_recent_languages (EHTMLEditor *editor, const gchar *language_code); static void -action_language_cb (GtkToggleAction *toggle_action, - EHTMLEditor *editor) +action_language_notify_active_cb (EUIAction *action, + GParamSpec *param, + gpointer user_data) { + EHTMLEditor *editor = user_data; ESpellChecker *spell_checker; EContentEditor *cnt_editor; const gchar *language_code; - GtkAction *add_action; - gchar *action_name; + EUIAction *add_action; + gchar action_name[128]; gboolean active; + e_ui_menu_freeze (editor->priv->main_menu); + cnt_editor = e_html_editor_get_content_editor (editor); spell_checker = e_content_editor_ref_spell_checker (cnt_editor); - language_code = gtk_action_get_name (GTK_ACTION (toggle_action)); + language_code = g_action_get_name (G_ACTION (action)); - active = gtk_toggle_action_get_active (toggle_action); + active = e_ui_action_get_active (action); e_spell_checker_set_language_active (spell_checker, language_code, active); g_clear_object (&spell_checker); /* Update "Add Word To" context menu item visibility. */ - action_name = g_strdup_printf ("context-spell-add-%s", language_code); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "context-spell-add-%s", language_code) < sizeof (action_name)); add_action = e_html_editor_get_action (editor, action_name); - gtk_action_set_visible (add_action, active); - g_free (action_name); + e_ui_action_set_visible (add_action, active); e_html_editor_update_spell_actions (editor); @@ -625,7 +718,7 @@ action_language_cb (GtkToggleAction *toggle_action, gchar **strv; gint ii, max_items; - gtk_ui_manager_remove_ui (editor->priv->manager, editor->priv->recent_spell_languages_merge_id); + g_menu_remove_all (editor->priv->recent_languages_menu); settings = e_util_ref_settings ("org.gnome.evolution.mail"); strv = g_settings_get_strv (settings, "composer-spell-languages-recently-used"); @@ -653,6 +746,8 @@ action_language_cb (GtkToggleAction *toggle_action, g_ptr_array_free (array, TRUE); g_strfreev (strv); } + + e_ui_menu_thaw (editor->priv->main_menu); } static gboolean @@ -661,7 +756,7 @@ update_mode_combobox (gpointer data) GWeakRef *weak_ref = data; EHTMLEditor *editor; EContentEditorMode mode; - GtkAction *action; + EUIAction *action; editor = g_weak_ref_get (weak_ref); if (!editor) @@ -669,8 +764,8 @@ update_mode_combobox (gpointer data) mode = e_html_editor_get_mode (editor); - action = gtk_action_group_get_action (editor->priv->core_editor_actions, "mode-html"); - gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), mode); + action = e_ui_action_group_get_action (editor->priv->core_editor_actions, "mode-html"); + e_ui_action_set_state (action, g_variant_new_int32 (mode)); g_object_unref (editor); @@ -682,28 +777,22 @@ html_editor_actions_notify_mode_cb (EHTMLEditor *editor, GParamSpec *param, gpointer user_data) { - GtkActionGroup *action_group; - GtkWidget *style_combo_box; gboolean is_html; g_return_if_fail (E_IS_HTML_EDITOR (editor)); is_html = e_html_editor_get_mode (editor) == E_CONTENT_EDITOR_MODE_HTML; + e_ui_manager_freeze (editor->priv->ui_manager); + g_object_set (G_OBJECT (editor->priv->html_actions), "sensitive", is_html, NULL); /* This must be done from idle callback, because apparently we can change * current value in callback of current value change */ g_idle_add_full (G_PRIORITY_HIGH_IDLE, update_mode_combobox, e_weak_ref_new (editor), (GDestroyNotify) e_weak_ref_free); - action_group = editor->priv->html_actions; - gtk_action_group_set_visible (action_group, is_html); - - action_group = editor->priv->html_context_actions; - gtk_action_group_set_visible (action_group, is_html); - - gtk_widget_set_sensitive (editor->priv->fg_color_combo_box, is_html); - gtk_widget_set_sensitive (editor->priv->bg_color_combo_box, is_html); + e_ui_action_group_set_visible (editor->priv->html_actions, is_html); + e_ui_action_group_set_visible (editor->priv->html_context_actions, is_html); if (is_html && gtk_widget_get_visible (editor->priv->edit_toolbar)) { gtk_widget_show (editor->priv->html_toolbar); @@ -712,33 +801,24 @@ html_editor_actions_notify_mode_cb (EHTMLEditor *editor, } /* Certain paragraph styles are HTML-only. */ - gtk_action_set_sensitive (ACTION (STYLE_H1), is_html); - gtk_action_set_visible (ACTION (STYLE_H1), is_html); - gtk_action_set_sensitive (ACTION (STYLE_H2), is_html); - gtk_action_set_visible (ACTION (STYLE_H2), is_html); - gtk_action_set_sensitive (ACTION (STYLE_H3), is_html); - gtk_action_set_visible (ACTION (STYLE_H3), is_html); - gtk_action_set_sensitive (ACTION (STYLE_H4), is_html); - gtk_action_set_visible (ACTION (STYLE_H4), is_html); - gtk_action_set_sensitive (ACTION (STYLE_H5), is_html); - gtk_action_set_visible (ACTION (STYLE_H5), is_html); - gtk_action_set_sensitive (ACTION (STYLE_H6), is_html); - gtk_action_set_visible (ACTION (STYLE_H6), is_html); - gtk_action_set_sensitive (ACTION (STYLE_ADDRESS), is_html); - gtk_action_set_visible (ACTION (STYLE_ADDRESS), is_html); + e_ui_action_set_sensitive (ACTION (STYLE_H1), is_html); + e_ui_action_set_visible (ACTION (STYLE_H1), is_html); + e_ui_action_set_sensitive (ACTION (STYLE_H2), is_html); + e_ui_action_set_visible (ACTION (STYLE_H2), is_html); + e_ui_action_set_sensitive (ACTION (STYLE_H3), is_html); + e_ui_action_set_visible (ACTION (STYLE_H3), is_html); + e_ui_action_set_sensitive (ACTION (STYLE_H4), is_html); + e_ui_action_set_visible (ACTION (STYLE_H4), is_html); + e_ui_action_set_sensitive (ACTION (STYLE_H5), is_html); + e_ui_action_set_visible (ACTION (STYLE_H5), is_html); + e_ui_action_set_sensitive (ACTION (STYLE_H6), is_html); + e_ui_action_set_visible (ACTION (STYLE_H6), is_html); + e_ui_action_set_sensitive (ACTION (STYLE_ADDRESS), is_html); + e_ui_action_set_visible (ACTION (STYLE_ADDRESS), is_html); - /* Hide them from the action combo box as well */ - style_combo_box = e_html_editor_get_style_combo_box (editor); - e_action_combo_box_update_model (E_ACTION_COMBO_BOX (style_combo_box)); -} + e_html_editor_emit_after_mode_changed (editor); -static void -action_mode_cb (GtkRadioAction *action, - GtkRadioAction *current, - EHTMLEditor *editor) -{ - /* Nothing to do here, wait for notification of - a property change from the EContentEditor */ + e_ui_manager_thaw (editor->priv->ui_manager); } static void @@ -761,9 +841,11 @@ clipboard_text_received_for_paste_as_text (GtkClipboard *clipboard, } static void -action_paste_as_text_cb (GtkAction *action, - EHTMLEditor *editor) +action_paste_as_text_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; GtkClipboard *clipboard; @@ -827,9 +909,11 @@ clipboard_text_received_for_paste_quote (GtkClipboard *clipboard, } static void -action_paste_quote_cb (GtkAction *action, - EHTMLEditor *editor) +action_paste_quote_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; GtkClipboard *clipboard; @@ -855,9 +939,12 @@ action_paste_quote_cb (GtkAction *action, } static void -action_properties_cell_cb (GtkAction *action, - EHTMLEditor *editor) +action_properties_cell_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->cell_dialog == NULL) { editor->priv->cell_dialog = e_html_editor_cell_dialog_new (editor); @@ -867,9 +954,12 @@ action_properties_cell_cb (GtkAction *action, } static void -action_properties_image_cb (GtkAction *action, - EHTMLEditor *editor) +action_properties_image_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->image_dialog == NULL) { editor->priv->image_dialog = e_html_editor_image_dialog_new (editor); @@ -880,9 +970,12 @@ action_properties_image_cb (GtkAction *action, } static void -action_properties_link_cb (GtkAction *action, - EHTMLEditor *editor) +action_properties_link_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (!editor->priv->link_popover) editor->priv->link_popover = e_html_editor_link_popover_new (editor); @@ -890,9 +983,12 @@ action_properties_link_cb (GtkAction *action, } static void -action_properties_page_cb (GtkAction *action, - EHTMLEditor *editor) +action_properties_page_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->page_dialog == NULL) { editor->priv->page_dialog = e_html_editor_page_dialog_new (editor); @@ -902,9 +998,12 @@ action_properties_page_cb (GtkAction *action, } static void -action_properties_paragraph_cb (GtkAction *action, - EHTMLEditor *editor) +action_properties_paragraph_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->paragraph_dialog == NULL) { editor->priv->paragraph_dialog = e_html_editor_paragraph_dialog_new (editor); @@ -914,9 +1013,12 @@ action_properties_paragraph_cb (GtkAction *action, } static void -action_properties_rule_cb (GtkAction *action, - EHTMLEditor *editor) +action_properties_rule_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->hrule_dialog == NULL) { editor->priv->hrule_dialog = e_html_editor_hrule_dialog_new (editor); @@ -926,9 +1028,12 @@ action_properties_rule_cb (GtkAction *action, } static void -action_properties_table_cb (GtkAction *action, - EHTMLEditor *editor) +action_properties_table_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->table_dialog == NULL) { editor->priv->table_dialog = e_html_editor_table_dialog_new (editor); @@ -938,9 +1043,12 @@ action_properties_table_cb (GtkAction *action, } static void -action_properties_text_cb (GtkAction *action, - EHTMLEditor *editor) +action_properties_text_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->text_dialog == NULL) { editor->priv->text_dialog = e_html_editor_text_dialog_new (editor); @@ -950,9 +1058,11 @@ action_properties_text_cb (GtkAction *action, } static void -action_redo_cb (GtkAction *action, - EHTMLEditor *editor) +action_redo_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -961,21 +1071,27 @@ action_redo_cb (GtkAction *action, } static void -action_show_find_cb (GtkAction *action, - EHTMLEditor *editor) +action_show_find_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->find_dialog == NULL) { editor->priv->find_dialog = e_html_editor_find_dialog_new (editor); - gtk_action_set_sensitive (ACTION (FIND_AGAIN), TRUE); + e_ui_action_set_sensitive (ACTION (FIND_AGAIN), TRUE); } gtk_window_present (GTK_WINDOW (editor->priv->find_dialog)); } static void -action_find_again_cb (GtkAction *action, - EHTMLEditor *editor) +action_find_again_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->find_dialog == NULL) return; @@ -984,9 +1100,12 @@ action_find_again_cb (GtkAction *action, } static void -action_show_replace_cb (GtkAction *action, - EHTMLEditor *editor) +action_show_replace_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->replace_dialog == NULL) { editor->priv->replace_dialog = e_html_editor_replace_dialog_new (editor); @@ -996,9 +1115,12 @@ action_show_replace_cb (GtkAction *action, } static void -action_spell_check_cb (GtkAction *action, - EHTMLEditor *editor) +action_spell_check_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + if (editor->priv->spell_check_dialog == NULL) { editor->priv->spell_check_dialog = e_html_editor_spell_check_dialog_new (editor); @@ -1008,9 +1130,11 @@ action_spell_check_cb (GtkAction *action, } static void -action_undo_cb (GtkAction *action, - EHTMLEditor *editor) +action_undo_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -1020,9 +1144,11 @@ action_undo_cb (GtkAction *action, } static void -action_unindent_cb (GtkAction *action, - EHTMLEditor *editor) +action_unindent_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -1031,9 +1157,11 @@ action_unindent_cb (GtkAction *action, } static void -action_wrap_lines_cb (GtkAction *action, - EHTMLEditor *editor) +action_wrap_lines_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; cnt_editor = e_html_editor_get_content_editor (editor); @@ -1044,9 +1172,9 @@ action_wrap_lines_cb (GtkAction *action, /* This is when the user toggled the action */ static void manage_format_subsuperscript_toggled (EHTMLEditor *editor, - GtkToggleAction *changed_action, + EUIAction *changed_action, const gchar *prop_name, - GtkToggleAction *second_action) + EUIAction *second_action) { EContentEditor *cnt_editor = e_html_editor_get_content_editor (editor); @@ -1054,11 +1182,11 @@ manage_format_subsuperscript_toggled (EHTMLEditor *editor, g_signal_handlers_block_matched (changed_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor); g_signal_handlers_block_matched (second_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor); - if (gtk_toggle_action_get_active (changed_action) && - gtk_toggle_action_get_active (second_action)) - gtk_toggle_action_set_active (second_action, FALSE); + if (e_ui_action_get_active (changed_action) && + e_ui_action_get_active (second_action)) + e_ui_action_set_active (second_action, FALSE); - g_object_set (G_OBJECT (cnt_editor), prop_name, gtk_toggle_action_get_active (changed_action), NULL); + g_object_set (G_OBJECT (cnt_editor), prop_name, e_ui_action_get_active (changed_action), NULL); g_signal_handlers_unblock_matched (second_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor); g_signal_handlers_unblock_matched (changed_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor); @@ -1068,9 +1196,9 @@ manage_format_subsuperscript_toggled (EHTMLEditor *editor, /* This is when the content editor claimed change on the property */ static void manage_format_subsuperscript_notify (EHTMLEditor *editor, - GtkToggleAction *changed_action, + EUIAction *changed_action, const gchar *prop_name, - GtkToggleAction *second_action) + EUIAction *second_action) { EContentEditor *cnt_editor = e_html_editor_get_content_editor (editor); gboolean value = FALSE; @@ -1081,11 +1209,11 @@ manage_format_subsuperscript_notify (EHTMLEditor *editor, g_object_get (G_OBJECT (cnt_editor), prop_name, &value, NULL); - gtk_toggle_action_set_active (changed_action, value); + e_ui_action_set_active (changed_action, value); - if (gtk_toggle_action_get_active (changed_action) && - gtk_toggle_action_get_active (second_action)) - gtk_toggle_action_set_active (second_action, FALSE); + if (e_ui_action_get_active (changed_action) && + e_ui_action_get_active (second_action)) + e_ui_action_set_active (second_action, FALSE); g_signal_handlers_unblock_matched (second_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor); g_signal_handlers_unblock_matched (changed_action, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor); @@ -1093,12 +1221,15 @@ manage_format_subsuperscript_notify (EHTMLEditor *editor, } static void -html_editor_actions_subscript_toggled_cb (GtkToggleAction *action, - EHTMLEditor *editor) +html_editor_actions_subscript_toggled_cb (EUIAction *action, + GParamSpec *param, + gpointer user_data) { + EHTMLEditor *editor = user_data; + g_return_if_fail (E_IS_HTML_EDITOR (editor)); - manage_format_subsuperscript_toggled (editor, GTK_TOGGLE_ACTION (ACTION (SUBSCRIPT)), "subscript", GTK_TOGGLE_ACTION (ACTION (SUPERSCRIPT))); + manage_format_subsuperscript_toggled (editor, ACTION (SUBSCRIPT), "subscript", ACTION (SUPERSCRIPT)); } static void @@ -1108,16 +1239,19 @@ html_editor_actions_notify_subscript_cb (EContentEditor *cnt_editor, { g_return_if_fail (E_IS_HTML_EDITOR (editor)); - manage_format_subsuperscript_notify (editor, GTK_TOGGLE_ACTION (ACTION (SUBSCRIPT)), "subscript", GTK_TOGGLE_ACTION (ACTION (SUPERSCRIPT))); + manage_format_subsuperscript_notify (editor, ACTION (SUBSCRIPT), "subscript", ACTION (SUPERSCRIPT)); } static void -html_editor_actions_superscript_toggled_cb (GtkToggleAction *action, - EHTMLEditor *editor) +html_editor_actions_superscript_toggled_cb (EUIAction *action, + GParamSpec *param, + gpointer user_data) { + EHTMLEditor *editor = user_data; + g_return_if_fail (E_IS_HTML_EDITOR (editor)); - manage_format_subsuperscript_toggled (editor, GTK_TOGGLE_ACTION (ACTION (SUPERSCRIPT)), "superscript", GTK_TOGGLE_ACTION (ACTION (SUBSCRIPT))); + manage_format_subsuperscript_toggled (editor, ACTION (SUPERSCRIPT), "superscript", ACTION (SUBSCRIPT)); } static void @@ -1127,7 +1261,7 @@ html_editor_actions_notify_superscript_cb (EContentEditor *cnt_editor, { g_return_if_fail (E_IS_HTML_EDITOR (editor)); - manage_format_subsuperscript_notify (editor, GTK_TOGGLE_ACTION (ACTION (SUPERSCRIPT)), "superscript", GTK_TOGGLE_ACTION (ACTION (SUBSCRIPT))); + manage_format_subsuperscript_notify (editor, ACTION (SUPERSCRIPT), "superscript", ACTION (SUBSCRIPT)); } @@ -1137,49 +1271,49 @@ html_editor_actions_notify_superscript_cb (EContentEditor *cnt_editor, * These actions are always enabled. *****************************************************************************/ -static GtkActionEntry core_entries[] = { +static const EUIActionEntry core_entries[] = { { "copy", "edit-copy", N_("_Copy"), "c", N_("Copy selected text to the clipboard"), - NULL }, /* Handled by focus tracker */ + NULL, NULL, NULL, NULL }, /* Handled by focus tracker */ { "cut", "edit-cut", N_("Cu_t"), "x", N_("Cut selected text to the clipboard"), - NULL }, /* Handled by focus tracker */ + NULL, NULL, NULL, NULL }, /* Handled by focus tracker */ { "paste", "edit-paste", N_("_Paste"), "v", N_("Paste text from the clipboard"), - NULL }, /* Handled by focus tracker */ + NULL, NULL, NULL, NULL }, /* Handled by focus tracker */ { "redo", "edit-redo", N_("_Redo"), "z", N_("Redo the last undone action"), - G_CALLBACK (action_redo_cb) }, + action_redo_cb, NULL, NULL, NULL }, { "select-all", "edit-select-all", N_("Select _All"), "a", NULL, - NULL }, /* Handled by focus tracker */ + NULL, NULL, NULL, NULL }, /* Handled by focus tracker */ { "undo", "edit-undo", N_("_Undo"), "z", N_("Undo the last action"), - G_CALLBACK (action_undo_cb) }, + action_undo_cb, NULL, NULL, NULL }, /* Menus */ @@ -1188,306 +1322,371 @@ static GtkActionEntry core_entries[] = { N_("_Edit"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "file-menu", NULL, N_("_File"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "format-menu", NULL, N_("For_mat"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "paragraph-style-menu", NULL, N_("_Paragraph Style"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "insert-menu", NULL, N_("_Insert"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "justify-menu", NULL, N_("_Alignment"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "language-menu", NULL, N_("Current _Languages"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "view-menu", NULL, N_("_View"), NULL, NULL, - NULL } + NULL, NULL, NULL, NULL }, + + /* fake actions, related to dynamic items */ + + { "EHTMLEditor::recent-languages", + NULL, + N_("Recent spell check languages"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, + + { "EHTMLEditor::all-languages", + NULL, + N_("All spell check languages"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, + + { "EHTMLEditor::editing-mode", + NULL, + N_("Editing Mode"), + NULL, + N_("Editing Mode"), + NULL, NULL, NULL, NULL }, + + { "EHTMLEditor::paragraph-style", + NULL, + N_("Paragraph Style"), + NULL, + N_("Paragraph Style"), + NULL, NULL, NULL, NULL }, + + { "EHTMLEditor::font-name", + NULL, + N_("Font Name"), + NULL, + N_("Font Name"), + NULL, NULL, NULL, NULL }, + + { "EHTMLEditor::font-size", + NULL, + N_("Font Size"), + NULL, + N_("Font Size"), + NULL, NULL, NULL, NULL }, + + { "EHTMLEditor::font-color", + NULL, + N_("Font Color"), + NULL, + N_("Font Color"), + NULL, NULL, NULL, NULL }, + + { "EHTMLEditor::background-color", + NULL, + N_("Background Color"), + NULL, + N_("Background Color"), + NULL, NULL, NULL, NULL } }; -static GtkActionEntry core_editor_entries[] = { +static const EUIActionEntry core_editor_entries[] = { { "indent", "format-indent-more", N_("_Increase Indent"), "bracketright", N_("Increase Indent"), - G_CALLBACK (action_indent_cb) }, + action_indent_cb, NULL, NULL, NULL }, { "insert-emoji", NULL, N_("E_moji"), NULL, N_("Insert Emoji"), - G_CALLBACK (action_insert_emoji_cb) }, + action_insert_emoji_cb, NULL, NULL, NULL }, + + { "EHTMLEditor::insert-emoticon", + "face-smile", + N_("_Emoticon"), + NULL, + N_("Insert Emoticon"), + action_insert_emoticon_cb, "s", NULL, NULL }, { "insert-emoji-toolbar", "face-smile", N_("Insert E_moji"), NULL, N_("Insert Emoji"), - G_CALLBACK (action_insert_emoji_cb) }, + action_insert_emoji_cb, NULL, NULL, NULL }, { "insert-html-file", NULL, N_("_HTML File…"), NULL, NULL, - G_CALLBACK (action_insert_html_file_cb) }, + action_insert_html_file_cb, NULL, NULL, NULL }, { "insert-text-file", NULL, N_("Te_xt File…"), NULL, NULL, - G_CALLBACK (action_insert_text_file_cb) }, + action_insert_text_file_cb, NULL, NULL, NULL }, { "paste-quote", NULL, N_("Paste _Quotation"), "v", NULL, - G_CALLBACK (action_paste_quote_cb) }, + action_paste_quote_cb, NULL, NULL, NULL }, { "show-find", "edit-find", N_("_Find…"), "f", N_("Search for text"), - G_CALLBACK (action_show_find_cb) }, + action_show_find_cb, NULL, NULL, NULL }, { "find-again", NULL, N_("Find A_gain"), "g", NULL, - G_CALLBACK (action_find_again_cb) }, + action_find_again_cb, NULL, NULL, NULL }, { "show-replace", "edit-find-replace", N_("Re_place…"), "h", N_("Search for and replace text"), - G_CALLBACK (action_show_replace_cb) }, + action_show_replace_cb, NULL, NULL, NULL }, { "spell-check", "tools-check-spelling", N_("Check _Spelling…"), "F7", NULL, - G_CALLBACK (action_spell_check_cb) }, + action_spell_check_cb, NULL, NULL, NULL }, { "unindent", "format-indent-less", N_("_Decrease Indent"), "bracketleft", N_("Decrease Indent"), - G_CALLBACK (action_unindent_cb) }, + action_unindent_cb, NULL, NULL, NULL }, { "wrap-lines", NULL, N_("_Wrap Lines"), "k", NULL, - G_CALLBACK (action_wrap_lines_cb) } + action_wrap_lines_cb, NULL, NULL, NULL } }; -static GtkRadioActionEntry core_justify_entries[] = { +static const EUIActionEnumEntry core_justify_entries[] = { { "justify-center", "format-justify-center", N_("_Center"), "e", N_("Center Alignment"), - E_CONTENT_EDITOR_ALIGNMENT_CENTER }, + NULL, E_CONTENT_EDITOR_ALIGNMENT_CENTER }, { "justify-fill", "format-justify-fill", N_("_Justified"), "j", N_("Align Justified"), - E_CONTENT_EDITOR_ALIGNMENT_JUSTIFY }, + NULL, E_CONTENT_EDITOR_ALIGNMENT_JUSTIFY }, { "justify-left", "format-justify-left", N_("_Left"), "l", N_("Left Alignment"), - E_CONTENT_EDITOR_ALIGNMENT_LEFT }, + NULL, E_CONTENT_EDITOR_ALIGNMENT_LEFT }, { "justify-right", "format-justify-right", N_("_Right"), "r", N_("Right Alignment"), - E_CONTENT_EDITOR_ALIGNMENT_RIGHT } + NULL, E_CONTENT_EDITOR_ALIGNMENT_RIGHT } }; -static GtkRadioActionEntry core_mode_entries[] = { +static const EUIActionEnumEntry core_mode_entries[] = { { "mode-html", NULL, N_("_HTML"), NULL, N_("HTML editing mode"), - E_CONTENT_EDITOR_MODE_HTML }, + NULL, E_CONTENT_EDITOR_MODE_HTML }, { "mode-plain", NULL, N_("Plain _Text"), NULL, N_("Plain text editing mode"), - E_CONTENT_EDITOR_MODE_PLAIN_TEXT }, + NULL, E_CONTENT_EDITOR_MODE_PLAIN_TEXT }, { "mode-markdown", NULL, N_("_Markdown"), NULL, N_("Markdown editing mode"), - E_CONTENT_EDITOR_MODE_MARKDOWN }, + NULL, E_CONTENT_EDITOR_MODE_MARKDOWN }, { "mode-markdown-plain", NULL, N_("Ma_rkdown as Plain Text"), NULL, N_("Markdown editing mode, exported as Plain Text"), - E_CONTENT_EDITOR_MODE_MARKDOWN_PLAIN_TEXT }, + NULL, E_CONTENT_EDITOR_MODE_MARKDOWN_PLAIN_TEXT }, { "mode-markdown-html", NULL, N_("Mar_kdown as HTML"), NULL, N_("Markdown editing mode, exported as HTML"), - E_CONTENT_EDITOR_MODE_MARKDOWN_HTML } + NULL, E_CONTENT_EDITOR_MODE_MARKDOWN_HTML } }; -static GtkRadioActionEntry core_style_entries[] = { +static const EUIActionEnumEntry core_style_entries[] = { { "style-normal", NULL, N_("_Normal"), "0", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH }, { "style-h1", NULL, N_("Heading _1"), "1", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_H1 }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_H1 }, { "style-h2", NULL, N_("Heading _2"), "2", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_H2 }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_H2 }, { "style-h3", NULL, N_("Heading _3"), "3", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_H3 }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_H3 }, { "style-h4", NULL, N_("Heading _4"), "4", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_H4 }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_H4 }, { "style-h5", NULL, N_("Heading _5"), "5", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_H5 }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_H5 }, { "style-h6", NULL, N_("Heading _6"), "6", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_H6 }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_H6 }, { "style-preformat", NULL, N_("_Preformatted"), "7", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_PRE }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_PRE }, { "style-address", NULL, N_("A_ddress"), "8", NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS }, { "style-list-bullet", NULL, N_("_Bulleted List"), NULL, NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST }, { "style-list-roman", NULL, N_("_Roman Numeral List"), NULL, NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN }, { "style-list-number", NULL, N_("Numbered _List"), NULL, NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST }, + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST }, { "style-list-alpha", NULL, N_("_Alphabetical List"), NULL, NULL, - E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA } + NULL, E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA } }; /***************************************************************************** @@ -1496,7 +1695,7 @@ static GtkRadioActionEntry core_style_entries[] = { * These actions are only enabled in HTML mode. *****************************************************************************/ -static GtkActionEntry html_entries[] = { +static const EUIActionEntry html_entries[] = { { "insert-image", "insert-image", @@ -1504,14 +1703,14 @@ static GtkActionEntry html_entries[] = { NULL, /* Translators: This is an action tooltip */ N_("Insert Image"), - G_CALLBACK (action_insert_image_cb) }, + action_insert_image_cb, NULL, NULL, NULL }, { "insert-link", "insert-link", N_("_Link…"), "k", N_("Insert Link"), - G_CALLBACK (action_insert_link_cb) }, + action_insert_link_cb, NULL, NULL, NULL }, { "insert-rule", "stock_insert-rule", @@ -1520,42 +1719,42 @@ static GtkActionEntry html_entries[] = { NULL, /* Translators: 'Rule' here means a horizontal line in an HTML text */ N_("Insert Rule"), - G_CALLBACK (action_insert_rule_cb) }, + action_insert_rule_cb, NULL, NULL, NULL }, { "insert-table", "stock_insert-table", N_("_Table…"), NULL, N_("Insert Table"), - G_CALLBACK (action_insert_table_cb) }, + action_insert_table_cb, NULL, NULL, NULL }, { "properties-cell", NULL, N_("_Cell…"), NULL, NULL, - G_CALLBACK (action_properties_cell_cb) }, + action_properties_cell_cb, NULL, NULL, NULL }, { "properties-image", NULL, N_("_Image…"), NULL, NULL, - G_CALLBACK (action_properties_image_cb) }, + action_properties_image_cb, NULL, NULL, NULL }, { "properties-link", NULL, N_("_Link…"), NULL, NULL, - G_CALLBACK (action_properties_link_cb) }, + action_properties_link_cb, NULL, NULL, NULL }, { "properties-page", NULL, N_("Pa_ge…"), NULL, NULL, - G_CALLBACK (action_properties_page_cb) }, + action_properties_page_cb, NULL, NULL, NULL }, { "properties-rule", NULL, @@ -1563,14 +1762,14 @@ static GtkActionEntry html_entries[] = { N_("_Rule…"), NULL, NULL, - G_CALLBACK (action_properties_rule_cb) }, + action_properties_rule_cb, NULL, NULL, NULL }, { "properties-table", NULL, N_("_Table…"), NULL, NULL, - G_CALLBACK (action_properties_table_cb) }, + action_properties_table_cb, NULL, NULL, NULL }, /* Menus */ @@ -1579,76 +1778,70 @@ static GtkActionEntry html_entries[] = { N_("Font _Size"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "font-style-menu", NULL, N_("_Font Style"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "paste-as-text", NULL, N_("Paste As _Text"), "v", NULL, - G_CALLBACK (action_paste_as_text_cb) }, + action_paste_as_text_cb, NULL, NULL, NULL }, }; -static GtkToggleActionEntry html_toggle_entries[] = { +static const EUIActionEntry html_toggle_entries[] = { { "bold", "format-text-bold", N_("_Bold"), "b", N_("Bold"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "italic", "format-text-italic", N_("_Italic"), "i", N_("Italic"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "strikethrough", "format-text-strikethrough", N_("_Strikethrough"), NULL, N_("Strikethrough"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "subscript", NULL, N_("Subs_cript"), "b", N_("Subscript"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "superscript", NULL, N_("Su_perscript"), "p", N_("Superscript"), - NULL, - FALSE }, + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state }, { "underline", "format-text-underline", N_("_Underline"), "u", N_("Underline"), - NULL, - FALSE } + NULL, NULL, "false", (EUIActionFunc) e_ui_action_set_state } }; -static GtkRadioActionEntry html_size_entries[] = { +static const EUIActionEnumEntry html_size_entries[] = { { "size-minus-two", NULL, @@ -1656,7 +1849,7 @@ static GtkRadioActionEntry html_size_entries[] = { N_("-2"), NULL, NULL, - E_CONTENT_EDITOR_FONT_SIZE_TINY }, + NULL, E_CONTENT_EDITOR_FONT_SIZE_TINY }, { "size-minus-one", NULL, @@ -1664,7 +1857,7 @@ static GtkRadioActionEntry html_size_entries[] = { N_("-1"), NULL, NULL, - E_CONTENT_EDITOR_FONT_SIZE_SMALL }, + NULL, E_CONTENT_EDITOR_FONT_SIZE_SMALL }, { "size-plus-zero", NULL, @@ -1672,7 +1865,7 @@ static GtkRadioActionEntry html_size_entries[] = { N_("+0"), NULL, NULL, - E_CONTENT_EDITOR_FONT_SIZE_NORMAL }, + NULL, E_CONTENT_EDITOR_FONT_SIZE_NORMAL }, { "size-plus-one", NULL, @@ -1680,7 +1873,7 @@ static GtkRadioActionEntry html_size_entries[] = { N_("+1"), NULL, NULL, - E_CONTENT_EDITOR_FONT_SIZE_BIG }, + NULL, E_CONTENT_EDITOR_FONT_SIZE_BIG }, { "size-plus-two", NULL, @@ -1688,7 +1881,7 @@ static GtkRadioActionEntry html_size_entries[] = { N_("+2"), NULL, NULL, - E_CONTENT_EDITOR_FONT_SIZE_BIGGER }, + NULL, E_CONTENT_EDITOR_FONT_SIZE_BIGGER }, { "size-plus-three", NULL, @@ -1696,7 +1889,7 @@ static GtkRadioActionEntry html_size_entries[] = { N_("+3"), NULL, NULL, - E_CONTENT_EDITOR_FONT_SIZE_LARGE }, + NULL, E_CONTENT_EDITOR_FONT_SIZE_LARGE }, { "size-plus-four", NULL, @@ -1704,7 +1897,7 @@ static GtkRadioActionEntry html_size_entries[] = { N_("+4"), NULL, NULL, - E_CONTENT_EDITOR_FONT_SIZE_VERY_LARGE } + NULL, E_CONTENT_EDITOR_FONT_SIZE_VERY_LARGE } }; /***************************************************************************** @@ -1716,49 +1909,49 @@ static GtkRadioActionEntry html_size_entries[] = { * non-context sensitive counterparts. *****************************************************************************/ -static GtkActionEntry context_entries[] = { +static const EUIActionEntry context_entries[] = { { "context-copy-link", "edit-copy", N_("Copy _Link Location"), NULL, N_("Copy the link to the clipboard"), - G_CALLBACK (action_copy_link_cb) }, + action_copy_link_cb, NULL, NULL, NULL }, { "context-open-link", "emblem-web", N_("_Open Link in Browser"), NULL, N_("Open the link in a web browser"), - G_CALLBACK (action_open_link_cb) }, + action_open_link_cb, NULL, NULL, NULL }, { "context-delete-cell", NULL, N_("Cell Contents"), NULL, NULL, - G_CALLBACK (action_context_delete_cell_contents_cb) }, + action_context_delete_cell_contents_cb, NULL, NULL, NULL }, { "context-delete-column", NULL, N_("Column"), NULL, NULL, - G_CALLBACK (action_context_delete_column_cb) }, + action_context_delete_column_cb, NULL, NULL, NULL }, { "context-delete-row", NULL, N_("Row"), NULL, NULL, - G_CALLBACK (action_context_delete_row_cb) }, + action_context_delete_row_cb, NULL, NULL, NULL }, { "context-delete-table", NULL, N_("Table"), NULL, NULL, - G_CALLBACK (action_context_delete_table_cb) }, + action_context_delete_table_cb, NULL, NULL, NULL }, /* Menus */ @@ -1768,7 +1961,7 @@ static GtkActionEntry context_entries[] = { N_("Table Delete"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "context-insert-table-menu", NULL, @@ -1776,14 +1969,14 @@ static GtkActionEntry context_entries[] = { N_("Table Insert"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, { "context-properties-menu", NULL, N_("Properties"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL } }; /***************************************************************************** @@ -1794,91 +1987,91 @@ static GtkActionEntry context_entries[] = { * counterparts. *****************************************************************************/ -static GtkActionEntry html_context_entries[] = { +static const EUIActionEntry html_context_entries[] = { { "context-delete-hrule", NULL, N_("Delete Rule"), NULL, NULL, - G_CALLBACK (action_context_delete_hrule_cb) }, + action_context_delete_hrule_cb, NULL, NULL, NULL }, { "context-delete-image", NULL, N_("Delete Image"), NULL, NULL, - G_CALLBACK (action_context_delete_image_cb) }, + action_context_delete_image_cb, NULL, NULL, NULL }, { "context-insert-column-after", NULL, N_("Column After"), NULL, NULL, - G_CALLBACK (action_context_insert_column_after_cb) }, + action_context_insert_column_after_cb, NULL, NULL, NULL }, { "context-insert-column-before", NULL, N_("Column Before"), NULL, NULL, - G_CALLBACK (action_context_insert_column_before_cb) }, + action_context_insert_column_before_cb, NULL, NULL, NULL }, { "context-insert-link", NULL, N_("Insert _Link"), NULL, NULL, - G_CALLBACK (action_insert_link_cb) }, + action_insert_link_cb, NULL, NULL, NULL }, { "context-insert-row-above", NULL, N_("Row Above"), NULL, NULL, - G_CALLBACK (action_context_insert_row_above_cb) }, + action_context_insert_row_above_cb, NULL, NULL, NULL }, { "context-insert-row-below", NULL, N_("Row Below"), NULL, NULL, - G_CALLBACK (action_context_insert_row_below_cb) }, + action_context_insert_row_below_cb, NULL, NULL, NULL }, { "context-properties-cell", NULL, N_("Cell…"), NULL, NULL, - G_CALLBACK (action_properties_cell_cb) }, + action_properties_cell_cb, NULL, NULL, NULL }, { "context-properties-image", NULL, N_("Image…"), NULL, NULL, - G_CALLBACK (action_properties_image_cb) }, + action_properties_image_cb, NULL, NULL, NULL }, { "context-properties-link", NULL, N_("Link…"), NULL, NULL, - G_CALLBACK (action_properties_link_cb) }, + action_properties_link_cb, NULL, NULL, NULL }, { "context-properties-page", NULL, N_("Page…"), NULL, NULL, - G_CALLBACK (action_properties_page_cb) }, + action_properties_page_cb, NULL, NULL, NULL }, { "context-properties-paragraph", NULL, N_("Paragraph…"), NULL, NULL, - G_CALLBACK (action_properties_paragraph_cb) }, + action_properties_paragraph_cb, NULL, NULL, NULL }, { "context-properties-rule", NULL, @@ -1886,28 +2079,28 @@ static GtkActionEntry html_context_entries[] = { N_("Rule…"), NULL, NULL, - G_CALLBACK (action_properties_rule_cb) }, + action_properties_rule_cb, NULL, NULL, NULL }, { "context-properties-table", NULL, N_("Table…"), NULL, NULL, - G_CALLBACK (action_properties_table_cb) }, + action_properties_table_cb, NULL, NULL, NULL }, { "context-properties-text", NULL, N_("Text…"), NULL, NULL, - G_CALLBACK (action_properties_text_cb) }, + action_properties_text_cb, NULL, NULL, NULL }, { "context-remove-link", NULL, N_("Remove Link"), NULL, NULL, - G_CALLBACK (action_context_remove_link_cb) } + action_context_remove_link_cb, NULL, NULL, NULL } }; /***************************************************************************** @@ -1917,78 +2110,126 @@ static GtkActionEntry html_context_entries[] = { * misspelled. *****************************************************************************/ -static GtkActionEntry spell_context_entries[] = { +static const EUIActionEntry spell_context_entries[] = { { "context-spell-add", NULL, N_("Add Word to Dictionary"), NULL, NULL, - G_CALLBACK (action_context_spell_add_cb) }, + action_context_spell_add_cb, NULL, NULL, NULL }, { "context-spell-ignore", NULL, N_("Ignore Misspelled Word"), NULL, NULL, - G_CALLBACK (action_context_spell_ignore_cb) }, + action_context_spell_ignore_cb, NULL, NULL, NULL }, - { "context-spell-add-menu", + { "EHTMLEditor::context-spell-add-menu", NULL, N_("Add Word To"), NULL, NULL, - NULL }, + NULL, NULL, NULL, NULL }, /* Menus */ - { "context-more-suggestions-menu", + { "EHTMLEditor::context-spell-suggest", + NULL, + N_("Spell check suggestions"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, + + { "EHTMLEditor::context-spell-suggest-more-menu", NULL, N_("More Suggestions"), NULL, NULL, - NULL } + NULL, NULL, NULL, NULL } }; +static void +editor_actions_setup_emoticon_menu (EHTMLEditor *editor) +{ + GList *list, *link; + + list = e_emoticon_chooser_get_items (); + + for (link = list; link; link = g_list_next (link)) { + EEmoticon *emoticon = link->data; + GMenuItem *item; + + item = g_menu_item_new (_(emoticon->label), NULL); + g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_ACTION, "s", "core-editor.EHTMLEditor::insert-emoticon"); + g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_TARGET, "s", emoticon->icon_name); + g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_ICON, "s", emoticon->icon_name); + + g_menu_append_item (editor->priv->emoticon_menu, item); + + g_clear_object (&item); + } + + g_list_free (list); +} + static gboolean editor_actions_add_to_recent_languages (EHTMLEditor *editor, const gchar *language_code) { - GtkAction *language_action; - gchar *name; + EUIAction *language_action; + GMenuModel *menu_model; + GMenuItem *menu_item; + const gchar *language_action_name; + guint ii, n_items; + guint group_name_len_plus_one, action_name_len; g_return_val_if_fail (E_IS_HTML_EDITOR (editor), FALSE); g_return_val_if_fail (language_code != NULL, FALSE); - language_action = gtk_action_group_get_action (editor->priv->language_actions, language_code); + language_action = e_ui_action_group_get_action (editor->priv->language_actions, language_code); if (!language_action) return FALSE; - name = g_strconcat ("recent-spell-language-", language_code, NULL); + group_name_len_plus_one = strlen (e_ui_action_group_get_name (editor->priv->language_actions)) + 1; + action_name_len = strlen (g_action_get_name (G_ACTION (language_action))); + language_action_name = g_action_get_name (G_ACTION (language_action)); - if (!gtk_action_group_get_action (editor->priv->language_actions, name)) { - GtkToggleAction *toggle_action; + menu_model = G_MENU_MODEL (editor->priv->recent_languages_menu); + n_items = g_menu_model_get_n_items (menu_model); + for (ii = 0; ii < n_items; ii++) { + GVariant *value; + const gchar *action_full_name; - toggle_action = gtk_toggle_action_new (name, - gtk_action_get_label (language_action), - gtk_action_get_tooltip (language_action), - NULL); + value = g_menu_model_get_item_attribute_value (menu_model, ii, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING); + if (!value || !g_variant_get_string (value, NULL)) { + g_clear_pointer (&value, g_variant_unref); + continue; + } - e_binding_bind_property (language_action, "active", - toggle_action, "active", - G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + action_full_name = g_variant_get_string (value, NULL); - gtk_action_group_add_action (editor->priv->language_actions, GTK_ACTION (toggle_action)); + if (strlen (action_full_name) == group_name_len_plus_one + action_name_len && + g_str_has_suffix (action_full_name, language_action_name) && + g_str_has_prefix (action_full_name, e_ui_action_group_get_name (editor->priv->language_actions))) { + g_clear_pointer (&value, g_variant_unref); + break; + } - g_object_unref (toggle_action); + g_clear_pointer (&value, g_variant_unref); } - gtk_ui_manager_add_ui ( - editor->priv->manager, editor->priv->recent_spell_languages_merge_id, - "/main-menu/edit-menu/language-menu/recent-languages", - name, name, GTK_UI_MANAGER_AUTO, FALSE); + /* it's already in the list */ + if (ii < n_items) + return TRUE; - g_free (name); + menu_item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (editor->priv->ui_manager, menu_item, language_action); + + g_menu_append_item (editor->priv->recent_languages_menu, menu_item); + + g_clear_object (&menu_item); return TRUE; } @@ -1998,32 +2239,30 @@ editor_actions_setup_languages_menu (EHTMLEditor *editor) { ESpellChecker *spell_checker; EContentEditor *cnt_editor; - GtkUIManager *manager; - GtkActionGroup *action_group; - GHashTable *lang_parents; /* gchar *name ~> GtkAction * */ + EUIActionGroup *action_group; + GHashTable *lang_parents; /* gchar *name ~> GMenu * (to add variants into a submenu) */ GList *list = NULL, *link; GSettings *settings; gchar **strv; + const gchar *map_name; gint ii, added = 0, max_items; - guint merge_id; lang_parents = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - manager = editor->priv->manager; action_group = editor->priv->language_actions; + map_name = e_ui_action_group_get_name (action_group); cnt_editor = e_html_editor_get_content_editor (editor); spell_checker = e_content_editor_ref_spell_checker (cnt_editor); - merge_id = gtk_ui_manager_new_merge_id (manager); - editor->priv->recent_spell_languages_merge_id = gtk_ui_manager_new_merge_id (manager); + + g_menu_remove_all (editor->priv->all_languages_menu); list = e_spell_checker_list_available_dicts (spell_checker); for (link = list; link != NULL; link = g_list_next (link)) { ESpellDictionary *dictionary = link->data; - GtkAction *parent_action; - GtkToggleAction *action; - const gchar *dictionay_name; - gchar *language_name, *path; - GString *escaped_name = NULL; + GMenu *parent_lang_menu; + GMenuItem *menu_item; + EUIAction *action; + gchar *language_name; gboolean active = FALSE; if (!e_util_get_language_info (e_spell_dictionary_get_code (dictionary), &language_name, NULL)) { @@ -2039,72 +2278,66 @@ editor_actions_setup_languages_menu (EHTMLEditor *editor) } } - dictionay_name = e_spell_dictionary_get_name (dictionary); - if (dictionay_name && strchr (dictionay_name, '_') != NULL) - escaped_name = e_str_replace_string (dictionay_name, "_", "__"); + action = e_ui_action_group_get_action (action_group, e_spell_dictionary_get_code (dictionary)); + if (action) { + g_object_ref (action); + } else { + const gchar *dictionay_name; + GString *escaped_name = NULL; - action = gtk_toggle_action_new ( - e_spell_dictionary_get_code (dictionary), - escaped_name ? escaped_name->str : dictionay_name, - NULL, NULL); + dictionay_name = e_spell_dictionary_get_name (dictionary); + if (dictionay_name && strchr (dictionay_name, '_') != NULL) + escaped_name = e_str_replace_string (dictionay_name, "_", "__"); - if (escaped_name) - g_string_free (escaped_name, TRUE); + action = e_ui_action_new_stateful (map_name, + e_spell_dictionary_get_code (dictionary), NULL, + g_variant_new_boolean (FALSE)); + e_ui_action_set_label (action, escaped_name ? escaped_name->str : dictionay_name); - /* Do this BEFORE connecting to the "toggled" signal. - * We're not prepared to invoke the signal handler yet. - * The "Add Word To" actions have not yet been added. */ - active = e_spell_checker_get_language_active ( - spell_checker, e_spell_dictionary_get_code (dictionary)); - gtk_toggle_action_set_active (action, active); + if (escaped_name) + g_string_free (escaped_name, TRUE); - g_signal_connect ( - action, "toggled", - G_CALLBACK (action_language_cb), editor); + g_signal_connect_object ( + action, "change-state", + G_CALLBACK (e_ui_action_set_state), editor, 0); - gtk_action_group_add_action ( - action_group, GTK_ACTION (action)); + g_signal_connect_object ( + action, "notify::active", + G_CALLBACK (action_language_notify_active_cb), editor, 0); - g_object_unref (action); - - parent_action = g_hash_table_lookup (lang_parents, language_name); - if (!parent_action) { - gchar *name, *tmp; - - name = g_strdup (e_spell_dictionary_get_code (dictionary)); - tmp = strchr (name, '_'); - if (tmp) - *tmp = '\0'; - - tmp = g_strconcat ("language-parent-", name, NULL); - g_free (name); - name = tmp; - - parent_action = gtk_action_new (name, language_name, NULL, NULL); - - gtk_action_group_add_action (action_group, parent_action); - - g_hash_table_insert (lang_parents, g_strdup (language_name), parent_action); - - gtk_ui_manager_add_ui ( - manager, merge_id, - "/main-menu/edit-menu/language-menu/all-languages", - name, name, GTK_UI_MANAGER_MENU, FALSE); - - g_free (name); + e_ui_action_group_add (action_group, action); + e_ui_menu_track_action (editor->priv->main_menu, action); } - path = g_strconcat ("/main-menu/edit-menu/language-menu/all-languages/", gtk_action_get_name (parent_action), NULL); + active = e_spell_checker_get_language_active (spell_checker, e_spell_dictionary_get_code (dictionary)); - gtk_ui_manager_add_ui ( - manager, merge_id, - path, - e_spell_dictionary_get_code (dictionary), - e_spell_dictionary_get_code (dictionary), - GTK_UI_MANAGER_AUTO, FALSE); + if ((!e_ui_action_get_active (action)) != (!active)) { + g_signal_handlers_block_by_func (action, action_language_notify_active_cb, editor); + e_ui_action_set_active (action, active); + g_signal_handlers_unblock_by_func (action, action_language_notify_active_cb, editor); + } + parent_lang_menu = g_hash_table_lookup (lang_parents, language_name); + if (!parent_lang_menu) { + parent_lang_menu = g_menu_new (); + + menu_item = g_menu_item_new_submenu (language_name, G_MENU_MODEL (parent_lang_menu)); + + g_hash_table_insert (lang_parents, g_strdup (language_name), parent_lang_menu); + + g_menu_append_item (editor->priv->all_languages_menu, menu_item); + + g_clear_object (&menu_item); + } + + menu_item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (editor->priv->ui_manager, menu_item, action); + + g_menu_append_item (parent_lang_menu, menu_item); + + g_clear_object (&menu_item); + g_clear_object (&action); g_free (language_name); - g_free (path); } g_list_free (list); @@ -2131,77 +2364,69 @@ editor_actions_setup_spell_check_menu (EHTMLEditor *editor) { EContentEditor *cnt_editor; ESpellChecker *spell_checker; - GtkUIManager *manager; - GtkActionGroup *action_group; + EUIActionGroup *action_group; GList *available_dicts = NULL, *iter; - guint merge_id; + const gchar *map_name; - manager = editor->priv->manager; action_group = editor->priv->spell_check_actions; + map_name = e_ui_action_group_get_name (action_group); cnt_editor = e_html_editor_get_content_editor (editor); spell_checker = e_content_editor_ref_spell_checker (cnt_editor); available_dicts = e_spell_checker_list_available_dicts (spell_checker); - merge_id = gtk_ui_manager_new_merge_id (manager); for (iter = available_dicts; iter; iter = iter->next) { ESpellDictionary *dictionary = iter->data; - GtkAction *action; + EUIAction *action; + GMenu *menu; const gchar *code; const gchar *name; GString *escaped_name = NULL; gchar *action_label; - gchar *action_name; + gchar action_name[128]; code = e_spell_dictionary_get_code (dictionary); name = e_spell_dictionary_get_name (dictionary); /* Add a suggestion menu. */ - action_name = g_strdup_printf ( - "context-spell-suggest-%s-menu", code); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "context-spell-suggest-%s-menu", code) < sizeof (action_name)); if (name && strchr (name, '_') != NULL) escaped_name = e_str_replace_string (name, "_", "__"); - action = gtk_action_new (action_name, escaped_name ? escaped_name->str : name, NULL, NULL); - gtk_action_group_add_action (action_group, action); - g_object_unref (action); + action = e_ui_action_new (map_name, action_name, NULL); + e_ui_action_set_label (action, escaped_name ? escaped_name->str : name); + e_ui_action_set_visible (action, FALSE); + e_ui_action_group_add (action_group, action); - gtk_ui_manager_add_ui ( - manager, merge_id, - "/context-menu/context-spell-suggest", - action_name, action_name, - GTK_UI_MANAGER_MENU, FALSE); + g_ptr_array_add (editor->priv->spell_suggest_actions, g_object_ref (action)); - g_free (action_name); + menu = g_menu_new (); + + g_hash_table_insert (editor->priv->spell_suggest_menus_by_code, g_strdup (code), + /* assumes ownership of both */ + e_html_editor_action_menu_pair_new (action, menu)); /* Add an item to the "Add Word To" menu. */ - action_name = g_strdup_printf ("context-spell-add-%s", code); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "context-spell-add-%s", code) < sizeof (action_name)); /* Translators: %s will be replaced with the actual dictionary * name, where a user can add a word to. This is part of an * "Add Word To" submenu. */ action_label = g_strdup_printf (_("%s Dictionary"), escaped_name ? escaped_name->str : name); - action = gtk_action_new ( - action_name, action_label, NULL, NULL); + action = e_ui_action_new_stateful (map_name, action_name, NULL, g_variant_new_string (code)); + e_ui_action_set_label (action, action_label); g_signal_connect ( action, "activate", - G_CALLBACK (action_context_spell_add_cb), editor); + G_CALLBACK (action_context_spell_add_to_dict_cb), editor); - gtk_action_set_visible (action, e_spell_checker_get_language_active (spell_checker, code)); + e_ui_action_set_visible (action, e_spell_checker_get_language_active (spell_checker, code)); - gtk_action_group_add_action (action_group, action); - - g_object_unref (action); - - gtk_ui_manager_add_ui ( - manager, merge_id, - "/context-menu/context-spell-add-menu", - action_name, action_name, - GTK_UI_MANAGER_AUTO, FALSE); + e_ui_action_group_add (action_group, action); + /* the array assumes ownership of the action */ + g_ptr_array_add (editor->priv->spell_add_actions, action); g_free (action_label); - g_free (action_name); if (escaped_name) g_string_free (escaped_name, TRUE); @@ -2212,176 +2437,94 @@ editor_actions_setup_spell_check_menu (EHTMLEditor *editor) } void -e_html_editor_actions_init (EHTMLEditor *editor) +e_html_editor_actions_add_actions (EHTMLEditor *editor) { - GtkAction *action; - GtkActionGroup *action_group; - GtkUIManager *manager; - const gchar *domain; + EUIManager *ui_manager; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + + ui_manager = e_html_editor_get_ui_manager (editor); + + /* Core Actions */ + e_ui_manager_add_actions (ui_manager, "core", NULL, + core_entries, G_N_ELEMENTS (core_entries), editor); + e_ui_manager_add_actions (ui_manager, "core-editor", NULL, + core_editor_entries, G_N_ELEMENTS (core_editor_entries), editor); + e_ui_manager_add_actions_enum (ui_manager, "core-editor", NULL, + core_justify_entries, G_N_ELEMENTS (core_justify_entries), editor); + e_ui_manager_add_actions_enum (ui_manager, "core-editor", NULL, + core_mode_entries, G_N_ELEMENTS (core_mode_entries), editor); + e_ui_manager_add_actions_enum (ui_manager, "core-editor", NULL, + core_style_entries, G_N_ELEMENTS (core_style_entries), editor); + + /* Core Actions (HTML only) */ + e_ui_manager_add_actions (ui_manager, "html", NULL, + html_entries, G_N_ELEMENTS (html_entries), editor); + e_ui_manager_add_actions (ui_manager, "html", NULL, + html_toggle_entries, G_N_ELEMENTS (html_toggle_entries), editor); + e_ui_manager_add_actions_enum (ui_manager, "html", NULL, + html_size_entries, G_N_ELEMENTS (html_size_entries), editor); + + /* Context Menu Actions */ + e_ui_manager_add_actions (ui_manager, "core-context", NULL, + context_entries, G_N_ELEMENTS (context_entries), editor); + + /* Context Menu Actions (HTML only) */ + e_ui_manager_add_actions (ui_manager, "html-context", NULL, + html_context_entries, G_N_ELEMENTS (html_context_entries), editor); + + /* Context Menu Actions (spell check only) */ + e_ui_manager_add_actions (ui_manager, "spell-check", NULL, + spell_context_entries, G_N_ELEMENTS (spell_context_entries), editor); +} + +void +e_html_editor_actions_setup_actions (EHTMLEditor *editor) +{ + EUIAction *action; + EUIManager *ui_manager; guint ii; g_return_if_fail (E_IS_HTML_EDITOR (editor)); - manager = e_html_editor_get_ui_manager (editor); - domain = GETTEXT_PACKAGE; + ui_manager = e_html_editor_get_ui_manager (editor); - /* Core Actions */ - action_group = editor->priv->core_actions; - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, core_entries, - G_N_ELEMENTS (core_entries), editor); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - - action_group = editor->priv->core_editor_actions; - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, core_editor_entries, - G_N_ELEMENTS (core_editor_entries), editor); - gtk_action_group_add_radio_actions ( - action_group, core_justify_entries, - G_N_ELEMENTS (core_justify_entries), - E_CONTENT_EDITOR_ALIGNMENT_LEFT, - NULL, NULL); - gtk_action_group_add_radio_actions ( - action_group, core_mode_entries, - G_N_ELEMENTS (core_mode_entries), - E_CONTENT_EDITOR_MODE_HTML, - G_CALLBACK (action_mode_cb), editor); - gtk_action_group_add_radio_actions ( - action_group, core_style_entries, - G_N_ELEMENTS (core_style_entries), - E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH, - NULL, NULL); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - - /* Face Action */ - action = e_emoticon_action_new ( - "insert-emoticon", _("_Emoticon"), - _("Insert Emoticon"), NULL); - g_object_set (action, "icon-name", "face-smile", NULL); - g_signal_connect ( - action, "item-activated", - G_CALLBACK (action_insert_emoticon_cb), editor); - gtk_action_group_add_action (action_group, action); - g_object_unref (action); - - /* Core Actions (HTML only) */ - action_group = editor->priv->html_actions; - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, html_entries, - G_N_ELEMENTS (html_entries), editor); - gtk_action_group_add_toggle_actions ( - action_group, html_toggle_entries, - G_N_ELEMENTS (html_toggle_entries), editor); - gtk_action_group_add_radio_actions ( - action_group, html_size_entries, - G_N_ELEMENTS (html_size_entries), - E_CONTENT_EDITOR_FONT_SIZE_NORMAL, - NULL, NULL); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - - /* Context Menu Actions */ - action_group = editor->priv->context_actions; - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, context_entries, - G_N_ELEMENTS (context_entries), editor); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - - /* Context Menu Actions (HTML only) */ - action_group = editor->priv->html_context_actions; - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, html_context_entries, - G_N_ELEMENTS (html_context_entries), editor); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - - /* Context Menu Actions (spell check only) */ - action_group = editor->priv->spell_check_actions; - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, spell_context_entries, - G_N_ELEMENTS (spell_context_entries), editor); - gtk_ui_manager_insert_action_group (manager, action_group, 0); + editor_actions_setup_emoticon_menu (editor); /* Language actions are generated dynamically. */ editor_actions_setup_languages_menu (editor); - action_group = editor->priv->language_actions; - gtk_ui_manager_insert_action_group (manager, action_group, 0); /* Some spell check actions are generated dynamically. */ - action_group = editor->priv->suggestion_actions; editor_actions_setup_spell_check_menu (editor); - gtk_ui_manager_insert_action_group (manager, action_group, 0); /* Do this after all language actions are initialized. */ e_html_editor_update_spell_actions (editor); - /* Fine Tuning */ + e_ui_action_set_sensitive (ACTION (UNINDENT), FALSE); + e_ui_action_set_sensitive (ACTION (FIND_AGAIN), FALSE); - g_object_set ( - G_OBJECT (ACTION (SHOW_FIND)), - "short-label", _("_Find"), NULL); - g_object_set ( - G_OBJECT (ACTION (SHOW_REPLACE)), - "short-label", _("Re_place"), NULL); - g_object_set ( - G_OBJECT (ACTION (INSERT_EMOJI)), - "short-label", _("E_moji"), NULL); - g_object_set ( - G_OBJECT (ACTION (INSERT_IMAGE)), - "short-label", _("_Image"), NULL); - g_object_set ( - G_OBJECT (ACTION (INSERT_LINK)), - "short-label", _("_Link"), NULL); - g_object_set ( - G_OBJECT (ACTION (INSERT_RULE)), - /* Translators: 'Rule' here means a horizontal line in an HTML text */ - "short-label", _("_Rule"), NULL); - g_object_set ( - G_OBJECT (ACTION (INSERT_TABLE)), - "short-label", _("_Table"), NULL); - - gtk_action_set_sensitive (ACTION (UNINDENT), FALSE); - gtk_action_set_sensitive (ACTION (FIND_AGAIN), FALSE); - - g_signal_connect_object (ACTION (SUBSCRIPT), "toggled", + g_signal_connect_object (ACTION (SUBSCRIPT), "notify::active", G_CALLBACK (html_editor_actions_subscript_toggled_cb), editor, 0); - g_signal_connect_object (ACTION (SUPERSCRIPT), "toggled", + g_signal_connect_object (ACTION (SUPERSCRIPT), "notify::active", G_CALLBACK (html_editor_actions_superscript_toggled_cb), editor, 0); g_signal_connect (editor, "notify::mode", G_CALLBACK (html_editor_actions_notify_mode_cb), NULL); - action_group = editor->priv->core_editor_actions; - action = gtk_action_group_get_action (action_group, "mode-html"); - e_binding_bind_property ( + action = e_ui_manager_get_action (ui_manager, "mode-html"); + e_binding_bind_property_full ( editor, "mode", - action, "current-value", - G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + action, "state", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, + e_ui_action_util_gvalue_to_enum_state, + e_ui_action_util_enum_state_to_gvalue, NULL, NULL); for (ii = 0; ii < G_N_ELEMENTS (core_mode_entries); ii++) { - action = gtk_action_group_get_action (action_group, core_mode_entries[ii].name); + action = e_ui_manager_get_action (ui_manager, core_mode_entries[ii].name); - gtk_action_set_visible (action, e_html_editor_has_editor_for_mode (editor, core_mode_entries[ii].value)); + e_ui_action_set_visible (action, e_html_editor_has_editor_for_mode (editor, core_mode_entries[ii].state)); } } -static gboolean -e_html_editor_content_editor_font_name_to_combo_box (GBinding *binding, - const GValue *from_value, - GValue *to_value, - gpointer user_data) -{ - gchar *id = NULL; - - id = e_html_editor_util_dup_font_id (GTK_COMBO_BOX (g_binding_get_target (binding)), g_value_get_string (from_value)); - g_value_take_string (to_value, id ? id : g_strdup ("")); - - return TRUE; -} - static gboolean e_html_editor_indent_level_to_bool_indent_cb (GBinding *binding, const GValue *from_value, @@ -2438,21 +2581,41 @@ e_html_editor_sensitize_html_actions_cb (GBinding *binding, EActionComboBox * e_html_editor_util_new_mode_combobox (void) { - GtkActionGroup *action_group; - GtkAction *action; + EUIActionGroup *action_group; + EUIAction *action; + EUIManager *ui_manager; + GPtrArray *actions; GtkWidget *widget; - action_group = gtk_action_group_new ("core-mode-entries"); + ui_manager = e_ui_manager_new (); - gtk_action_group_add_radio_actions ( - action_group, core_mode_entries, - G_N_ELEMENTS (core_mode_entries), - E_CONTENT_EDITOR_MODE_HTML, - NULL, NULL); + e_ui_manager_add_actions_enum (ui_manager, "core-mode-entries", NULL, + core_mode_entries, G_N_ELEMENTS (core_mode_entries), NULL); - action = gtk_action_group_get_action (action_group, "mode-html"); + action_group = e_ui_manager_get_action_group (ui_manager, "core-mode-entries"); - widget = e_action_combo_box_new_with_action (GTK_RADIO_ACTION (action)); + g_object_ref (action_group); + g_clear_object (&ui_manager); + + actions = e_ui_action_group_list_actions (action_group); + if (actions) { + GPtrArray *group; + guint ii; + + group = g_ptr_array_new (); + + for (ii = 0; ii < actions->len; ii++) { + EUIAction *radio_action = g_ptr_array_index (actions, ii); + e_ui_action_set_radio_group (radio_action, group); + } + + g_ptr_array_unref (group); + g_ptr_array_unref (actions); + } + + action = e_ui_action_group_get_action (action_group, "mode-html"); + + widget = e_action_combo_box_new_with_action (action); gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); gtk_widget_set_tooltip_text (widget, _("Editing Mode")); @@ -2473,23 +2636,6 @@ e_html_editor_actions_bind (EHTMLEditor *editor) /* 'rb' for 'remember binding' */ #define rb(x) editor->priv->content_editor_bindings = g_slist_prepend (editor->priv->content_editor_bindings, g_object_ref (x)) - rb (e_binding_bind_property ( - editor->priv->fg_color_combo_box, "current-color", - cnt_editor, "font-color", - G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL)); - rb (e_binding_bind_property ( - cnt_editor, "editable", - editor->priv->fg_color_combo_box, "sensitive", - G_BINDING_SYNC_CREATE)); - rb (e_binding_bind_property ( - editor->priv->bg_color_combo_box, "current-color", - cnt_editor, "background-color", - G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL)); - rb (e_binding_bind_property ( - cnt_editor, "editable", - editor->priv->bg_color_combo_box, "sensitive", - G_BINDING_SYNC_CREATE)); - rb (e_binding_bind_property ( cnt_editor, "can-redo", ACTION (REDO), "sensitive", @@ -2517,22 +2663,28 @@ e_html_editor_actions_bind (EHTMLEditor *editor) /* This is connected to JUSTIFY_LEFT action only, but * it automatically applies on all actions in the group. */ - rb (e_binding_bind_property ( + rb (e_binding_bind_property_full ( cnt_editor, "alignment", - ACTION (JUSTIFY_LEFT), "current-value", - G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL)); + ACTION (JUSTIFY_LEFT), "state", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + e_ui_action_util_gvalue_to_enum_state, + e_ui_action_util_enum_state_to_gvalue, NULL, NULL)); rb (e_binding_bind_property ( cnt_editor, "bold", ACTION (BOLD), "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL)); - rb (e_binding_bind_property ( + rb (e_binding_bind_property_full ( cnt_editor, "font-size", - ACTION (FONT_SIZE_GROUP), "current-value", - G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL)); - rb (e_binding_bind_property ( + ACTION (FONT_SIZE_GROUP), "state", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + e_ui_action_util_gvalue_to_enum_state, + e_ui_action_util_enum_state_to_gvalue, NULL, NULL)); + rb (e_binding_bind_property_full ( cnt_editor, "block-format", - ACTION (STYLE_NORMAL), "current-value", - G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL)); + ACTION (STYLE_NORMAL), "state", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + e_ui_action_util_gvalue_to_enum_state, + e_ui_action_util_enum_state_to_gvalue, NULL, NULL)); rb (e_binding_bind_property_full ( cnt_editor, "indent-level", ACTION (INDENT), "sensitive", @@ -2557,13 +2709,6 @@ e_html_editor_actions_bind (EHTMLEditor *editor) cnt_editor, "underline", ACTION (UNDERLINE), "active", G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL)); - rb (e_binding_bind_property_full ( - cnt_editor, "font-name", - editor->priv->font_name_combo_box, "active-id", - G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, - e_html_editor_content_editor_font_name_to_combo_box, - NULL, - NULL, NULL)); /* Cannot use binding, due to subscript and superscript being mutually exclusive */ editor->priv->subscript_notify_id = g_signal_connect_object (cnt_editor, "notify::subscript", @@ -2616,8 +2761,8 @@ e_html_editor_actions_update_spellcheck_languages_menu (EHTMLEditor *editor, const gchar * const *languages) { GHashTable *active; - GList *actions, *link; - gint ii; + GPtrArray *actions; + guint ii; g_return_if_fail (E_IS_HTML_EDITOR (editor)); @@ -2627,28 +2772,20 @@ e_html_editor_actions_update_spellcheck_languages_menu (EHTMLEditor *editor, g_hash_table_insert (active, g_strdup (languages[ii]), NULL); } - actions = gtk_action_group_list_actions (editor->priv->language_actions); - for (link = actions; link; link = g_list_next (link)) { - GtkToggleAction *toggle_action; + actions = e_ui_action_group_list_actions (editor->priv->language_actions); + for (ii = 0; actions && ii < actions->len; ii++) { + EUIAction *action = g_ptr_array_index (actions, ii); gboolean is_active; - if (!GTK_IS_TOGGLE_ACTION (link->data)) - continue; + is_active = g_hash_table_contains (active, g_action_get_name (G_ACTION (action))); - if (gtk_action_get_name (link->data) && - g_str_has_prefix (gtk_action_get_name (link->data), "recent-spell-language-")) - continue; - - is_active = g_hash_table_contains (active, gtk_action_get_name (link->data)); - toggle_action = GTK_TOGGLE_ACTION (link->data); - - if ((gtk_toggle_action_get_active (toggle_action) ? 1 : 0) != (is_active ? 1 : 0)) { - g_signal_handlers_block_by_func (toggle_action, action_language_cb, editor); - gtk_toggle_action_set_active (toggle_action, is_active); - g_signal_handlers_unblock_by_func (toggle_action, action_language_cb, editor); + if ((e_ui_action_get_active (action) ? 1 : 0) != (is_active ? 1 : 0)) { + g_signal_handlers_block_by_func (action, action_language_notify_active_cb, editor); + e_ui_action_set_active (action, is_active); + g_signal_handlers_unblock_by_func (action, action_language_notify_active_cb, editor); } } + g_clear_pointer (&actions, g_ptr_array_unref); g_hash_table_destroy (active); - g_list_free (actions); } diff --git a/src/e-util/e-html-editor-actions.h b/src/e-util/e-html-editor-actions.h index 0adde4c3d9..2cca349077 100644 --- a/src/e-util/e-html-editor-actions.h +++ b/src/e-util/e-html-editor-actions.h @@ -74,7 +74,7 @@ #define E_HTML_EDITOR_ACTION_CONTEXT_SPELL_ADD(editor) \ E_HTML_EDITOR_ACTION ((editor), "context-spell-add") #define E_HTML_EDITOR_ACTION_CONTEXT_SPELL_ADD_MENU(editor) \ - E_HTML_EDITOR_ACTION ((editor), "context-spell-add-menu") + E_HTML_EDITOR_ACTION ((editor), "EHTMLEditor::context-spell-add-menu") #define E_HTML_EDITOR_ACTION_CONTEXT_SPELL_IGNORE(editor) \ E_HTML_EDITOR_ACTION ((editor), "context-spell-ignore") #define E_HTML_EDITOR_ACTION_COPY(editor) \ diff --git a/src/e-util/e-html-editor-manager.ui b/src/e-util/e-html-editor-manager.ui deleted file mode 100644 index 4592ea63a8..0000000000 --- a/src/e-util/e-html-editor-manager.ui +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/e-util/e-html-editor-paragraph-dialog.c b/src/e-util/e-html-editor-paragraph-dialog.c index 56c6a27067..d5748d1f1b 100644 --- a/src/e-util/e-html-editor-paragraph-dialog.c +++ b/src/e-util/e-html-editor-paragraph-dialog.c @@ -51,6 +51,8 @@ html_editor_paragraph_dialog_constructed (GObject *object) dialog = E_HTML_EDITOR_PARAGRAPH_DIALOG (object); editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog)); + e_ui_manager_add_action_groups_to_widget (e_html_editor_get_ui_manager (editor), GTK_WIDGET (dialog)); + main_layout = e_html_editor_dialog_get_container (E_HTML_EDITOR_DIALOG (dialog)); /* == General == */ @@ -66,8 +68,7 @@ html_editor_paragraph_dialog_constructed (GObject *object) gtk_widget_set_margin_left (GTK_WIDGET (grid), 10); /* Style */ - widget = e_action_combo_box_new_with_action ( - GTK_RADIO_ACTION (e_html_editor_get_action (editor, "style-normal"))); + widget = e_action_combo_box_new_with_action (e_html_editor_get_action (editor, "style-normal")); gtk_widget_set_hexpand (widget, TRUE); gtk_grid_attach (grid, widget, 1, 0, 1, 1); dialog->priv->style_combo = widget; @@ -92,9 +93,7 @@ html_editor_paragraph_dialog_constructed (GObject *object) /* Left */ widget = gtk_toggle_button_new_with_label (_("_Left")); gtk_button_set_use_stock (GTK_BUTTON (widget), TRUE); - gtk_activatable_set_related_action ( - GTK_ACTIVATABLE (widget), - e_html_editor_get_action (editor, "justify-left")); + e_ui_action_util_assign_to_widget (e_html_editor_get_action (editor, "justify-left"), widget); gtk_grid_attach (grid, widget, 0, 0, 1, 1); dialog->priv->left_button = widget; @@ -102,27 +101,21 @@ html_editor_paragraph_dialog_constructed (GObject *object) widget = gtk_toggle_button_new_with_label (_("_Center")); gtk_button_set_use_stock (GTK_BUTTON (widget), TRUE); gtk_grid_attach (grid, widget, 1, 0, 1, 1); - gtk_activatable_set_related_action ( - GTK_ACTIVATABLE (widget), - e_html_editor_get_action (editor, "justify-center")); + e_ui_action_util_assign_to_widget (e_html_editor_get_action (editor, "justify-center"), widget); dialog->priv->center_button = widget; /* Right */ widget = gtk_toggle_button_new_with_label (_("_Right")); gtk_button_set_use_stock (GTK_BUTTON (widget), TRUE); gtk_grid_attach (grid, widget, 2, 0, 1, 1); - gtk_activatable_set_related_action ( - GTK_ACTIVATABLE (widget), - e_html_editor_get_action (editor, "justify-right")); + e_ui_action_util_assign_to_widget (e_html_editor_get_action (editor, "justify-right"), widget); dialog->priv->right_button = widget; /* Justified */ widget = gtk_toggle_button_new_with_label (_("_Justified")); gtk_button_set_use_stock (GTK_BUTTON (widget), TRUE); gtk_grid_attach (grid, widget, 2, 0, 1, 1); - gtk_activatable_set_related_action ( - GTK_ACTIVATABLE (widget), - e_html_editor_get_action (editor, "justify-fill")); + e_ui_action_util_assign_to_widget (e_html_editor_get_action (editor, "justify-fill"), widget); dialog->priv->justified_button = widget; gtk_widget_show_all (GTK_WIDGET (main_layout)); diff --git a/src/e-util/e-html-editor-private.h b/src/e-util/e-html-editor-private.h index d21029db09..d32baa103e 100644 --- a/src/e-util/e-html-editor-private.h +++ b/src/e-util/e-html-editor-private.h @@ -36,33 +36,48 @@ #include #include #include +#include +#include #include -#ifdef HAVE_XFREE -#include -#endif - #define ACTION(name) (E_HTML_EDITOR_ACTION_##name (editor)) -#define WIDGET(name) (E_HTML_EDITOR_WIDGETS_##name (editor)) G_BEGIN_DECLS +typedef struct _EHTMLEditorActionMenuPair { + EUIAction *parent_menu_action; /* to control visibility of the parent menu item (submenu) */ + GMenu *submenu_items; /* actual items of the submenu */ +} EHTMLEditorActionMenuPair; + +EHTMLEditorActionMenuPair * + e_html_editor_action_menu_pair_new (EUIAction *action, /* (transfer full) */ + GMenu *menu); /* (transfer full) */ +void e_html_editor_action_menu_pair_free (gpointer ptr); + struct _EHTMLEditorPrivate { EContentEditorMode mode; GtkWidget *content_editors_box; - GtkUIManager *manager; - GtkActionGroup *core_actions; - GtkActionGroup *core_editor_actions; - GtkActionGroup *html_actions; - GtkActionGroup *context_actions; - GtkActionGroup *html_context_actions; - GtkActionGroup *language_actions; - GtkActionGroup *spell_check_actions; - GtkActionGroup *suggestion_actions; + EUIManager *ui_manager; + EUIActionGroup *core_actions; /* owned by priv->manager */ + EUIActionGroup *core_editor_actions; /* owned by priv->manager */ + EUIActionGroup *html_actions; /* owned by priv->manager */ + EUIActionGroup *context_actions; /* owned by priv->manager */ + EUIActionGroup *html_context_actions; /* owned by priv->manager */ + EUIActionGroup *language_actions; /* owned by priv->manager */ + EUIActionGroup *spell_check_actions; /* owned by priv->manager */ + EUIActionGroup *suggestion_actions; /* owned by priv->manager */ - GtkWidget *main_menu; + GMenu *emoticon_menu; + GMenu *recent_languages_menu; + GMenu *all_languages_menu; + GPtrArray *spell_suggest_actions; /* EUIAction; to fill a GMenu */ + GPtrArray *spell_suggest_more_actions; /* EUIAction; to fill a GMenu */ + GPtrArray *spell_add_actions; /* EUIAction, to fill a GMenu */ + GHashTable *spell_suggest_menus_by_code; /* gchar *dictionary-code ~> EHTMLEditorActionMenuPair * */ + + EUIMenu *main_menu; GtkWidget *main_toolbar; GtkWidget *edit_toolbar; GtkWidget *html_toolbar; @@ -83,16 +98,10 @@ struct _EHTMLEditorPrivate { GtkWidget *cell_dialog; GtkWidget *spell_check_dialog; - GtkWidget *fg_color_combo_box; - GtkWidget *bg_color_combo_box; - GtkWidget *mode_combo_box; - GtkToolItem *mode_tool_item; - GtkWidget *size_combo_box; - GtkWidget *style_combo_box; - GtkWidget *font_name_combo_box; GtkWidget *scrolled_window; GtkWidget *emoji_chooser; + GtkWidget *emoticon_chooser; GHashTable *cid_parts; /* gchar *cid: URI ~> CamelMimePart * */ GHashTable *content_editors; /* gchar *name ~> EContentEditor * */ @@ -105,9 +114,6 @@ struct _EHTMLEditorPrivate { gulong subscript_notify_id; gulong superscript_notify_id; - guint spell_suggestions_merge_id; - guint recent_spell_languages_merge_id; - gint editor_layout_row; gboolean paste_plain_prefer_pre; @@ -115,7 +121,10 @@ struct _EHTMLEditorPrivate { gchar *context_hover_uri; }; -void e_html_editor_actions_init (EHTMLEditor *editor); +void e_html_editor_actions_add_actions + (EHTMLEditor *editor); +void e_html_editor_actions_setup_actions + (EHTMLEditor *editor); void e_html_editor_actions_bind (EHTMLEditor *editor); void e_html_editor_actions_unbind (EHTMLEditor *editor); void e_html_editor_actions_update_spellcheck_languages_menu @@ -130,6 +139,8 @@ gchar * e_html_editor_util_dup_font_id (GtkComboBox *combo_box, gboolean e_html_editor_has_editor_for_mode (EHTMLEditor *editor, EContentEditorMode mode); +void e_html_editor_emit_after_mode_changed + (EHTMLEditor *self); G_END_DECLS diff --git a/src/e-util/e-html-editor.c b/src/e-util/e-html-editor.c index ad9c7da7e8..02112b6cd9 100644 --- a/src/e-util/e-html-editor.c +++ b/src/e-util/e-html-editor.c @@ -78,6 +78,7 @@ enum { enum { UPDATE_ACTIONS, SPELL_LANGUAGES_CHANGED, + AFTER_MODE_CHANGED, LAST_SIGNAL }; @@ -220,20 +221,57 @@ e_html_editor_util_dup_font_id (GtkComboBox *combo_box, return id; } +EHTMLEditorActionMenuPair * +e_html_editor_action_menu_pair_new (EUIAction *action, /* (transfer full) */ + GMenu *menu) /* (transfer full) */ +{ + EHTMLEditorActionMenuPair *data; + + data = g_new0 (EHTMLEditorActionMenuPair, 1); + data->parent_menu_action = action; + data->submenu_items = menu; + + return data; +} + +void +e_html_editor_action_menu_pair_free (gpointer ptr) +{ + EHTMLEditorActionMenuPair *data = ptr; + + if (data) { + g_clear_object (&data->parent_menu_action); + g_clear_object (&data->submenu_items); + g_free (data); + } +} + +void +e_html_editor_emit_after_mode_changed (EHTMLEditor *self) +{ + g_return_if_fail (E_IS_HTML_EDITOR (self)); + + g_signal_emit (self, signals[AFTER_MODE_CHANGED], 0, NULL); +} + /* Action callback for context menu spelling suggestions. * XXX This should really be in e-html-editor-actions.c */ static void -action_context_spell_suggest_cb (GtkAction *action, - EHTMLEditor *editor) +action_context_spell_suggest_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; - const gchar *word; + GVariant *state; - word = g_object_get_data (G_OBJECT (action), "word"); - g_return_if_fail (word != NULL); + state = g_action_get_state (G_ACTION (action)); + g_return_if_fail (state != NULL); cnt_editor = e_html_editor_get_content_editor (editor); - e_content_editor_replace_caret_word (cnt_editor, word); + e_content_editor_replace_caret_word (cnt_editor, g_variant_get_string (state, NULL)); + + g_clear_pointer (&state, g_variant_unref); } static void @@ -242,27 +280,34 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor, { EContentEditor *cnt_editor; ESpellChecker *spell_checker; - GtkActionGroup *action_group; - GtkUIManager *manager; + EUIActionGroup *action_group; + GPtrArray *fill_actions; gchar **suggestions; - const gchar *path; + const gchar *map_name; guint count = 0; guint length; - guint merge_id; guint threshold; gint ii; + gboolean had_any_before; + + had_any_before = editor->priv->spell_suggest_actions->len > 0 || editor->priv->spell_suggest_more_actions->len > 0; + + g_ptr_array_set_size (editor->priv->spell_suggest_actions, 0); + g_ptr_array_set_size (editor->priv->spell_suggest_more_actions, 0); + + if (!caret_word || !*caret_word) { + if (had_any_before) + e_ui_menu_rebuild (editor->priv->main_menu); + return; + } cnt_editor = e_html_editor_get_content_editor (editor); - if (!caret_word || !*caret_word) - return; - spell_checker = e_content_editor_ref_spell_checker (cnt_editor); suggestions = e_spell_checker_get_guesses_for_word (spell_checker, caret_word); - - path = "/context-menu/context-spell-suggest/"; - manager = e_html_editor_get_ui_manager (editor); action_group = editor->priv->suggestion_actions; - merge_id = editor->priv->spell_suggestions_merge_id; + map_name = e_ui_action_group_get_name (action_group); + + fill_actions = editor->priv->spell_suggest_actions; length = (suggestions != NULL) ? g_strv_length (suggestions) : 0; @@ -278,55 +323,34 @@ html_editor_inline_spelling_suggestions (EHTMLEditor *editor, for (ii = 0; suggestions && suggestions[ii]; ii++) { gchar *suggestion = suggestions[ii]; - gchar *action_name; - gchar *action_label; - GtkAction *action; - GtkWidget *child; - GSList *proxies; + gchar action_name[128]; + EUIAction *action; /* Once we reach the threshold, put all subsequent * spelling suggestions in a secondary menu. */ if (count == threshold) - path = "/context-menu/context-more-suggestions-menu/"; + fill_actions = editor->priv->spell_suggest_more_actions; /* Action name just needs to be unique. */ - action_name = g_strdup_printf ("suggest-%d", count++); - action_label = g_markup_printf_escaped ("%s", suggestion); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "suggest-%d", count++) < sizeof (action_name)); - action = gtk_action_new (action_name, action_label, NULL, NULL); - - g_object_set_data_full ( - G_OBJECT (action), "word", - g_strdup (suggestion), g_free); + action = e_ui_action_new_stateful (map_name, action_name, NULL, g_variant_new_string (suggestion)); + e_ui_action_set_label (action, suggestion); g_signal_connect ( action, "activate", G_CALLBACK (action_context_spell_suggest_cb), editor); - gtk_action_group_add_action (action_group, action); - - gtk_ui_manager_add_ui ( - manager, merge_id, path, - action_name, action_name, - GTK_UI_MANAGER_AUTO, FALSE); - - /* XXX GtkAction offers no support for Pango markup, - * so we have to manually set "use-markup" on the - * child of the proxy widget. */ - gtk_ui_manager_ensure_update (manager); - proxies = gtk_action_get_proxies (action); - - if (proxies) { - child = gtk_bin_get_child (proxies->data); - g_object_set (child, "use-markup", TRUE, NULL); - } - - g_free (action_name); - g_free (action_label); + e_ui_action_group_add (action_group, action); + /* the array assumes ownership of the action */ + g_ptr_array_add (fill_actions, action); } g_strfreev (suggestions); g_clear_object (&spell_checker); + + if (had_any_before || count > 0) + e_ui_menu_rebuild (editor->priv->main_menu); } /* Helper for html_editor_update_actions() */ @@ -338,17 +362,23 @@ html_editor_spell_checkers_foreach (EHTMLEditor *editor, EContentEditor *cnt_editor; ESpellChecker *spell_checker; ESpellDictionary *dictionary = NULL; - GtkActionGroup *action_group; - GtkUIManager *manager; + EUIActionGroup *action_group; + EHTMLEditorActionMenuPair *action_menu_pair; GList *list, *link; - gchar *path; + const gchar *map_name; gint ii = 0; - guint merge_id; + + action_menu_pair = g_hash_table_lookup (editor->priv->spell_suggest_menus_by_code, language_code); + g_return_if_fail (action_menu_pair != NULL); + + g_menu_remove_all (action_menu_pair->submenu_items); + + if (!caret_word || !*caret_word) { + e_ui_action_set_visible (action_menu_pair->parent_menu_action, FALSE); + return; + } cnt_editor = e_html_editor_get_content_editor (editor); - if (!caret_word || !*caret_word) - return; - spell_checker = e_content_editor_ref_spell_checker (cnt_editor); dictionary = e_spell_checker_ref_dictionary (spell_checker, language_code); @@ -359,60 +389,43 @@ html_editor_spell_checkers_foreach (EHTMLEditor *editor, list = NULL; } - manager = e_html_editor_get_ui_manager (editor); action_group = editor->priv->suggestion_actions; - merge_id = editor->priv->spell_suggestions_merge_id; - - path = g_strdup_printf ( - "/context-menu/context-spell-suggest/" - "context-spell-suggest-%s-menu", language_code); + map_name = e_ui_action_group_get_name (action_group); + e_ui_action_set_visible (action_menu_pair->parent_menu_action, list != NULL); for (link = list; link != NULL; link = g_list_next (link), ii++) { gchar *suggestion = link->data; - gchar *action_name; - gchar *action_label; - GtkAction *action; - GtkWidget *child; - GSList *proxies; + gchar action_name[128]; + EUIAction *action; + GMenuItem *menu_item; /* Action name just needs to be unique. */ - action_name = g_strdup_printf ("suggest-%s-%d", language_code, ii); - action_label = g_markup_printf_escaped ("%s", suggestion); + g_snprintf (action_name, sizeof (action_name), "suggest-%s-%d", language_code, ii); - action = gtk_action_new (action_name, action_label, NULL, NULL); - - g_object_set_data_full ( - G_OBJECT (action), "word", - g_strdup (suggestion), g_free); + action = e_ui_action_new_stateful (map_name, action_name, NULL, g_variant_new_string (suggestion)); + e_ui_action_set_label (action, suggestion); g_signal_connect ( action, "activate", G_CALLBACK (action_context_spell_suggest_cb), editor); - gtk_action_group_add_action (action_group, action); + e_ui_action_group_add (action_group, action); - gtk_ui_manager_add_ui ( - manager, merge_id, path, - action_name, action_name, - GTK_UI_MANAGER_AUTO, FALSE); + menu_item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (editor->priv->ui_manager, menu_item, action); + /* to not look like a radio item */ + g_menu_item_set_attribute (menu_item, G_MENU_ATTRIBUTE_TARGET, NULL); - /* XXX GtkAction offers no supports for Pango markup, - * so we have to manually set "use-markup" on the - * child of the proxy widget. */ - gtk_ui_manager_ensure_update (manager); - proxies = gtk_action_get_proxies (action); - if (proxies && proxies->data) { - child = gtk_bin_get_child (proxies->data); - g_object_set (child, "use-markup", TRUE, NULL); - } + g_menu_append_item (action_menu_pair->submenu_items, menu_item); - g_free (action_name); - g_free (action_label); + g_clear_object (&menu_item); + + if (link == list) + g_ptr_array_add (editor->priv->spell_suggest_actions, g_object_ref (action_menu_pair->parent_menu_action)); } g_list_free_full (list, (GDestroyNotify) g_free); g_clear_object (&spell_checker); - g_free (path); } void @@ -427,22 +440,22 @@ e_html_editor_update_spell_actions (EHTMLEditor *editor) count = e_spell_checker_count_active_languages (spell_checker); - gtk_action_set_visible (ACTION (CONTEXT_SPELL_ADD), count == 1); - gtk_action_set_visible (ACTION (CONTEXT_SPELL_ADD_MENU), count > 1); - gtk_action_set_visible (ACTION (CONTEXT_SPELL_IGNORE), count > 0); + e_ui_action_set_visible (ACTION (CONTEXT_SPELL_ADD), count == 1); + e_ui_action_set_visible (ACTION (CONTEXT_SPELL_ADD_MENU), count > 1); + e_ui_action_set_visible (ACTION (CONTEXT_SPELL_IGNORE), count > 0); - gtk_action_set_sensitive (ACTION (SPELL_CHECK), count > 0); - gtk_action_set_sensitive (ACTION (LANGUAGE_MENU), e_spell_checker_count_available_dicts (spell_checker) > 0); + e_ui_action_set_sensitive (ACTION (SPELL_CHECK), count > 0); + e_ui_action_set_sensitive (ACTION (LANGUAGE_MENU), e_spell_checker_count_available_dicts (spell_checker) > 0); g_clear_object (&spell_checker); } static void -action_set_visible_and_sensitive (GtkAction *action, +action_set_visible_and_sensitive (EUIAction *action, gboolean value) { - gtk_action_set_visible (action, value); - gtk_action_set_sensitive (action, value); + e_ui_action_set_visible (action, value); + e_ui_action_set_sensitive (action, value); } static void @@ -453,13 +466,11 @@ html_editor_update_actions (EHTMLEditor *editor, { EContentEditor *cnt_editor; ESpellChecker *spell_checker; - GtkUIManager *manager; - GtkActionGroup *action_group; - GList *list; + GHashTableIter iter; + gpointer value = NULL; gchar **languages = NULL; guint ii, n_languages; gboolean visible; - guint merge_id; cnt_editor = e_html_editor_get_content_editor (editor); @@ -492,8 +503,8 @@ html_editor_update_actions (EHTMLEditor *editor, visible && !(flags & E_CONTENT_EDITOR_NODE_IS_TEXT_COLLAPSED)); visible = - gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_IMAGE)) || - gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_LINK)) || + e_ui_action_get_visible (ACTION (CONTEXT_PROPERTIES_IMAGE)) || + e_ui_action_get_visible (ACTION (CONTEXT_PROPERTIES_LINK)) || visible; /* text node under caret */ action_set_visible_and_sensitive (ACTION (CONTEXT_PROPERTIES_PARAGRAPH), visible); @@ -521,24 +532,16 @@ html_editor_update_actions (EHTMLEditor *editor, /********************** Spell Check Suggestions **********************/ - manager = e_html_editor_get_ui_manager (editor); - action_group = editor->priv->suggestion_actions; - /* Remove the old content from the context menu. */ - merge_id = editor->priv->spell_suggestions_merge_id; - if (merge_id > 0) { - gtk_ui_manager_remove_ui (manager, merge_id); - editor->priv->spell_suggestions_merge_id = 0; + g_hash_table_iter_init (&iter, editor->priv->spell_suggest_menus_by_code); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + EHTMLEditorActionMenuPair *action_menu_pair = value; + e_ui_action_set_visible (action_menu_pair->parent_menu_action, FALSE); + g_menu_remove_all (action_menu_pair->submenu_items); } /* Clear the action group for spelling suggestions. */ - list = gtk_action_group_list_actions (action_group); - while (list != NULL) { - GtkAction *action = list->data; - - gtk_action_group_remove_action (action_group, action); - list = g_list_delete_link (list, list); - } + e_ui_action_group_remove_all (editor->priv->suggestion_actions); spell_checker = e_content_editor_ref_spell_checker (cnt_editor); languages = e_spell_checker_list_active_languages ( @@ -554,8 +557,7 @@ html_editor_update_actions (EHTMLEditor *editor, } } - action_group = editor->priv->spell_check_actions; - gtk_action_group_set_visible (action_group, visible); + e_ui_action_group_set_visible (editor->priv->spell_check_actions, visible); g_clear_object (&spell_checker); @@ -565,9 +567,6 @@ html_editor_update_actions (EHTMLEditor *editor, return; } - merge_id = gtk_ui_manager_new_merge_id (manager); - editor->priv->spell_suggestions_merge_id = merge_id; - /* Handle a single active language as a special case. */ if (n_languages == 1) { html_editor_inline_spelling_suggestions (editor, caret_word); @@ -577,6 +576,9 @@ html_editor_update_actions (EHTMLEditor *editor, return; } + g_ptr_array_set_size (editor->priv->spell_suggest_actions, 0); + g_ptr_array_set_size (editor->priv->spell_suggest_more_actions, 0); + /* Add actions and context menu content for active languages. */ for (ii = 0; ii < n_languages; ii++) html_editor_spell_checkers_foreach (editor, languages[ii], caret_word); @@ -643,16 +645,6 @@ context_menu_data_free (gpointer ptr) } } -static void -html_editor_menu_deactivate_cb (GtkMenu *popup_menu, - gpointer user_data) -{ - g_return_if_fail (GTK_IS_MENU (popup_menu)); - - g_signal_handlers_disconnect_by_func (popup_menu, html_editor_menu_deactivate_cb, user_data); - gtk_menu_detach (popup_menu); -} - static gboolean html_editor_show_context_menu_idle_cb (gpointer user_data) { @@ -663,21 +655,22 @@ html_editor_show_context_menu_idle_cb (gpointer user_data) editor = g_weak_ref_get (cmd->editor_weakref); if (editor) { - GtkWidget *menu; - - menu = e_html_editor_get_managed_widget (editor, "/context-menu"); + GtkMenu *menu; + GObject *ui_item; + e_ui_menu_freeze (editor->priv->main_menu); g_signal_emit (editor, signals[UPDATE_ACTIONS], 0, cmd->flags, cmd->caret_word, cmd->hover_uri); + e_ui_menu_thaw (editor->priv->main_menu); - if (!gtk_menu_get_attach_widget (GTK_MENU (menu))) { - gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (editor), NULL); + ui_item = e_ui_manager_create_item (editor->priv->ui_manager, "context-menu"); + menu = GTK_MENU (gtk_menu_new_from_model (G_MENU_MODEL (ui_item))); + g_clear_object (&ui_item); - g_signal_connect ( - menu, "deactivate", - G_CALLBACK (html_editor_menu_deactivate_cb), NULL); - } + gtk_menu_attach_to_widget (menu, GTK_WIDGET (editor), NULL); - gtk_menu_popup_at_pointer (GTK_MENU (menu), cmd->event); + e_util_connect_menu_detach_after_deactivate (menu); + + gtk_menu_popup_at_pointer (menu, cmd->event); g_object_unref (editor); } @@ -715,12 +708,16 @@ html_editor_find_ui_file (const gchar *basename) g_return_val_if_fail (basename != NULL, NULL); /* Support running directly from the source tree. */ - filename = g_build_filename (".", basename, NULL); + filename = g_build_filename (".", "data", "ui", basename, NULL); + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + return filename; + g_free (filename); + + filename = g_build_filename ("..", "..", "..", "data", "ui", basename, NULL); if (g_file_test (filename, G_FILE_TEST_EXISTS)) return filename; g_free (filename); - /* XXX This is kinda broken. */ filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); if (g_file_test (filename, G_FILE_TEST_EXISTS)) return filename; @@ -743,7 +740,8 @@ html_editor_parent_changed (GtkWidget *widget, if (GTK_IS_WINDOW (top_level)) { gtk_window_add_accel_group ( GTK_WINDOW (top_level), - gtk_ui_manager_get_accel_group (editor->priv->manager)); + e_ui_manager_get_accel_group (editor->priv->ui_manager)); + e_ui_manager_set_action_groups_widget (editor->priv->ui_manager, top_level); } } @@ -811,6 +809,367 @@ e_html_editor_edit_html_toolbar_visible_cb (GBinding *binding, return TRUE; } +static gboolean +e_html_editor_content_editor_font_name_to_combo_box (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + gchar *id = NULL; + + id = e_html_editor_util_dup_font_id (GTK_COMBO_BOX (g_binding_get_target (binding)), g_value_get_string (from_value)); + g_value_take_string (to_value, id ? id : g_strdup ("")); + + return TRUE; +} + +static void +e_html_editor_unbind_and_unref (gpointer ptr) +{ + GBinding *binding = ptr; + + if (binding) { + g_binding_unbind (binding); + g_object_unref (binding); + } +} + +static void +e_html_editor_bind_font_name_after_mode_changed_cb (EHTMLEditor *self, + gpointer user_data) +{ + GtkWidget *widget = user_data; + EContentEditor *cnt_editor; + + g_return_if_fail (E_IS_HTML_EDITOR (self)); + g_return_if_fail (GTK_IS_COMBO_BOX (widget)); + + cnt_editor = e_html_editor_get_content_editor (self); + if (cnt_editor) { + GBinding *binding; + + binding = e_binding_bind_property_full ( + cnt_editor, "font-name", + widget, "active-id", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL, + e_html_editor_content_editor_font_name_to_combo_box, + NULL, + NULL, NULL); + g_object_set_data_full (G_OBJECT (widget), "EHTMLEditor::binding", g_object_ref (binding), + e_html_editor_unbind_and_unref); + + binding = e_binding_bind_property ( + cnt_editor, "editable", + widget, "sensitive", + G_BINDING_SYNC_CREATE); + g_object_set_data_full (G_OBJECT (widget), "EHTMLEditor::binding-sensitive", g_object_ref (binding), + e_html_editor_unbind_and_unref); + + gtk_widget_set_sensitive (widget, e_content_editor_is_editable (cnt_editor) && e_html_editor_get_mode (self) == E_CONTENT_EDITOR_MODE_HTML); + } else { + g_object_set_data (G_OBJECT (widget), "EHTMLEditor::binding", NULL); + g_object_set_data (G_OBJECT (widget), "EHTMLEditor::binding-sensitive", NULL); + } +} + +static void +e_html_editor_bind_color_combox_box (EHTMLEditor *self, + GtkWidget *widget, + const gchar *property_name) +{ + EContentEditor *cnt_editor; + + cnt_editor = e_html_editor_get_content_editor (self); + if (cnt_editor) { + GBinding *binding; + + binding = e_binding_bind_property ( + widget, "current-color", + cnt_editor, property_name, + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + g_object_set_data_full (G_OBJECT (widget), "EHTMLEditor::binding", g_object_ref (binding), + e_html_editor_unbind_and_unref); + + binding = e_binding_bind_property ( + cnt_editor, "editable", + widget, "sensitive", + G_BINDING_SYNC_CREATE); + g_object_set_data_full (G_OBJECT (widget), "EHTMLEditor::binding-sensitive", g_object_ref (binding), + e_html_editor_unbind_and_unref); + + gtk_widget_set_sensitive (widget, e_content_editor_is_editable (cnt_editor) && e_html_editor_get_mode (self) == E_CONTENT_EDITOR_MODE_HTML); + } else { + g_object_set_data (G_OBJECT (widget), "EHTMLEditor::binding", NULL); + g_object_set_data (G_OBJECT (widget), "EHTMLEditor::binding-sensitive", NULL); + gtk_widget_set_sensitive (widget, FALSE); + } +} + +static void +e_html_editor_bind_font_color_after_mode_changed_cb (EHTMLEditor *self, + gpointer user_data) +{ + GtkWidget *widget = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (self)); + g_return_if_fail (E_IS_COLOR_COMBO (widget)); + + e_html_editor_bind_color_combox_box (self, widget, "font-color"); +} + +static void +e_html_editor_bind_background_color_after_mode_changed_cb (EHTMLEditor *self, + gpointer user_data) +{ + GtkWidget *widget = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (self)); + g_return_if_fail (E_IS_COLOR_COMBO (widget)); + + e_html_editor_bind_color_combox_box (self, widget, "background-color"); +} + +static GObject * +e_html_editor_create_submenu_from_actions (EHTMLEditor *self, + const gchar *label, + GPtrArray *actions) /* EUIAction * */ +{ + GMenuItem *submenu; + GMenu *menu; + guint ii, n_added = 0; + + menu = g_menu_new (); + + for (ii = 0; ii < actions->len; ii++) { + EUIAction *subaction = g_ptr_array_index (actions, ii); + GMenuItem *item; + + if (!e_ui_action_is_visible (subaction)) + continue; + + item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (self->priv->ui_manager, item, subaction); + /* to not look like a radio item */ + g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_TARGET, NULL); + g_menu_append_item (menu, item); + g_clear_object (&item); + + n_added++; + } + + if (n_added) { + if (label) + submenu = g_menu_item_new_submenu (label, G_MENU_MODEL (menu)); + else + submenu = g_menu_item_new_section (NULL, G_MENU_MODEL (menu)); + } else { + submenu = NULL; + } + + g_clear_object (&menu); + + return submenu ? G_OBJECT (submenu) : NULL; +} + +static GObject * +e_html_editor_create_spell_add_menu (EHTMLEditor *self, + EUIAction *action) +{ + return e_html_editor_create_submenu_from_actions (self, e_ui_action_get_label (action), self->priv->spell_add_actions); +} + +static gboolean +e_html_editor_spell_is_single_lang (EHTMLEditor *self) +{ + EContentEditor *cnt_editor; + ESpellChecker *spell_checker; + gboolean single_lang; + + cnt_editor = e_html_editor_get_content_editor (self); + spell_checker = e_content_editor_ref_spell_checker (cnt_editor); + single_lang = spell_checker && e_spell_checker_count_active_languages (spell_checker) == 1; + g_clear_object (&spell_checker); + + return single_lang; +} + +static GObject * +e_html_editor_create_spell_suggest (EHTMLEditor *self, + EUIAction *action) +{ + GMenu *menu; + GMenuItem *item; + GHashTableIter iter; + GHashTable *submenu_by_action; /* EUIAction ~> GMenu */ + gpointer value; + guint ii, n_added = 0; + + if (e_html_editor_spell_is_single_lang (self)) + return e_html_editor_create_submenu_from_actions (self, NULL, self->priv->spell_suggest_actions); + + submenu_by_action = g_hash_table_new (g_direct_hash, g_direct_equal); + + g_hash_table_iter_init (&iter, self->priv->spell_suggest_menus_by_code); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + EHTMLEditorActionMenuPair *pair = value; + + if (e_ui_action_is_visible (pair->parent_menu_action)) + g_hash_table_insert (submenu_by_action, pair->parent_menu_action, pair->submenu_items); + } + + menu = g_menu_new (); + + for (ii = 0; ii < self->priv->spell_suggest_actions->len; ii++) { + EUIAction *subaction = g_ptr_array_index (self->priv->spell_suggest_actions, ii); + GMenuModel *submenu; + + if (!e_ui_action_is_visible (subaction)) + continue; + + submenu = g_hash_table_lookup (submenu_by_action, subaction); + if (!submenu) { + g_warn_if_reached (); + continue; + } + + item = g_menu_item_new_submenu (e_ui_action_get_label (subaction), submenu); + g_menu_append_item (menu, item); + g_clear_object (&item); + + n_added++; + } + + g_hash_table_destroy (submenu_by_action); + + if (n_added) + item = g_menu_item_new_section (NULL, G_MENU_MODEL (menu)); + else + item = NULL; + + g_clear_object (&menu); + + return item ? G_OBJECT (item) : NULL; +} + +static GObject * +e_html_editor_create_spell_suggest_more_menu (EHTMLEditor *self, + EUIAction *action) +{ + if (!e_html_editor_spell_is_single_lang (self)) + return NULL; + + return e_html_editor_create_submenu_from_actions (self, e_ui_action_get_label (action), self->priv->spell_suggest_more_actions); +} + +static gboolean +e_html_editor_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EHTMLEditor *self = user_data; + const gchar *name; + + g_return_val_if_fail (E_IS_HTML_EDITOR (self), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "EHTMLEditor::")) + return FALSE; + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (for_kind == E_UI_ELEMENT_KIND_MENU) { + if (is_action ("EHTMLEditor::recent-languages")) + *out_item = G_OBJECT (g_menu_item_new_section (NULL, G_MENU_MODEL (self->priv->recent_languages_menu))); + else if (is_action ("EHTMLEditor::all-languages")) + *out_item = G_OBJECT (g_menu_item_new_section (NULL, G_MENU_MODEL (self->priv->all_languages_menu))); + else if (is_action ("EHTMLEditor::context-spell-suggest")) + *out_item = e_html_editor_create_spell_suggest (self, action); + else if (is_action ("EHTMLEditor::context-spell-suggest-more-menu")) + *out_item = e_html_editor_create_spell_suggest_more_menu (self, action); + else if (is_action ("EHTMLEditor::context-spell-add-menu")) + *out_item = e_html_editor_create_spell_add_menu (self, action); + else if (is_action ("EHTMLEditor::insert-emoticon")) + *out_item = G_OBJECT (g_menu_item_new_submenu (e_ui_action_get_label (action), G_MENU_MODEL (self->priv->emoticon_menu))); + else + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + GtkWidget *widget = NULL; + gboolean claimed = FALSE; + + if (is_action ("EHTMLEditor::editing-mode")) { + widget = e_action_combo_box_new_with_action (E_HTML_EDITOR_ACTION_MODE_HTML (self)); + gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); + gtk_widget_set_tooltip_text (widget, _("Editing Mode")); + } else if (is_action ("EHTMLEditor::paragraph-style")) { + widget = e_action_combo_box_new_with_action (E_HTML_EDITOR_ACTION_STYLE_NORMAL (self)); + gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); + gtk_widget_set_tooltip_text (widget, _("Paragraph Style")); + + /* Hide the items from the action combo box as well */ + g_signal_connect_object (self, "after-mode-changed", + G_CALLBACK (e_action_combo_box_update_model), widget, G_CONNECT_SWAPPED); + } else if (is_action ("EHTMLEditor::font-name")) { + widget = e_html_editor_util_create_font_name_combo (); + gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); + gtk_widget_set_tooltip_text (widget, _("Font Name")); + + g_signal_connect_object (self, "after-mode-changed", + G_CALLBACK (e_html_editor_bind_font_name_after_mode_changed_cb), widget, 0); + e_html_editor_bind_font_name_after_mode_changed_cb (self, widget); + } else if (is_action ("EHTMLEditor::font-size")) { + widget = e_action_combo_box_new_with_action (E_HTML_EDITOR_ACTION_SIZE_PLUS_ZERO (self)); + gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); + gtk_widget_set_tooltip_text (widget, _("Font Size")); + } else if (is_action ("EHTMLEditor::font-color")) { + widget = e_color_combo_new (); + gtk_widget_set_tooltip_text (widget, _("Font Color")); + + g_signal_connect_object (self, "after-mode-changed", + G_CALLBACK (e_html_editor_bind_font_color_after_mode_changed_cb), widget, 0); + e_html_editor_bind_font_color_after_mode_changed_cb (self, widget); + } else if (is_action ("EHTMLEditor::background-color")) { + GdkRGBA transparent = { 0, 0, 0, 0 }; + + widget = e_color_combo_new (); + e_color_combo_set_default_color (E_COLOR_COMBO (widget), &transparent); + e_color_combo_set_current_color (E_COLOR_COMBO (widget), &transparent); + e_color_combo_set_default_transparent (E_COLOR_COMBO (widget), TRUE); + gtk_widget_set_tooltip_text (widget, _("Background Color")); + + g_signal_connect_object (self, "after-mode-changed", + G_CALLBACK (e_html_editor_bind_background_color_after_mode_changed_cb), widget, 0); + e_html_editor_bind_background_color_after_mode_changed_cb (self, widget); + } else { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + claimed = TRUE; + } + + if (widget) { + GtkToolItem *tool_item; + + tool_item = gtk_tool_item_new (); + gtk_container_add (GTK_CONTAINER (tool_item), widget); + gtk_widget_show_all (GTK_WIDGET (tool_item)); + + *out_item = G_OBJECT (tool_item); + } else if (!claimed) { + g_warning ("%s: Did not get toolbar widget for '%s'", G_STRFUNC, name); + } + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + #undef is_action + + return TRUE; +} + static void html_editor_set_property (GObject *object, guint property_id, @@ -875,10 +1234,9 @@ html_editor_constructed (GObject *object) EHTMLEditor *editor = E_HTML_EDITOR (object); EHTMLEditorPrivate *priv = editor->priv; GSettings *settings; - GdkRGBA transparent = { 0, 0, 0, 0 }; GtkWidget *widget; - GtkToolbar *toolbar; - GtkToolItem *tool_item; + gchar *filename; + GError *local_error = NULL; /* Chain up to parent's method. */ G_OBJECT_CLASS (e_html_editor_parent_class)->constructed (object); @@ -901,29 +1259,41 @@ html_editor_constructed (GObject *object) gtk_grid_attach (GTK_GRID (editor), widget, 0, 4, 1, 1); priv->content_editors_box = widget; - e_html_editor_actions_init (editor); + e_ui_manager_freeze (priv->ui_manager); + + e_html_editor_actions_add_actions (editor); priv->editor_layout_row = 2; - /* Tweak the main-toolbar style. */ - widget = e_html_editor_get_managed_widget (editor, "/main-toolbar"); - gtk_style_context_add_class ( - gtk_widget_get_style_context (widget), - GTK_STYLE_CLASS_PRIMARY_TOOLBAR); + filename = html_editor_find_ui_file ("e-html-editor.eui"); + + if (!e_ui_parser_merge_file (e_ui_manager_get_parser (priv->ui_manager), filename, &local_error)) + g_critical ("Couldn't load .eui file: %s", local_error ? local_error->message : "Unknown error"); + + g_free (filename); + g_clear_error (&local_error); + + e_ui_manager_thaw (priv->ui_manager); + + priv->main_menu = E_UI_MENU (e_ui_manager_create_item (editor->priv->ui_manager, "main-menu")); + + if (e_util_get_use_header_bar ()) + widget = GTK_WIDGET (e_ui_manager_create_item (editor->priv->ui_manager, "main-toolbar-with-headerbar")); + else + widget = GTK_WIDGET (e_ui_manager_create_item (editor->priv->ui_manager, "main-toolbar-without-headerbar")); + editor->priv->main_toolbar = g_object_ref_sink (widget); /* Construct the editing toolbars. */ - widget = e_html_editor_get_managed_widget (editor, "/edit-toolbar"); + widget = GTK_WIDGET (e_ui_manager_create_item (editor->priv->ui_manager, "edit-toolbar")); gtk_widget_set_hexpand (widget, TRUE); gtk_toolbar_set_style (GTK_TOOLBAR (widget), GTK_TOOLBAR_BOTH_HORIZ); - e_util_setup_toolbar_icon_size (GTK_TOOLBAR (widget), GTK_ICON_SIZE_BUTTON); gtk_grid_attach (GTK_GRID (editor), widget, 0, 0, 1, 1); priv->edit_toolbar = g_object_ref (widget); gtk_widget_show (widget); - widget = e_html_editor_get_managed_widget (editor, "/html-toolbar"); + widget = GTK_WIDGET (e_ui_manager_create_item (editor->priv->ui_manager, "html-toolbar")); gtk_widget_set_hexpand (widget, TRUE); gtk_toolbar_set_style (GTK_TOOLBAR (widget), GTK_TOOLBAR_BOTH_HORIZ); - e_util_setup_toolbar_icon_size (GTK_TOOLBAR (widget), GTK_ICON_SIZE_BUTTON); gtk_grid_attach (GTK_GRID (editor), widget, 0, 1, 1, 1); priv->html_toolbar = g_object_ref (widget); @@ -942,81 +1312,15 @@ html_editor_constructed (GObject *object) priv->alert_bar = g_object_ref (widget); /* EAlertBar controls its own visibility. */ + e_ui_manager_freeze (priv->ui_manager); + /* do this only when the EUIMenu and others are available */ + e_html_editor_actions_setup_actions (editor); + e_ui_manager_thaw (priv->ui_manager); + /* Have the default editor added (it's done inside the function) */ widget = GTK_WIDGET (e_html_editor_get_content_editor (editor)); gtk_widget_show (widget); - /* Add some combo boxes to the "edit" toolbar. */ - - toolbar = GTK_TOOLBAR (priv->edit_toolbar); - - tool_item = gtk_tool_item_new (); - widget = e_action_combo_box_new_with_action ( - GTK_RADIO_ACTION (ACTION (STYLE_NORMAL))); - gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); - gtk_container_add (GTK_CONTAINER (tool_item), widget); - gtk_widget_set_tooltip_text (widget, _("Paragraph Style")); - gtk_toolbar_insert (toolbar, tool_item, 0); - priv->style_combo_box = g_object_ref (widget); - gtk_widget_show_all (GTK_WIDGET (tool_item)); - - tool_item = gtk_separator_tool_item_new (); - gtk_toolbar_insert (toolbar, tool_item, 0); - gtk_widget_show_all (GTK_WIDGET (tool_item)); - - tool_item = gtk_tool_item_new (); - widget = e_action_combo_box_new_with_action ( - GTK_RADIO_ACTION (ACTION (MODE_HTML))); - gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); - gtk_container_add (GTK_CONTAINER (tool_item), widget); - gtk_widget_set_tooltip_text (widget, _("Editing Mode")); - gtk_toolbar_insert (toolbar, tool_item, 0); - priv->mode_combo_box = g_object_ref (widget); - priv->mode_tool_item = g_object_ref (tool_item); - gtk_widget_show_all (GTK_WIDGET (tool_item)); - - /* Add some combo boxes to the "html" toolbar. */ - - toolbar = GTK_TOOLBAR (priv->html_toolbar); - - tool_item = gtk_tool_item_new (); - widget = e_color_combo_new (); - gtk_container_add (GTK_CONTAINER (tool_item), widget); - gtk_widget_set_tooltip_text (widget, _("Font Color")); - gtk_toolbar_insert (toolbar, tool_item, 0); - priv->fg_color_combo_box = g_object_ref (widget); - gtk_widget_show_all (GTK_WIDGET (tool_item)); - - tool_item = gtk_tool_item_new (); - widget = e_color_combo_new (); - e_color_combo_set_default_color (E_COLOR_COMBO (widget), &transparent); - e_color_combo_set_current_color (E_COLOR_COMBO (widget), &transparent); - e_color_combo_set_default_transparent (E_COLOR_COMBO (widget), TRUE); - gtk_container_add (GTK_CONTAINER (tool_item), widget); - gtk_widget_set_tooltip_text (widget, _("Background Color")); - gtk_toolbar_insert (toolbar, tool_item, 1); - priv->bg_color_combo_box = g_object_ref (widget); - gtk_widget_show_all (GTK_WIDGET (tool_item)); - - tool_item = gtk_tool_item_new (); - widget = e_action_combo_box_new_with_action ( - GTK_RADIO_ACTION (ACTION (SIZE_PLUS_ZERO))); - gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); - gtk_container_add (GTK_CONTAINER (tool_item), widget); - gtk_widget_set_tooltip_text (widget, _("Font Size")); - gtk_toolbar_insert (toolbar, tool_item, 0); - priv->size_combo_box = g_object_ref (widget); - gtk_widget_show_all (GTK_WIDGET (tool_item)); - - tool_item = gtk_tool_item_new (); - widget = e_html_editor_util_create_font_name_combo (); - gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); - gtk_container_add (GTK_CONTAINER (tool_item), widget); - gtk_widget_set_tooltip_text (widget, _("Font Name")); - gtk_toolbar_insert (toolbar, tool_item, 0); - priv->font_name_combo_box = g_object_ref (widget); - gtk_widget_show_all (GTK_WIDGET (tool_item)); - e_binding_bind_property_full ( editor, "mode", E_HTML_EDITOR_ACTION (editor, "paragraph-style-menu"), "visible", @@ -1085,15 +1389,24 @@ html_editor_dispose (GObject *object) if (self->priv->mode_change_content_cancellable) g_cancellable_cancel (self->priv->mode_change_content_cancellable); - g_clear_object (&self->priv->manager); - g_clear_object (&self->priv->core_actions); - g_clear_object (&self->priv->core_editor_actions); - g_clear_object (&self->priv->html_actions); - g_clear_object (&self->priv->context_actions); - g_clear_object (&self->priv->html_context_actions); - g_clear_object (&self->priv->language_actions); - g_clear_object (&self->priv->spell_check_actions); - g_clear_object (&self->priv->suggestion_actions); + g_clear_object (&self->priv->ui_manager); + + self->priv->core_actions = NULL; + self->priv->core_editor_actions = NULL; + self->priv->html_actions = NULL; + self->priv->context_actions = NULL; + self->priv->html_context_actions = NULL; + self->priv->language_actions = NULL; + self->priv->spell_check_actions = NULL; + self->priv->suggestion_actions = NULL; + + g_clear_object (&self->priv->emoticon_menu); + g_clear_object (&self->priv->recent_languages_menu); + g_clear_object (&self->priv->all_languages_menu); + g_clear_pointer (&self->priv->spell_suggest_actions, g_ptr_array_unref); + g_clear_pointer (&self->priv->spell_suggest_more_actions, g_ptr_array_unref); + g_clear_pointer (&self->priv->spell_add_actions, g_ptr_array_unref); + g_clear_pointer (&self->priv->spell_suggest_menus_by_code, g_hash_table_unref); g_clear_object (&self->priv->main_menu); g_clear_object (&self->priv->main_toolbar); @@ -1104,14 +1417,6 @@ html_editor_dispose (GObject *object) g_clear_object (&self->priv->edit_area); g_clear_object (&self->priv->markdown_editor); - g_clear_object (&self->priv->fg_color_combo_box); - g_clear_object (&self->priv->bg_color_combo_box); - g_clear_object (&self->priv->mode_combo_box); - g_clear_object (&self->priv->mode_tool_item); - g_clear_object (&self->priv->size_combo_box); - g_clear_object (&self->priv->font_name_combo_box); - g_clear_object (&self->priv->style_combo_box); - g_clear_object (&self->priv->mode_change_content_cancellable); g_clear_pointer (&self->priv->filename, g_free); @@ -1223,6 +1528,15 @@ e_html_editor_class_init (EHTMLEditorClass *class) NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + signals[AFTER_MODE_CHANGED] = g_signal_new ( + "after-mode-changed", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void @@ -1232,36 +1546,33 @@ e_html_editor_alert_sink_init (EAlertSinkInterface *interface) } static void -e_html_editor_init (EHTMLEditor *editor) +e_html_editor_init (EHTMLEditor *self) { - EHTMLEditorPrivate *priv; - gchar *filename; - GError *error = NULL; + self->priv = e_html_editor_get_instance_private (self); + self->priv->mode = E_CONTENT_EDITOR_MODE_HTML; + self->priv->ui_manager = e_ui_manager_new (); + self->priv->core_actions = e_ui_manager_get_action_group (self->priv->ui_manager, "core"); + self->priv->core_editor_actions = e_ui_manager_get_action_group (self->priv->ui_manager, "core-editor"); + self->priv->html_actions = e_ui_manager_get_action_group (self->priv->ui_manager, "html"); + self->priv->context_actions = e_ui_manager_get_action_group (self->priv->ui_manager, "core-context"); + self->priv->html_context_actions = e_ui_manager_get_action_group (self->priv->ui_manager, "html-context"); + self->priv->language_actions = e_ui_manager_get_action_group (self->priv->ui_manager, "language"); + self->priv->spell_check_actions = e_ui_manager_get_action_group (self->priv->ui_manager, "spell-check"); + self->priv->suggestion_actions = e_ui_manager_get_action_group (self->priv->ui_manager, "suggestion"); + self->priv->cid_parts = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, g_object_unref); + self->priv->content_editors = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, NULL); + self->priv->content_editors_for_mode = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); - editor->priv = e_html_editor_get_instance_private (editor); + self->priv->emoticon_menu = g_menu_new (); + self->priv->recent_languages_menu = g_menu_new (); + self->priv->all_languages_menu = g_menu_new (); + self->priv->spell_suggest_actions = g_ptr_array_new_with_free_func (g_object_unref); + self->priv->spell_suggest_more_actions = g_ptr_array_new_with_free_func (g_object_unref); + self->priv->spell_add_actions = g_ptr_array_new_with_free_func (g_object_unref); + self->priv->spell_suggest_menus_by_code = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, e_html_editor_action_menu_pair_free); - priv = editor->priv; - - priv->mode = E_CONTENT_EDITOR_MODE_HTML; - priv->manager = gtk_ui_manager_new (); - priv->core_actions = gtk_action_group_new ("core"); - priv->core_editor_actions = gtk_action_group_new ("core-editor"); - priv->html_actions = gtk_action_group_new ("html"); - priv->context_actions = gtk_action_group_new ("core-context"); - priv->html_context_actions = gtk_action_group_new ("html-context"); - priv->language_actions = gtk_action_group_new ("language"); - priv->spell_check_actions = gtk_action_group_new ("spell-check"); - priv->suggestion_actions = gtk_action_group_new ("suggestion"); - priv->cid_parts = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, g_object_unref); - priv->content_editors = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, NULL); - priv->content_editors_for_mode = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); - - filename = html_editor_find_ui_file ("e-html-editor-manager.ui"); - if (!gtk_ui_manager_add_ui_from_file (priv->manager, filename, &error)) { - g_critical ("Couldn't load builder file: %s\n", error->message); - g_clear_error (&error); - } - g_free (filename); + g_signal_connect_object (self->priv->ui_manager, "create-item", + G_CALLBACK (e_html_editor_ui_manager_create_item_cb), self, 0); } static void @@ -1793,6 +2104,8 @@ e_html_editor_set_mode (EHTMLEditor *editor, if (cnt_editor) { gboolean editor_changed = cnt_editor != editor->priv->use_content_editor; + e_ui_manager_freeze (editor->priv->ui_manager); + if (editor_changed) { EContentEditorInterface *iface; gboolean is_focused = FALSE; @@ -1824,19 +2137,12 @@ e_html_editor_set_mode (EHTMLEditor *editor, if (E_IS_MARKDOWN_EDITOR (editor->priv->use_content_editor)) { EMarkdownEditor *markdown_editor; - GtkToolbar *toolbar; GSettings *settings; markdown_editor = E_MARKDOWN_EDITOR (editor->priv->use_content_editor); e_markdown_editor_set_preview_mode (markdown_editor, FALSE); - toolbar = e_markdown_editor_get_action_toolbar (markdown_editor); - gtk_container_remove (GTK_CONTAINER (toolbar), GTK_WIDGET (editor->priv->mode_tool_item)); - - toolbar = GTK_TOOLBAR (editor->priv->edit_toolbar); - gtk_toolbar_insert (toolbar, editor->priv->mode_tool_item, 0); - settings = e_util_ref_settings ("org.gnome.evolution.mail"); if (g_settings_get_boolean (settings, "composer-show-edit-toolbar")) gtk_widget_show (GTK_WIDGET (editor->priv->edit_toolbar)); @@ -1847,13 +2153,24 @@ e_html_editor_set_mode (EHTMLEditor *editor, gtk_widget_show (GTK_WIDGET (cnt_editor)); if (E_IS_MARKDOWN_EDITOR (cnt_editor)) { - GtkToolbar *toolbar; + if (!g_object_get_data (G_OBJECT (cnt_editor), "EHTMLEditor::has-editing-mode")) { + GtkToolbar *toolbar; + GtkToolItem *tool_item; + GtkWidget *widget; - toolbar = GTK_TOOLBAR (editor->priv->edit_toolbar); - gtk_container_remove (GTK_CONTAINER (toolbar), GTK_WIDGET (editor->priv->mode_tool_item)); + g_object_set_data (G_OBJECT (cnt_editor), "EHTMLEditor::has-editing-mode", GINT_TO_POINTER (1)); - toolbar = e_markdown_editor_get_action_toolbar (E_MARKDOWN_EDITOR (cnt_editor)); - gtk_toolbar_insert (toolbar, editor->priv->mode_tool_item, 0); + widget = e_action_combo_box_new_with_action (ACTION (MODE_HTML)); + gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE); + gtk_widget_set_tooltip_text (widget, _("Editing Mode")); + + tool_item = gtk_tool_item_new (); + gtk_container_add (GTK_CONTAINER (tool_item), widget); + gtk_widget_show_all (GTK_WIDGET (tool_item)); + + toolbar = e_markdown_editor_get_action_toolbar (E_MARKDOWN_EDITOR (cnt_editor)); + gtk_toolbar_insert (toolbar, tool_item, 0); + } gtk_widget_hide (GTK_WIDGET (editor->priv->edit_toolbar)); } @@ -1865,7 +2182,7 @@ e_html_editor_set_mode (EHTMLEditor *editor, support moving between misspelled words. */ iface = E_CONTENT_EDITOR_GET_IFACE (cnt_editor); - gtk_action_set_visible (e_html_editor_get_action (editor, "spell-check"), + e_ui_action_set_visible (ACTION (SPELL_CHECK), iface && iface->spell_check_next_word && iface->spell_check_prev_word); e_content_editor_clear_undo_redo_history (cnt_editor); @@ -1886,6 +2203,8 @@ e_html_editor_set_mode (EHTMLEditor *editor, g_object_set (G_OBJECT (cnt_editor), "mode", mode, NULL); g_object_notify (G_OBJECT (editor), "mode"); + + e_ui_manager_thaw (editor->priv->ui_manager); } } @@ -1915,14 +2234,16 @@ e_html_editor_cancel_mode_change_content_update (EHTMLEditor *editor) * e_html_editor_get_ui_manager: * @editor: an #EHTMLEditor * - * Returns #GtkUIManager that manages all the actions in the @editor. + * Returns an #EUIManager that manages all the actions in the @editor. + * + * Returns: (transfer none): an internal #EUIManager */ -GtkUIManager * +EUIManager * e_html_editor_get_ui_manager (EHTMLEditor *editor) { g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL); - return editor->priv->manager; + return editor->priv->ui_manager; } /** @@ -1930,95 +2251,55 @@ e_html_editor_get_ui_manager (EHTMLEditor *editor) * @editor: an #EHTMLEditor * @action_name: name of action to lookup and return * - * Returns: A #GtkAction matching @action_name or @NULL if no such action exists. + * Gets action named @action_name from the internal #EUIManager. + * + * Returns: (transfer none) (nullable): an #EUIAction matching @action_name or + * %NULL, if no such action exists */ -GtkAction * +EUIAction * e_html_editor_get_action (EHTMLEditor *editor, const gchar *action_name) { - GtkUIManager *manager; - GtkAction *action = NULL; - GList *list; + EUIManager *ui_manager; g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL); g_return_val_if_fail (action_name != NULL, NULL); - manager = e_html_editor_get_ui_manager (editor); - list = gtk_ui_manager_get_action_groups (manager); + ui_manager = e_html_editor_get_ui_manager (editor); - while (list != NULL && action == NULL) { - GtkActionGroup *action_group = list->data; - - action = gtk_action_group_get_action ( - action_group, action_name); - - list = g_list_next (list); - } - - g_return_val_if_fail (action != NULL, NULL); - - return action; + return e_ui_manager_get_action (ui_manager, action_name); } /** - * e_html_editor_get_action_group: + * e_html_editor_get_ui_object: * @editor: an #EHTMLEditor - * @group_name: name of action group to lookup and return + * @object_name: an object name to get * - * Returns: A #GtkActionGroup matching @group_name or @NULL if not such action - * group exists. - */ -GtkActionGroup * -e_html_editor_get_action_group (EHTMLEditor *editor, - const gchar *group_name) + * Gets a UI object (usually a GtkWidget descendant) by its name. + * There are only few objects recognized, namely: + * E_HTML_EDITOR_UI_OBJECT_MAIN_MENU: the main menu as an #EUIMenu; + * E_HTML_EDITOR_UI_OBJECT_MAIN_TOOLBAR: the main toolbar as a #GtkToolbar. + * + * Returns: (transfer none) (nullable): the UI object named @object_name, or %NULL, + * when the name is not recognized. + * + * Since: 3.56 + **/ +gpointer +e_html_editor_get_ui_object (EHTMLEditor *editor, + const gchar *object_name) { - GtkUIManager *manager; - GList *list; + gpointer object = NULL; g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL); - g_return_val_if_fail (group_name != NULL, NULL); + g_return_val_if_fail (object_name != NULL, NULL); - manager = e_html_editor_get_ui_manager (editor); - list = gtk_ui_manager_get_action_groups (manager); + if (g_strcmp0 (object_name, E_HTML_EDITOR_UI_OBJECT_MAIN_MENU) == 0) + object = editor->priv->main_menu; + else if (g_strcmp0 (object_name, E_HTML_EDITOR_UI_OBJECT_MAIN_TOOLBAR) == 0) + object = editor->priv->main_toolbar; - while (list != NULL) { - GtkActionGroup *action_group = list->data; - const gchar *name; - - name = gtk_action_group_get_name (action_group); - if (strcmp (name, group_name) == 0) - return action_group; - - list = g_list_next (list); - } - - return NULL; -} - -GtkWidget * -e_html_editor_get_managed_widget (EHTMLEditor *editor, - const gchar *widget_path) -{ - GtkUIManager *manager; - GtkWidget *widget; - - g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL); - g_return_val_if_fail (widget_path != NULL, NULL); - - manager = e_html_editor_get_ui_manager (editor); - widget = gtk_ui_manager_get_widget (manager, widget_path); - - g_return_val_if_fail (widget != NULL, NULL); - - return widget; -} - -GtkWidget * -e_html_editor_get_style_combo_box (EHTMLEditor *editor) -{ - g_return_val_if_fail (E_IS_HTML_EDITOR (editor), NULL); - - return editor->priv->style_combo_box; + return object; } /** diff --git a/src/e-util/e-html-editor.h b/src/e-util/e-html-editor.h index 997f3e113f..8271feba7f 100644 --- a/src/e-util/e-html-editor.h +++ b/src/e-util/e-html-editor.h @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include /* Standard GObject macros */ #define E_TYPE_HTML_EDITOR \ @@ -54,6 +57,9 @@ #define E_HTML_EDITOR_MAX_INDENT_LEVEL 10 +#define E_HTML_EDITOR_UI_OBJECT_MAIN_MENU "main-menu" +#define E_HTML_EDITOR_UI_OBJECT_MAIN_TOOLBAR "main-toolbar" + G_BEGIN_DECLS typedef struct _EHTMLEditor EHTMLEditor; @@ -100,18 +106,11 @@ void e_html_editor_set_mode (EHTMLEditor *editor, void e_html_editor_cancel_mode_change_content_update (EHTMLEditor *editor); GtkBuilder * e_html_editor_get_builder (EHTMLEditor *editor); -GtkUIManager * e_html_editor_get_ui_manager (EHTMLEditor *editor); -GtkAction * e_html_editor_get_action (EHTMLEditor *editor, +EUIManager * e_html_editor_get_ui_manager (EHTMLEditor *editor); +EUIAction * e_html_editor_get_action (EHTMLEditor *editor, const gchar *action_name); -GtkActionGroup *e_html_editor_get_action_group (EHTMLEditor *editor, - const gchar *group_name); -GtkWidget * e_html_editor_get_widget (EHTMLEditor *editor, - const gchar *widget_name); -GtkWidget * e_html_editor_get_managed_widget - (EHTMLEditor *editor, - const gchar *widget_path); -GtkWidget * e_html_editor_get_style_combo_box - (EHTMLEditor *editor); +gpointer e_html_editor_get_ui_object (EHTMLEditor *editor, + const gchar *object_name); const gchar * e_html_editor_get_filename (EHTMLEditor *editor); void e_html_editor_set_filename (EHTMLEditor *editor, const gchar *filename); diff --git a/src/e-util/e-mail-signature-editor.c b/src/e-util/e-mail-signature-editor.c index 7faeba3090..6fe4d9551f 100644 --- a/src/e-util/e-mail-signature-editor.c +++ b/src/e-util/e-mail-signature-editor.c @@ -34,7 +34,7 @@ typedef struct _AsyncContext AsyncContext; struct _EMailSignatureEditorPrivate { EHTMLEditor *editor; - GtkActionGroup *action_group; + EUIActionGroup *action_group; EFocusTracker *focus_tracker; GCancellable *cancellable; ESourceRegistry *registry; @@ -44,6 +44,7 @@ struct _EMailSignatureEditorPrivate { GtkWidget *entry; /* not referenced */ EMenuBar *menu_bar; + GtkWidget *menu_button; /* owned by menu_bar */ }; struct _AsyncContext { @@ -64,24 +65,6 @@ enum { PROP_SOURCE }; -static const gchar *ui = -"\n" -" \n" -" \n" -" \n" -" \n" -" " -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -""; - G_DEFINE_TYPE_WITH_PRIVATE (EMailSignatureEditor, e_mail_signature_editor, GTK_TYPE_WINDOW) static void @@ -188,26 +171,28 @@ static gboolean mail_signature_editor_delete_event_cb (EMailSignatureEditor *editor, GdkEvent *event) { - GtkActionGroup *action_group; - GtkAction *action; + EUIAction *action; - action_group = editor->priv->action_group; - action = gtk_action_group_get_action (action_group, "close"); - gtk_action_activate (action); + action = e_ui_action_group_get_action (editor->priv->action_group, "close"); + g_action_activate (G_ACTION (action), NULL); return TRUE; } static void -action_close_cb (GtkAction *action, - EMailSignatureEditor *window) +action_close_cb (EUIAction *action, + GVariant *parametr, + gpointer user_data) { + EMailSignatureEditor *window = user_data; EHTMLEditor *editor; EContentEditor *cnt_editor; gboolean something_changed = FALSE; const gchar *original_name; const gchar *signature_name; + g_return_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (window)); + editor = e_mail_signature_editor_get_editor (window); cnt_editor = e_html_editor_get_content_editor (editor); @@ -224,13 +209,10 @@ action_close_cb (GtkAction *action, GTK_WINDOW (window), "widgets:ask-signature-changed", NULL); if (response == GTK_RESPONSE_YES) { - GtkActionGroup *action_group; - GtkAction *action2; + EUIAction *action2; - action_group = window->priv->action_group; - action2 = gtk_action_group_get_action ( - action_group, "save-and-close"); - gtk_action_activate (action2); + action2 = e_ui_action_group_get_action (window->priv->action_group, "save-and-close"); + g_action_activate (G_ACTION (action2), NULL); return; } else if (response == GTK_RESPONSE_CANCEL) return; @@ -283,13 +265,17 @@ mail_signature_editor_commit_ready_cb (GObject *source_object, } static void -action_save_and_close_cb (GtkAction *action, - EMailSignatureEditor *editor) +action_save_and_close_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailSignatureEditor *editor = user_data; GtkEntry *entry; ESource *source; gchar *display_name; + g_return_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (editor)); + entry = GTK_ENTRY (editor->priv->entry); source = e_mail_signature_editor_get_source (editor); @@ -322,29 +308,35 @@ action_save_and_close_cb (GtkAction *action, mail_signature_editor_commit_ready_cb, NULL); } -static GtkActionEntry entries[] = { +static gboolean +e_mail_signature_editor_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EMailSignatureEditor *self = user_data; + const gchar *name; - { "close", - "window-close", - N_("_Close"), - "w", - N_("Close"), - G_CALLBACK (action_close_cb) }, + g_return_val_if_fail (E_IS_MAIL_SIGNATURE_EDITOR (self), FALSE); - { "save-and-close", - "document-save", - N_("_Save and Close"), - "Return", - N_("Save and Close"), - G_CALLBACK (action_save_and_close_cb) }, + name = g_action_get_name (G_ACTION (action)); - { "file-menu", - NULL, - N_("_File"), - NULL, - NULL, - NULL } -}; + if (!g_str_has_prefix (name, "EMailSignatureEditor::")) + return FALSE; + + if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + if (g_str_equal (name, "EMailSignatureEditor::menu-button")) + *out_item = G_OBJECT (g_object_ref (self->priv->menu_button)); + else + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + return TRUE; +} static void mail_signature_editor_set_editor (EMailSignatureEditor *editor, @@ -503,22 +495,64 @@ mail_signature_editor_finalize (GObject *object) static void mail_signature_editor_constructed (GObject *object) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry entries[] = { + + { "close", + "window-close", + N_("_Close"), + "w", + N_("Close"), + action_close_cb, NULL, NULL, NULL }, + + { "save-and-close", + "document-save", + N_("_Save and Close"), + "Return", + N_("Save and Close"), + action_save_and_close_cb, NULL, NULL, NULL }, + + { "file-menu", NULL, N_("_File"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EMailSignatureEditor::menu-button", NULL, N_("Menu"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + EMailSignatureEditor *window; - GtkActionGroup *action_group; EFocusTracker *focus_tracker; EHTMLEditor *editor; EContentEditor *cnt_editor; - GtkUIManager *ui_manager; + EUIManager *ui_manager; + EUIAction *action; ESource *source; - GtkAction *action; + GObject *ui_item; GtkWidget *container; GtkWidget *widget; - GtkWidget *button; GtkWidget *hbox; - GtkWidget *menu_button = NULL; - GtkHeaderBar *header_bar; const gchar *display_name; - GError *error = NULL; /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_signature_editor_parent_class)->constructed (object); @@ -526,33 +560,21 @@ mail_signature_editor_constructed (GObject *object) window = E_MAIL_SIGNATURE_EDITOR (object); editor = e_mail_signature_editor_get_editor (window); cnt_editor = e_html_editor_get_content_editor (editor); - ui_manager = e_html_editor_get_ui_manager (editor); - /* Because we are loading from a hard-coded string, there is - * no chance of I/O errors. Failure here implies a malformed - * UI definition. Full stop. */ - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) - g_error ("%s", error->message); + g_signal_connect_object (ui_manager, "create-item", + G_CALLBACK (e_mail_signature_editor_ui_manager_create_item_cb), window, 0); - action_group = gtk_action_group_new ("signature"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, entries, - G_N_ELEMENTS (entries), window); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - window->priv->action_group = g_object_ref (action_group); + e_ui_manager_add_actions_with_eui_data (ui_manager, "signature", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), window, eui); + window->priv->action_group = g_object_ref (e_ui_manager_get_action_group (ui_manager, "signature")); /* Hide page properties because it is not inherited in the mail. */ action = e_html_editor_get_action (editor, "properties-page"); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); action = e_html_editor_get_action (editor, "context-properties-page"); - gtk_action_set_visible (action, FALSE); - - gtk_ui_manager_ensure_update (ui_manager); + e_ui_action_set_visible (action, FALSE); gtk_window_set_default_size (GTK_WINDOW (window), -1, 440); @@ -562,45 +584,30 @@ mail_signature_editor_constructed (GObject *object) container = widget; - widget = e_html_editor_get_managed_widget (editor, "/main-menu"); - window->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (window), &menu_button); + ui_item = e_ui_manager_create_item (ui_manager, "main-menu"); + widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (ui_item)); + g_clear_object (&ui_item); + + window->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (window), &window->priv->menu_button); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); /* Construct the main menu and toolbar. */ if (e_util_get_use_header_bar ()) { - widget = gtk_header_bar_new (); - gtk_widget_show (widget); - header_bar = GTK_HEADER_BAR (widget); - gtk_header_bar_set_show_close_button (header_bar, TRUE); - gtk_header_bar_set_title (header_bar, _("Edit Signature")); - gtk_window_set_titlebar (GTK_WINDOW (window), widget); + ui_item = e_ui_manager_create_item (ui_manager, "main-headerbar"); + widget = GTK_WIDGET (ui_item); + gtk_header_bar_set_title (GTK_HEADER_BAR (widget), _("Edit Signature")); - action = gtk_action_group_get_action (window->priv->action_group, "save-and-close"); - button = e_header_bar_button_new (_("Save"), action); - e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "suggested-action"); - e_header_bar_button_set_show_icon_only (E_HEADER_BAR_BUTTON (button), FALSE); - gtk_widget_show (button); - gtk_header_bar_pack_start (header_bar, button); - - if (menu_button) - gtk_header_bar_pack_end (header_bar, menu_button); - - widget = e_html_editor_get_managed_widget (editor, "/main-toolbar/pre-main-toolbar/save-and-close"); - gtk_widget_destroy (widget); + ui_item = e_ui_manager_create_item (ui_manager, "main-toolbar-with-headerbar"); } else { gtk_window_set_title (GTK_WINDOW (window), _("Edit Signature")); - widget = e_html_editor_get_managed_widget (editor, "/main-toolbar"); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - if (menu_button) { - g_object_ref_sink (menu_button); - gtk_widget_destroy (menu_button); - } + ui_item = e_ui_manager_create_item (ui_manager, "main-toolbar-without-headerbar"); } + widget = GTK_WIDGET (ui_item); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + /* Construct the signature name entry. */ widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); diff --git a/src/e-util/e-menu-bar.c b/src/e-util/e-menu-bar.c index cde744b70d..4dd9497813 100644 --- a/src/e-util/e-menu-bar.c +++ b/src/e-util/e-menu-bar.c @@ -153,6 +153,7 @@ menu_bar_dispose (GObject *menu_bar) self->priv->delayed_hide_id = 0; } + g_clear_object (&self->priv->inner_menu_bar); g_clear_object (&self->priv->menu_button); /* Chain up to parent's method. */ @@ -204,11 +205,11 @@ static gboolean delayed_hide_cb (gpointer user_data) { EMenuBar *self = user_data; - GtkWidget *widget = GTK_WIDGET (self->priv->inner_menu_bar); + GtkWidget *widget = self->priv->inner_menu_bar; self->priv->delayed_hide_id = 0; - if (!self->priv->visible && + if (!self->priv->visible && widget && !self->priv->delayed_show_id) { if (gtk_widget_get_visible (widget) && !gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (self->priv->inner_menu_bar))) @@ -302,7 +303,7 @@ e_menu_bar_new (GtkMenuBar *inner_menu_bar, g_return_val_if_fail (GTK_IS_WINDOW (window), NULL); self = g_object_new (E_TYPE_MENU_BAR, NULL); - self->priv->inner_menu_bar = GTK_WIDGET (inner_menu_bar); + self->priv->inner_menu_bar = GTK_WIDGET (g_object_ref_sink (inner_menu_bar)); settings = e_util_ref_settings ("org.gnome.evolution.shell"); g_signal_connect_object ( diff --git a/src/e-util/e-menu-tool-action.c b/src/e-util/e-menu-tool-action.c deleted file mode 100644 index 97e52765b6..0000000000 --- a/src/e-util/e-menu-tool-action.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * e-menu-tool-action.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include "evolution-config.h" - -#include "e-menu-tool-action.h" - -G_DEFINE_TYPE ( - EMenuToolAction, - e_menu_tool_action, - GTK_TYPE_ACTION) - -static void -e_menu_tool_action_class_init (EMenuToolActionClass *class) -{ - GtkActionClass *action_class; - - action_class = GTK_ACTION_CLASS (class); - action_class->toolbar_item_type = GTK_TYPE_MENU_TOOL_BUTTON; -} - -static void -e_menu_tool_action_init (EMenuToolAction *action) -{ -} - -EMenuToolAction * -e_menu_tool_action_new (const gchar *name, - const gchar *label, - const gchar *tooltip) -{ - g_return_val_if_fail (name != NULL, NULL); - - return g_object_new ( - E_TYPE_MENU_TOOL_ACTION, - "name", name, - "label", label, - "tooltip", tooltip, - NULL); -} diff --git a/src/e-util/e-menu-tool-action.h b/src/e-util/e-menu-tool-action.h deleted file mode 100644 index 1cb16a77aa..0000000000 --- a/src/e-util/e-menu-tool-action.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * e-menu-tool-action.h - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* This is a trivial GtkAction subclass that sets the toolbar - * item type to GtkMenuToolButton instead of GtkToolButton. */ - -#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) -#error "Only should be included directly." -#endif - -#ifndef E_MENU_TOOL_ACTION_H -#define E_MENU_TOOL_ACTION_H - -#include - -/* Standard GObject macros */ -#define E_TYPE_MENU_TOOL_ACTION \ - (e_menu_tool_action_get_type ()) -#define E_MENU_TOOL_ACTION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_MENU_TOOL_ACTION, EMenuToolAction)) -#define E_MENU_TOOL_ACTION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_MENU_TOOL_ACTION, EMenuToolActionClass)) -#define E_IS_MENU_TOOL_ACTION(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_MENU_TOOL_ACTION)) -#define E_IS_MENU_TOOL_ACTION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_MENU_TOOL_ACTION)) -#define E_MENU_TOOL_ACTION_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_MENU_TOOL_ACTION, EMenuToolActionClass)) - -G_BEGIN_DECLS - -typedef struct _EMenuToolAction EMenuToolAction; -typedef struct _EMenuToolActionClass EMenuToolActionClass; - -struct _EMenuToolAction { - GtkAction parent; -}; - -struct _EMenuToolActionClass { - GtkActionClass parent_class; -}; - -GType e_menu_tool_action_get_type (void) G_GNUC_CONST; -EMenuToolAction * - e_menu_tool_action_new (const gchar *name, - const gchar *label, - const gchar *tooltip); - -G_END_DECLS - -#endif /* E_MENU_TOOL_ACTION_H */ diff --git a/src/e-util/e-menu-tool-button.c b/src/e-util/e-menu-tool-button.c index 2f70da834b..9f489dbfa3 100644 --- a/src/e-util/e-menu-tool-button.c +++ b/src/e-util/e-menu-tool-button.c @@ -20,136 +20,53 @@ #include "evolution-config.h" -#include "e-menu-tool-button.h" #include "e-misc-utils.h" +#include "e-ui-manager.h" + +#include "e-menu-tool-button.h" struct _EMenuToolButtonPrivate { gchar *prefer_item; + EUIManager *ui_manager; }; enum { PROP_0, - PROP_PREFER_ITEM + PROP_PREFER_ITEM, + PROP_UI_MANAGER }; G_DEFINE_TYPE_WITH_PRIVATE (EMenuToolButton, e_menu_tool_button, GTK_TYPE_MENU_TOOL_BUTTON) -static GtkWidget * -menu_tool_button_clone_image (GtkWidget *source) +static EUIAction * +menu_tool_button_get_prefer_item_action (EMenuToolButton *self) { - GtkIconSize size; - GtkImageType image_type; - const gchar *icon_name; - - /* XXX This isn't general purpose because it requires that the - * source image be using a named icon. Somewhat surprised - * GTK+ doesn't offer something like this. */ - image_type = gtk_image_get_storage_type (GTK_IMAGE (source)); - g_return_val_if_fail (image_type == GTK_IMAGE_ICON_NAME, NULL); - gtk_image_get_icon_name (GTK_IMAGE (source), &icon_name, &size); - - return gtk_image_new_from_icon_name (icon_name, size); -} - -static GtkMenuItem * -menu_tool_button_get_prefer_menu_item (GtkMenuToolButton *menu_tool_button) -{ - GtkWidget *menu; - GtkMenuItem *item = NULL; - GList *children; - const gchar *prefer_item; - - menu = gtk_menu_tool_button_get_menu (menu_tool_button); - if (!GTK_IS_MENU (menu)) + if (!self->priv->ui_manager || + !self->priv->prefer_item) return NULL; - children = gtk_container_get_children (GTK_CONTAINER (menu)); - if (children == NULL) - return NULL; - - prefer_item = e_menu_tool_button_get_prefer_item ( - E_MENU_TOOL_BUTTON (menu_tool_button)); - if (prefer_item != NULL && *prefer_item != '\0') { - GtkAction *action; - GList *link; - - for (link = children; link != NULL; link = g_list_next (link)) { - GtkWidget *child; - const gchar *name; - - child = GTK_WIDGET (link->data); - - if (!GTK_IS_MENU_ITEM (child)) - continue; - - action = gtk_activatable_get_related_action ( - GTK_ACTIVATABLE (child)); - - if (action != NULL) - name = gtk_action_get_name (action); - else - name = gtk_widget_get_name (child); - - if (g_strcmp0 (name, prefer_item) == 0) { - item = GTK_MENU_ITEM (child); - break; - } - } - } - - if (item == NULL) - item = GTK_MENU_ITEM (children->data); - - g_list_free (children); - - return item; + return e_ui_manager_get_action (self->priv->ui_manager, self->priv->prefer_item); } static void -menu_tool_button_update_button (GtkToolButton *tool_button) +menu_tool_button_update_button (EMenuToolButton *self) { - GtkMenuItem *menu_item; - GtkMenuToolButton *menu_tool_button; - GtkImageMenuItem *image_menu_item; - GtkAction *action; - GtkWidget *image; - gchar *tooltip = NULL; + EUIAction *action; + gchar *label; - menu_tool_button = GTK_MENU_TOOL_BUTTON (tool_button); - menu_item = menu_tool_button_get_prefer_menu_item (menu_tool_button); - if (!GTK_IS_IMAGE_MENU_ITEM (menu_item)) + action = menu_tool_button_get_prefer_item_action (self); + + if (!action) return; - image_menu_item = GTK_IMAGE_MENU_ITEM (menu_item); - image = gtk_image_menu_item_get_image (image_menu_item); - if (!GTK_IS_IMAGE (image)) - return; + /* preserve the label */ + label = g_strdup (gtk_tool_button_get_label (GTK_TOOL_BUTTON (self))); - image = menu_tool_button_clone_image (image); - gtk_tool_button_set_icon_widget (tool_button, image); - gtk_widget_show (image); + e_ui_manager_update_item_from_action (self->priv->ui_manager, self, action); - /* If the menu item is a proxy for a GtkAction, extract - * the action's tooltip and use it as our own tooltip. */ - action = gtk_activatable_get_related_action ( - GTK_ACTIVATABLE (menu_item)); - if (action != NULL) - g_object_get (action, "tooltip", &tooltip, NULL); - gtk_widget_set_tooltip_text (GTK_WIDGET (tool_button), tooltip); - g_free (tooltip); -} + gtk_tool_button_set_label (GTK_TOOL_BUTTON (self), label); -static void -menu_tool_button_clicked (GtkToolButton *tool_button) -{ - GtkMenuItem *menu_item; - GtkMenuToolButton *menu_tool_button; - - menu_tool_button = GTK_MENU_TOOL_BUTTON (tool_button); - menu_item = menu_tool_button_get_prefer_menu_item (menu_tool_button); - - if (GTK_IS_MENU_ITEM (menu_item)) - gtk_menu_item_activate (menu_item); + g_free (label); } static void @@ -164,6 +81,11 @@ menu_tool_button_set_property (GObject *object, E_MENU_TOOL_BUTTON (object), g_value_get_string (value)); return; + + case PROP_UI_MANAGER: + g_clear_object (&E_MENU_TOOL_BUTTON (object)->priv->ui_manager); + E_MENU_TOOL_BUTTON (object)->priv->ui_manager = g_value_dup_object (value); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -181,6 +103,10 @@ menu_tool_button_get_property (GObject *object, value, e_menu_tool_button_get_prefer_item ( E_MENU_TOOL_BUTTON (object))); return; + + case PROP_UI_MANAGER: + g_value_set_object (value, E_MENU_TOOL_BUTTON (object)->priv->ui_manager); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -191,6 +117,7 @@ menu_tool_button_finalize (GObject *object) { EMenuToolButton *self = E_MENU_TOOL_BUTTON (object); + g_clear_object (&self->priv->ui_manager); g_free (self->priv->prefer_item); /* Chain up to parent's finalize() method. */ @@ -201,16 +128,12 @@ static void e_menu_tool_button_class_init (EMenuToolButtonClass *class) { GObjectClass *object_class; - GtkToolButtonClass *tool_button_class; object_class = G_OBJECT_CLASS (class); object_class->set_property = menu_tool_button_set_property; object_class->get_property = menu_tool_button_get_property; object_class->finalize = menu_tool_button_finalize; - tool_button_class = GTK_TOOL_BUTTON_CLASS (class); - tool_button_class->clicked = menu_tool_button_clicked; - g_object_class_install_property ( object_class, PROP_PREFER_ITEM, @@ -220,6 +143,16 @@ e_menu_tool_button_class_init (EMenuToolButtonClass *class) "Name of an item to show instead of the first", NULL, G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_UI_MANAGER, + g_param_spec_object ( + "ui-manager", + NULL, + NULL, + E_TYPE_UI_MANAGER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } static void @@ -235,9 +168,13 @@ e_menu_tool_button_init (EMenuToolButton *button) } GtkToolItem * -e_menu_tool_button_new (const gchar *label) +e_menu_tool_button_new (const gchar *label, + EUIManager *ui_manager) { - return g_object_new (E_TYPE_MENU_TOOL_BUTTON, "label", label, NULL); + return g_object_new (E_TYPE_MENU_TOOL_BUTTON, + "label", label, + "ui-manager", ui_manager, + NULL); } const gchar * @@ -260,5 +197,7 @@ e_menu_tool_button_set_prefer_item (EMenuToolButton *button, g_free (button->priv->prefer_item); button->priv->prefer_item = g_strdup (prefer_item); + menu_tool_button_update_button (button); + g_object_notify (G_OBJECT (button), "prefer-item"); } diff --git a/src/e-util/e-menu-tool-button.h b/src/e-util/e-menu-tool-button.h index e8c276b565..726e6863f8 100644 --- a/src/e-util/e-menu-tool-button.h +++ b/src/e-util/e-menu-tool-button.h @@ -31,6 +31,8 @@ #include +#include + /* Standard GObject macros */ #define E_TYPE_MENU_TOOL_BUTTON \ (e_menu_tool_button_get_type ()) @@ -66,7 +68,8 @@ struct _EMenuToolButtonClass { }; GType e_menu_tool_button_get_type (void) G_GNUC_CONST; -GtkToolItem * e_menu_tool_button_new (const gchar *label); +GtkToolItem * e_menu_tool_button_new (const gchar *label, + EUIManager *ui_manager); const gchar * e_menu_tool_button_get_prefer_item (EMenuToolButton *button); void e_menu_tool_button_set_prefer_item diff --git a/src/e-util/e-misc-utils.c b/src/e-util/e-misc-utils.c index 5de05e8482..f1c1eea30a 100644 --- a/src/e-util/e-misc-utils.c +++ b/src/e-util/e-misc-utils.c @@ -530,245 +530,6 @@ e_restore_window (GtkWindow *window, g_object_unref (settings); } -/** - * e_lookup_action: - * @ui_manager: a #GtkUIManager - * @action_name: the name of an action - * - * Returns the first #GtkAction named @action_name by traversing the - * list of action groups in @ui_manager. If no such action exists, the - * function emits a critical warning before returning %NULL, since this - * probably indicates a programming error and most code is not prepared - * to deal with lookup failures. - * - * Returns: the first #GtkAction named @action_name - **/ -GtkAction * -e_lookup_action (GtkUIManager *ui_manager, - const gchar *action_name) -{ - GtkAction *action = NULL; - GList *iter; - - g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); - g_return_val_if_fail (action_name != NULL, NULL); - - iter = gtk_ui_manager_get_action_groups (ui_manager); - - while (iter != NULL) { - GtkActionGroup *action_group = iter->data; - - action = gtk_action_group_get_action ( - action_group, action_name); - if (action != NULL) - return action; - - iter = g_list_next (iter); - } - - g_critical ("%s: action '%s' not found", G_STRFUNC, action_name); - - return NULL; -} - -/** - * e_lookup_action_group: - * @ui_manager: a #GtkUIManager - * @group_name: the name of an action group - * - * Returns the #GtkActionGroup in @ui_manager named @group_name. If no - * such action group exists, the function emits a critical warnings before - * returning %NULL, since this probably indicates a programming error and - * most code is not prepared to deal with lookup failures. - * - * Returns: the #GtkActionGroup named @group_name - **/ -GtkActionGroup * -e_lookup_action_group (GtkUIManager *ui_manager, - const gchar *group_name) -{ - GList *iter; - - g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); - g_return_val_if_fail (group_name != NULL, NULL); - - iter = gtk_ui_manager_get_action_groups (ui_manager); - - while (iter != NULL) { - GtkActionGroup *action_group = iter->data; - const gchar *name; - - name = gtk_action_group_get_name (action_group); - if (strcmp (name, group_name) == 0) - return action_group; - - iter = g_list_next (iter); - } - - g_critical ("%s: action group '%s' not found", G_STRFUNC, group_name); - - return NULL; -} - -/** - * e_action_compare_by_label: - * @action1: a #GtkAction - * @action2: a #GtkAction - * - * Compares the labels for @action1 and @action2 using g_utf8_collate(). - * - * Returns: < 0 if @action1 compares before @action2, 0 if they - * compare equal, > 0 if @action1 compares after @action2 - **/ -gint -e_action_compare_by_label (GtkAction *action1, - GtkAction *action2) -{ - gchar *label1; - gchar *label2; - gint result; - - /* XXX This is horribly inefficient but will generally only be - * used on short lists of actions during UI construction. */ - - if (action1 == action2) - return 0; - - g_object_get (action1, "label", &label1, NULL); - g_object_get (action2, "label", &label2, NULL); - - result = g_utf8_collate (label1, label2); - - g_free (label1); - g_free (label2); - - return result; -} - -/** - * e_action_group_remove_all_actions: - * @action_group: a #GtkActionGroup - * - * Removes all actions from the action group. - **/ -void -e_action_group_remove_all_actions (GtkActionGroup *action_group) -{ - GList *list, *iter; - - /* XXX I've proposed this function for inclusion in GTK+. - * GtkActionGroup stores actions in an internal hash - * table and can do this more efficiently by calling - * g_hash_table_remove_all(). - * - * http://bugzilla.gnome.org/show_bug.cgi?id=550485 */ - - g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); - - list = gtk_action_group_list_actions (action_group); - for (iter = list; iter != NULL; iter = iter->next) - gtk_action_group_remove_action (action_group, iter->data); - g_list_free (list); -} - -/** - * e_radio_action_get_current_action: - * @radio_action: a #GtkRadioAction - * - * Returns the currently active member of the group to which @radio_action - * belongs. - * - * Returns: the currently active group member - **/ -GtkRadioAction * -e_radio_action_get_current_action (GtkRadioAction *radio_action) -{ - GSList *group; - gint current_value; - - g_return_val_if_fail (GTK_IS_RADIO_ACTION (radio_action), NULL); - - group = gtk_radio_action_get_group (radio_action); - current_value = gtk_radio_action_get_current_value (radio_action); - - while (group != NULL) { - gint value; - - radio_action = GTK_RADIO_ACTION (group->data); - g_object_get (radio_action, "value", &value, NULL); - - if (value == current_value) - return radio_action; - - group = g_slist_next (group); - } - - return NULL; -} - -/** - * e_action_group_add_actions_localized: - * @action_group: a #GtkActionGroup to add @entries to - * @translation_domain: a translation domain to use - * to translate label and tooltip strings in @entries - * @entries: (array length=n_entries): an array of action descriptions - * @n_entries: the number of entries - * @user_data: data to pass to the action callbacks - * - * Adds #GtkAction-s defined by @entries to @action_group, with action's - * label and tooltip localized in the given translation domain, instead - * of the domain set on the @action_group. - * - * Since: 3.4 - **/ -void -e_action_group_add_actions_localized (GtkActionGroup *action_group, - const gchar *translation_domain, - const GtkActionEntry *entries, - guint n_entries, - gpointer user_data) -{ - GtkActionGroup *tmp_group; - GList *list, *iter; - gint ii; - - g_return_if_fail (action_group != NULL); - g_return_if_fail (entries != NULL); - g_return_if_fail (n_entries > 0); - g_return_if_fail (translation_domain != NULL); - g_return_if_fail (*translation_domain); - - tmp_group = gtk_action_group_new ("temporary-group"); - gtk_action_group_set_translation_domain (tmp_group, translation_domain); - gtk_action_group_add_actions (tmp_group, entries, n_entries, user_data); - - list = gtk_action_group_list_actions (tmp_group); - for (iter = list; iter != NULL; iter = iter->next) { - GtkAction *action = GTK_ACTION (iter->data); - const gchar *action_name; - - g_object_ref (action); - - action_name = gtk_action_get_name (action); - - for (ii = 0; ii < n_entries; ii++) { - if (g_strcmp0 (entries[ii].name, action_name) == 0) { - gtk_action_group_remove_action ( - tmp_group, action); - gtk_action_group_add_action_with_accel ( - action_group, action, - entries[ii].accelerator); - break; - } - } - - g_object_unref (action); - } - - g_list_free (list); - g_object_unref (tmp_group); -} - /** * e_builder_get_widget: * @builder: a #GtkBuilder @@ -836,102 +597,6 @@ e_load_ui_builder_definition (GtkBuilder *builder, } } -static gdouble -e_get_ui_manager_definition_file_version (const gchar *filename) -{ - xmlDocPtr doc; - xmlNode *root; - gdouble version = -1.0; - - g_return_val_if_fail (filename != NULL, version); - - doc = e_xml_parse_file (filename); - if (!doc) - return version; - - root = xmlDocGetRootElement (doc); - if (root && g_strcmp0 ((const gchar *) root->name, "ui") == 0) { - version = e_xml_get_double_prop_by_name_with_default (root, (const xmlChar *) "evolution-ui-version", -1.0); - } - - xmlFreeDoc (doc); - - return version; -} - -static gchar * -e_pick_ui_manager_definition_file (const gchar *basename) -{ - gchar *system_filename, *user_filename; - gdouble system_version, user_version; - - g_return_val_if_fail (basename != NULL, NULL); - - system_filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); - user_filename = g_build_filename (e_get_user_config_dir (), "ui", basename, NULL); - - if (!g_file_test (user_filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) { - g_free (user_filename); - - return system_filename; - } - - user_version = e_get_ui_manager_definition_file_version (user_filename); - system_version = e_get_ui_manager_definition_file_version (system_filename); - - /* Versions are equal and the system version is a positive number */ - if (user_version - system_version >= -1e-9 && - user_version - system_version <= 1e-9 && - system_version > 1e-9) { - g_free (system_filename); - - return user_filename; - } - - g_warning ("User's UI file '%s' version (%.1f) doesn't match expected version (%.1f), skipping it. Either correct the version or remove the file.", - user_filename, user_version, system_version); - - g_free (user_filename); - - return system_filename; -} - -/** - * e_load_ui_manager_definition: - * @ui_manager: a #GtkUIManager - * @basename: basename of the UI definition file - * - * Loads a UI definition into @ui_manager from Evolution's UI directory. - * Failure here is fatal, since the application can't function without - * its UI definitions. - * - * Returns: The merge ID for the merged UI. The merge ID can be used to - * unmerge the UI with gtk_ui_manager_remove_ui(). - **/ -guint -e_load_ui_manager_definition (GtkUIManager *ui_manager, - const gchar *basename) -{ - gchar *filename; - guint merge_id; - GError *error = NULL; - - g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), 0); - g_return_val_if_fail (basename != NULL, 0); - - filename = e_pick_ui_manager_definition_file (basename); - merge_id = gtk_ui_manager_add_ui_from_file ( - ui_manager, filename, &error); - g_free (filename); - - if (error != NULL) { - g_error ("%s: %s", basename, error->message); - g_warn_if_reached (); - } - - return merge_id; -} - /* Helper for e_categories_add_change_hook() */ static void categories_changed_cb (GObject *useless_opaque_object, @@ -5165,3 +4830,99 @@ e_util_call_malloc_trim_limited (void) e_util_call_malloc_trim (); } } + +static gboolean +e_util_detach_menu_on_idle_cb (gpointer user_data) +{ + GtkMenu *menu = user_data; + + gtk_menu_detach (menu); + + return G_SOURCE_REMOVE; +} + +static void +e_util_menu_deactivate_cb (GtkMenu *menu, + gpointer user_data) +{ + g_return_if_fail (GTK_IS_MENU (menu)); + + g_signal_handlers_disconnect_by_func (menu, e_util_menu_deactivate_cb, user_data); + + g_idle_add_full (G_PRIORITY_LOW, e_util_detach_menu_on_idle_cb, g_object_ref (menu), g_object_unref); +} + +/** + * e_util_connect_menu_detach_after_deactivate: + * @menu: a #GtkMenu + * + * Connects a signal handler on a "deactivate" signal of the @menu and + * calls gtk_menu_detach() after the handler is invoked, which can cause + * destroy of the @menu. + * + * As the #GAction-s are not executed immediately by the GTK, the detach can be + * called only later, not in the deactivate signal handler. This function makes + * it simpler and consistent to detach (and possibly free) the @menu after the user + * dismisses it either by clicking elsewhere or by picking an item from it. + * + * Since: 3.56 + **/ +void +e_util_connect_menu_detach_after_deactivate (GtkMenu *menu) +{ + g_return_if_fail (GTK_IS_MENU (menu)); + + g_signal_connect ( + menu, "deactivate", + G_CALLBACK (e_util_menu_deactivate_cb), NULL); +} + +/** + * e_util_ignore_accel_for_focused: + * @focused: (nullable): a focused #GtkWidget, or %NULL + * + * Returns whether an accel key press should be ignored, due to the @focused + * might use it. Returns %FALSE, when the @focused is %NULL. + * + * Returns: whether an accel key press should be ignored + * + * Since: 3.56 + **/ +gboolean +e_util_ignore_accel_for_focused (GtkWidget *focused) +{ + if (!focused) + return FALSE; + + if ((GTK_IS_ENTRY (focused) || GTK_IS_EDITABLE (focused) || + (GTK_IS_TREE_VIEW (focused) && gtk_tree_view_get_search_column (GTK_TREE_VIEW (focused)) >= 0))) { + GdkEvent *event; + gboolean ignore = TRUE; + + event = gtk_get_current_event (); + if (event) { + GdkModifierType modifs = 0; + guint keyval = 0; + gboolean can_process; + + /* multi-key presses are always allowed */ + can_process = gdk_event_get_state (event, &modifs) && + (modifs & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0; + + if (!can_process && gdk_event_get_keyval (event, &keyval)) { + /* function keys are allowed (they are used as shortcuts in the mail view) */ + can_process = keyval == GDK_KEY_F1 || keyval == GDK_KEY_F2 || keyval == GDK_KEY_F3 || keyval == GDK_KEY_F4 || + keyval == GDK_KEY_F5 || keyval == GDK_KEY_F6 || keyval == GDK_KEY_F7 || keyval == GDK_KEY_F8 || + keyval == GDK_KEY_F9 || keyval == GDK_KEY_F10 || keyval == GDK_KEY_F11 || keyval == GDK_KEY_F12; + } + + g_clear_pointer (&event, gdk_event_free); + + ignore = !can_process; + } + + return ignore; + } + + return FALSE; +} diff --git a/src/e-util/e-misc-utils.h b/src/e-util/e-misc-utils.h index 8170ef1976..cdb258ad4a 100644 --- a/src/e-util/e-misc-utils.h +++ b/src/e-util/e-misc-utils.h @@ -60,28 +60,10 @@ void e_display_help (GtkWindow *parent, void e_restore_window (GtkWindow *window, const gchar *settings_path, ERestoreWindowFlags flags); -GtkAction * e_lookup_action (GtkUIManager *ui_manager, - const gchar *action_name); -GtkActionGroup *e_lookup_action_group (GtkUIManager *ui_manager, - const gchar *group_name); -gint e_action_compare_by_label (GtkAction *action1, - GtkAction *action2); -void e_action_group_remove_all_actions - (GtkActionGroup *action_group); -GtkRadioAction *e_radio_action_get_current_action - (GtkRadioAction *radio_action); -void e_action_group_add_actions_localized - (GtkActionGroup *action_group, - const gchar *translation_domain, - const GtkActionEntry *entries, - guint n_entries, - gpointer user_data); GtkWidget * e_builder_get_widget (GtkBuilder *builder, const gchar *widget_name); void e_load_ui_builder_definition (GtkBuilder *builder, const gchar *basename); -guint e_load_ui_manager_definition (GtkUIManager *ui_manager, - const gchar *basename); void e_categories_add_change_hook (GHookFunc func, gpointer object); @@ -360,6 +342,9 @@ void e_open_map_uri (GtkWindow *parent, gboolean e_util_link_requires_reference (const gchar *href, const gchar *text); void e_util_call_malloc_trim_limited (void); +void e_util_connect_menu_detach_after_deactivate + (GtkMenu *menu); +gboolean e_util_ignore_accel_for_focused (GtkWidget *focused); G_END_DECLS diff --git a/src/e-util/e-plugin-ui.c b/src/e-util/e-plugin-ui.c index 83ded1e271..002cc07deb 100644 --- a/src/e-util/e-plugin-ui.c +++ b/src/e-util/e-plugin-ui.c @@ -16,55 +16,30 @@ #include "evolution-config.h" -#include "e-plugin-ui.h" - #include +#include "e-ui-manager.h" + +#include "e-plugin-ui.h" + #define E_PLUGIN_UI_DEFAULT_FUNC "e_plugin_ui_init" #define E_PLUGIN_UI_HOOK_CLASS_ID "org.gnome.evolution.ui:1.0" struct _EPluginUIHookPrivate { - /* Table of GtkUIManager ID's to UI definitions. - * - * For example: - * - * - * - * ... UI definition ... - * - * - * - * Results in: - * - * g_hash_table_insert ( - * ui_definitions, - * "org.gnome.evolution.foo", - * "... UI definition ..."); - * - * See https://docs.gtk.org/gtk3/class.UIManager.html - * for more information about UI definitions. Note: the tag is - * optional. - */ - GHashTable *ui_definitions; - - /* Table of GtkUIManager ID's to callback function names. + /* Table of EUIManager ID's to callback function names. * * This stores the optional "callback" attribute in the * element. If not specified, it defaults to "e_plugin_ui_init". * - * This is useful when extending the UI of multiple GtkUIManager IDs + * This is useful when extending the UI of multiple EUIManager IDs * from a single plugin. * * For example: * * - * - * ... - * - * - * ... - * + * + * * * * Results in: @@ -77,115 +52,38 @@ struct _EPluginUIHookPrivate { */ GHashTable *callbacks; - /* The registry is the heart of EPluginUI. It tracks GtkUIManager - * instances, GtkUIManager IDs, and UI merge IDs as a hash table of - * hash tables: - * - * GtkUIManager instance -> GtkUIManager ID -> UI Merge ID - * - * A GtkUIManager instance and ID form a unique key for looking up - * UI merge IDs. The reason both are needed is because the same - * GtkUIManager instance can be registered under multiple IDs. - * - * This is done primarily to support shell views, which share a - * common GtkUIManager instance for a particular shell window. - * Each shell view registers the same GtkUIManager instance under - * a unique ID: - * - * "org.gnome.evolution.mail" } - * "org.gnome.evolution.contacts" } aliases for a common - * "org.gnome.evolution.calendar" } GtkUIManager instance - * "org.gnome.evolution.memos" } - * "org.gnome.evolution.tasks" } - * - * Note: The shell window also registers the same GtkUIManager - * instance as "org.gnome.evolution.shell". - * - * This way, plugins that extend a shell view's UI will follow the - * merging and unmerging of the shell view automatically. - * - * The presence or absence of GtkUIManager IDs in the registry is - * significant. Presence of a (instance, ID) pair indicates that - * UI manager is active, absence indicates inactive. Furthermore, - * a non-zero merge ID for an active UI manager indicates the - * plugin is enabled. Zero indicates disabled. - * - * Here's a quick scenario to illustrate: - * - * Suppose we have a plugin that extends the mail shell view UI. - * Its EPlugin definition file has this section: - * - * - * - * ... UI definition ... - * - * - * - * The plugin is enabled and the active shell view is "mail". - * Let "ManagerA" denote the common GtkUIManager instance for - * this shell window. Here's what happens to the registry as - * the user performs various actions; - * - * - Initial State Merge ID - * V - * { "ManagerA", { "org.gnome.evolution.mail", 3 } } - * - * - User Disables the Plugin - * - * { "ManagerA", { "org.gnome.evolution.mail", 0 } } - * - * - User Enables the Plugin - * - * { "ManagerA", { "org.gnome.evolution.mail", 4 } } - * - * - User Switches to Calendar View - * - * { "ManagerA", { } } - * - * - User Disables the Plugin - * - * { "ManagerA", { } } - * - * - User Switches to Mail View - * - * { "ManagerA", { "org.gnome.evolution.mail", 0 } } - * - * - User Enables the Plugin - * - * { "ManagerA", { "org.gnome.evolution.mail", 5 } } + /* The registry is the heart of EPluginUI. It tracks EUIManager + * instances. */ - GHashTable *registry; + GPtrArray *registry; }; G_DEFINE_TYPE_WITH_PRIVATE (EPluginUIHook, e_plugin_ui_hook, E_TYPE_PLUGIN_HOOK) static void plugin_ui_hook_unregister_manager (EPluginUIHook *hook, - GtkUIManager *ui_manager) + EUIManager *ui_manager) { - GHashTable *registry; - /* Note: Manager may already be finalized. */ - registry = hook->priv->registry; - g_hash_table_remove (registry, ui_manager); + g_ptr_array_remove (hook->priv->registry, ui_manager); } static void plugin_ui_hook_register_manager (EPluginUIHook *hook, - GtkUIManager *ui_manager, + EUIManager *ui_manager, const gchar *id, gpointer user_data) { EPlugin *plugin; EPluginUIInitFunc func; - GHashTable *registry; - GHashTable *hash_table; const gchar *func_name; plugin = ((EPluginHook *) hook)->plugin; - hash_table = hook->priv->callbacks; - func_name = g_hash_table_lookup (hash_table, id); + if (!g_hash_table_contains (hook->priv->callbacks, id)) + return; + + func_name = g_hash_table_lookup (hook->priv->callbacks, id); if (func_name == NULL) func_name = E_PLUGIN_UI_DEFAULT_FUNC; @@ -200,7 +98,7 @@ plugin_ui_hook_register_manager (EPluginUIHook *hook, } /* Pass the manager and user_data to the plugin's callback function. - * The plugin should install whatever GtkActions and GtkActionGroups + * The plugin should install whatever EUIAction-s and UI definitions * are neccessary to implement the actions in its UI definition. */ if (!func (ui_manager, user_data)) return; @@ -209,193 +107,26 @@ plugin_ui_hook_register_manager (EPluginUIHook *hook, G_OBJECT (ui_manager), (GWeakNotify) plugin_ui_hook_unregister_manager, hook); - registry = hook->priv->registry; - hash_table = g_hash_table_lookup (registry, ui_manager); - - if (hash_table == NULL) { - hash_table = g_hash_table_new_full ( - g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) NULL); - g_hash_table_insert (registry, ui_manager, hash_table); - } -} - -static guint -plugin_ui_hook_merge_ui (EPluginUIHook *hook, - GtkUIManager *ui_manager, - const gchar *id) -{ - GHashTable *hash_table; - const gchar *ui_definition; - guint merge_id; - GError *error = NULL; - - hash_table = hook->priv->ui_definitions; - ui_definition = g_hash_table_lookup (hash_table, id); - g_return_val_if_fail (ui_definition != NULL, 0); - - merge_id = gtk_ui_manager_add_ui_from_string ( - ui_manager, ui_definition, -1, &error); - - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } - - return merge_id; -} - -static void -plugin_ui_enable_manager (EPluginUIHook *hook, - GtkUIManager *ui_manager, - const gchar *id) -{ - GHashTable *hash_table; - GHashTable *ui_definitions; - GList *keys; - - hash_table = hook->priv->registry; - hash_table = g_hash_table_lookup (hash_table, ui_manager); - - if (hash_table == NULL) - return; - - if (id != NULL) - keys = g_list_prepend (NULL, (gpointer) id); - else - keys = g_hash_table_get_keys (hash_table); - - ui_definitions = hook->priv->ui_definitions; - - while (keys != NULL) { - guint merge_id; - gpointer data; - - id = keys->data; - keys = g_list_delete_link (keys, keys); - - if (g_hash_table_lookup (ui_definitions, id) == NULL) - continue; - - data = g_hash_table_lookup (hash_table, id); - merge_id = GPOINTER_TO_UINT (data); - - if (merge_id > 0) - continue; - - if (((EPluginHook *) hook)->plugin->enabled) - merge_id = plugin_ui_hook_merge_ui ( - hook, ui_manager, id); - - /* Merge ID will be 0 on error, which is what we want. */ - data = GUINT_TO_POINTER (merge_id); - g_hash_table_insert (hash_table, g_strdup (id), data); - } -} - -static void -plugin_ui_disable_manager (EPluginUIHook *hook, - GtkUIManager *ui_manager, - const gchar *id, - gboolean remove) -{ - GHashTable *hash_table; - GHashTable *ui_definitions; - GList *keys; - - hash_table = hook->priv->registry; - hash_table = g_hash_table_lookup (hash_table, ui_manager); - - if (hash_table == NULL) - return; - - if (id != NULL) - keys = g_list_prepend (NULL, (gpointer) id); - else - keys = g_hash_table_get_keys (hash_table); - - ui_definitions = hook->priv->ui_definitions; - - while (keys != NULL) { - guint merge_id; - gpointer data; - - id = keys->data; - keys = g_list_delete_link (keys, keys); - - if (g_hash_table_lookup (ui_definitions, id) == NULL) - continue; - - data = g_hash_table_lookup (hash_table, id); - merge_id = GPOINTER_TO_UINT (data); - - /* Merge ID could be 0 if the plugin is disabled. */ - if (merge_id > 0) { - gtk_ui_manager_remove_ui (ui_manager, merge_id); - gtk_ui_manager_ensure_update (ui_manager); - } - - if (remove) - g_hash_table_remove (hash_table, id); - else - g_hash_table_insert (hash_table, g_strdup (id), NULL); - } -} - -static void -plugin_ui_enable_hook (EPluginUIHook *hook) -{ - GHashTable *hash_table; - GHashTableIter iter; - gpointer key; - - /* Enable all GtkUIManagers for this hook. */ - - hash_table = hook->priv->registry; - g_hash_table_iter_init (&iter, hash_table); - - while (g_hash_table_iter_next (&iter, &key, NULL)) { - GtkUIManager *ui_manager = key; - plugin_ui_enable_manager (hook, ui_manager, NULL); - } -} - -static void -plugin_ui_disable_hook (EPluginUIHook *hook) -{ - GHashTable *hash_table; - GHashTableIter iter; - gpointer key; - - /* Disable all GtkUIManagers for this hook. */ - - hash_table = hook->priv->registry; - g_hash_table_iter_init (&iter, hash_table); - - while (g_hash_table_iter_next (&iter, &key, NULL)) { - GtkUIManager *ui_manager = key; - plugin_ui_disable_manager (hook, ui_manager, NULL, FALSE); - } + if (!g_ptr_array_find (hook->priv->registry, ui_manager, NULL)) + g_ptr_array_add (hook->priv->registry, ui_manager); } static void plugin_ui_hook_finalize (GObject *object) { EPluginUIHook *self = E_PLUGIN_UI_HOOK (object); - GHashTableIter iter; - gpointer ui_manager; + guint ii; - /* Remove weak reference callbacks to GtkUIManagers. */ - g_hash_table_iter_init (&iter, self->priv->registry); - while (g_hash_table_iter_next (&iter, &ui_manager, NULL)) + /* Remove weak reference callbacks to EUIManager-s. */ + for (ii = 0; ii < self->priv->registry->len; ii++) { + EUIManager *ui_manager = g_ptr_array_index (self->priv->registry, ii); g_object_weak_unref ( G_OBJECT (ui_manager), (GWeakNotify) plugin_ui_hook_unregister_manager, object); + } - g_hash_table_destroy (self->priv->ui_definitions); g_hash_table_destroy (self->priv->callbacks); - g_hash_table_destroy (self->priv->registry); + g_ptr_array_free (self->priv->registry, TRUE); /* Chain up to parent's method. */ G_OBJECT_CLASS (e_plugin_ui_hook_parent_class)->finalize (object); @@ -433,14 +164,12 @@ plugin_ui_hook_construct (EPluginHook *hook, } callback = e_plugin_xml_prop (node, "callback"); - if (callback != NULL) - g_hash_table_insert ( - self->priv->callbacks, - g_strdup (id), callback); + g_hash_table_insert (self->priv->callbacks, id, callback); content = g_string_sized_new (1024); - /* Extract the XML content below */ + /* Extract the XML content below . There cannot be any since 3.56, + thus claim a warning if there is */ buffer = xmlBufferCreate (); for (child = node->children; child != NULL; child = child->next) { xmlNodeDump (buffer, node->doc, child, 2, 1); @@ -448,10 +177,16 @@ plugin_ui_hook_construct (EPluginHook *hook, g_string_append (content, temp); } - g_hash_table_insert ( - self->priv->ui_definitions, - id, g_string_free (content, FALSE)); + g_string_replace (content, "\r" ,"", 0); + g_string_replace (content, "\n" ,"", 0); + g_string_replace (content, " " ,"", 0); + if (content->len) { + g_warning ("UI definitions cannot be part of .eplug files anymore. Add your UI with actions in the e_plugin_ui_init() instead. Plugin: %s", + plugin ? plugin->id : "Unknown"); + } + + g_string_free (content, TRUE); xmlBufferFree (buffer); } @@ -462,10 +197,6 @@ static void plugin_ui_hook_enable (EPluginHook *hook, gint state) { - if (state) - plugin_ui_enable_hook (E_PLUGIN_UI_HOOK (hook)); - else - plugin_ui_disable_hook (E_PLUGIN_UI_HOOK (hook)); } static void @@ -486,39 +217,26 @@ e_plugin_ui_hook_class_init (EPluginUIHookClass *class) static void e_plugin_ui_hook_init (EPluginUIHook *hook) { - GHashTable *ui_definitions; GHashTable *callbacks; - GHashTable *registry; - - ui_definitions = g_hash_table_new_full ( - g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_free); callbacks = g_hash_table_new_full ( g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); - registry = g_hash_table_new_full ( - g_direct_hash, g_direct_equal, - (GDestroyNotify) NULL, - (GDestroyNotify) g_hash_table_destroy); - hook->priv = e_plugin_ui_hook_get_instance_private (hook); - hook->priv->ui_definitions = ui_definitions; hook->priv->callbacks = callbacks; - hook->priv->registry = registry; + hook->priv->registry = g_ptr_array_new (); } void -e_plugin_ui_register_manager (GtkUIManager *ui_manager, +e_plugin_ui_register_manager (EUIManager *ui_manager, const gchar *id, gpointer user_data) { GSList *plugin_list; - g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); + g_return_if_fail (E_IS_UI_MANAGER (ui_manager)); g_return_if_fail (id != NULL); /* Loop over all installed plugins. */ @@ -532,83 +250,12 @@ e_plugin_ui_register_manager (GtkUIManager *ui_manager, /* Look for hooks of type EPluginUIHook. */ for (iter = plugin->hooks; iter != NULL; iter = iter->next) { EPluginUIHook *hook = iter->data; - GHashTable *hash_table; if (!E_IS_PLUGIN_UI_HOOK (hook)) continue; - hash_table = hook->priv->ui_definitions; - - /* Check if the hook has a UI definition - * for the GtkUIManager being registered. */ - if (g_hash_table_lookup (hash_table, id) == NULL) - continue; - /* Register the manager with the hook. */ - plugin_ui_hook_register_manager ( - hook, ui_manager, id, user_data); - } - - g_object_unref (plugin); - } -} - -void -e_plugin_ui_enable_manager (GtkUIManager *ui_manager, - const gchar *id) -{ - GSList *plugin_list; - - g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); - g_return_if_fail (id != NULL); - - /* Loop over all installed plugins. */ - plugin_list = e_plugin_list_plugins (); - while (plugin_list != NULL) { - EPlugin *plugin = plugin_list->data; - GSList *iter; - - plugin_list = g_slist_remove (plugin_list, plugin); - - /* Look for hooks of type EPluginUIHook. */ - for (iter = plugin->hooks; iter != NULL; iter = iter->next) { - EPluginUIHook *hook = iter->data; - - if (!E_IS_PLUGIN_UI_HOOK (hook)) - continue; - - plugin_ui_enable_manager (hook, ui_manager, id); - } - - g_object_unref (plugin); - } -} - -void -e_plugin_ui_disable_manager (GtkUIManager *ui_manager, - const gchar *id) -{ - GSList *plugin_list; - - g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); - g_return_if_fail (id != NULL); - - /* Loop over all installed plugins. */ - plugin_list = e_plugin_list_plugins (); - while (plugin_list != NULL) { - EPlugin *plugin = plugin_list->data; - GSList *iter; - - plugin_list = g_slist_remove (plugin_list, plugin); - - /* Look for hooks of type EPluginUIHook. */ - for (iter = plugin->hooks; iter != NULL; iter = iter->next) { - EPluginUIHook *hook = iter->data; - - if (!E_IS_PLUGIN_UI_HOOK (hook)) - continue; - - plugin_ui_disable_manager (hook, ui_manager, id, TRUE); + plugin_ui_hook_register_manager (hook, ui_manager, id, user_data); } g_object_unref (plugin); diff --git a/src/e-util/e-plugin-ui.h b/src/e-util/e-plugin-ui.h index fb9b02e746..1d49c66759 100644 --- a/src/e-util/e-plugin-ui.h +++ b/src/e-util/e-plugin-ui.h @@ -24,6 +24,7 @@ #include #include +#include /* Standard GObject macros */ #define E_TYPE_PLUGIN_UI_HOOK \ @@ -61,18 +62,14 @@ struct _EPluginUIHookClass { /* Plugins with "org.gnome.evolution.ui" hooks should define a * function named e_plugin_ui_init() having this signature. */ -typedef gboolean (*EPluginUIInitFunc) (GtkUIManager *ui_manager, +typedef gboolean (*EPluginUIInitFunc) (EUIManager *ui_manager, gpointer user_data); GType e_plugin_ui_hook_get_type (void) G_GNUC_CONST; -void e_plugin_ui_register_manager (GtkUIManager *ui_manager, +void e_plugin_ui_register_manager (EUIManager *ui_manager, const gchar *id, gpointer user_data); -void e_plugin_ui_enable_manager (GtkUIManager *ui_manager, - const gchar *id); -void e_plugin_ui_disable_manager (GtkUIManager *ui_manager, - const gchar *id); G_END_DECLS diff --git a/src/e-util/e-popup-action.c b/src/e-util/e-popup-action.c deleted file mode 100644 index 480613be32..0000000000 --- a/src/e-util/e-popup-action.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * e-popup-action.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include "evolution-config.h" - -#include "e-popup-action.h" - -#include - -enum { - PROP_0, - PROP_RELATED_ACTION, - PROP_USE_ACTION_APPEARANCE -}; - -struct _EPopupActionPrivate { - GtkAction *related_action; - gboolean use_action_appearance; - gulong activate_handler_id; - gulong notify_handler_id; -}; - -/* Forward Declarations */ -static void e_popup_action_activatable_init (GtkActivatableIface *iface); - -G_DEFINE_TYPE_WITH_CODE (EPopupAction, e_popup_action, GTK_TYPE_ACTION, - G_ADD_PRIVATE (EPopupAction) - G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE, e_popup_action_activatable_init)) - -static void -popup_action_notify_cb (GtkAction *action, - GParamSpec *pspec, - GtkActivatable *activatable) -{ - GtkActivatableIface *iface; - - iface = GTK_ACTIVATABLE_GET_IFACE (activatable); - g_return_if_fail (iface->update != NULL); - - iface->update (activatable, action, pspec->name); -} - -static GtkAction * -popup_action_get_related_action (EPopupAction *popup_action) -{ - return popup_action->priv->related_action; -} - -static void -popup_action_set_related_action (EPopupAction *popup_action, - GtkAction *related_action) -{ - GtkActivatable *activatable; - - /* Do not call gtk_activatable_do_set_related_action() because - * it assumes the activatable object is a widget and tries to add - * it to the related actions's proxy list. Instead we'll just do - * the relevant steps manually. */ - - activatable = GTK_ACTIVATABLE (popup_action); - - if (related_action == popup_action->priv->related_action) - return; - - if (related_action != NULL) - g_object_ref (related_action); - - if (popup_action->priv->related_action != NULL) { - g_signal_handler_disconnect ( - popup_action, - popup_action->priv->activate_handler_id); - g_signal_handler_disconnect ( - popup_action->priv->related_action, - popup_action->priv->notify_handler_id); - popup_action->priv->activate_handler_id = 0; - popup_action->priv->notify_handler_id = 0; - g_object_unref (popup_action->priv->related_action); - } - - popup_action->priv->related_action = related_action; - - if (related_action != NULL) { - popup_action->priv->activate_handler_id = - g_signal_connect_swapped ( - popup_action, "activate", - G_CALLBACK (gtk_action_activate), - related_action); - popup_action->priv->notify_handler_id = - g_signal_connect ( - related_action, "notify", - G_CALLBACK (popup_action_notify_cb), - popup_action); - gtk_activatable_sync_action_properties ( - activatable, related_action); - } else - gtk_action_set_visible (GTK_ACTION (popup_action), FALSE); - - g_object_notify (G_OBJECT (popup_action), "related-action"); -} - -static gboolean -popup_action_get_use_action_appearance (EPopupAction *popup_action) -{ - return popup_action->priv->use_action_appearance; -} - -static void -popup_action_set_use_action_appearance (EPopupAction *popup_action, - gboolean use_action_appearance) -{ - GtkActivatable *activatable; - GtkAction *related_action; - - if (popup_action->priv->use_action_appearance == use_action_appearance) - return; - - popup_action->priv->use_action_appearance = use_action_appearance; - - g_object_notify (G_OBJECT (popup_action), "use-action-appearance"); - - activatable = GTK_ACTIVATABLE (popup_action); - related_action = popup_action_get_related_action (popup_action); - gtk_activatable_sync_action_properties (activatable, related_action); -} - -static void -popup_action_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_RELATED_ACTION: - popup_action_set_related_action ( - E_POPUP_ACTION (object), - g_value_get_object (value)); - return; - - case PROP_USE_ACTION_APPEARANCE: - popup_action_set_use_action_appearance ( - E_POPUP_ACTION (object), - g_value_get_boolean (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -popup_action_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_RELATED_ACTION: - g_value_set_object ( - value, - popup_action_get_related_action ( - E_POPUP_ACTION (object))); - return; - - case PROP_USE_ACTION_APPEARANCE: - g_value_set_boolean ( - value, - popup_action_get_use_action_appearance ( - E_POPUP_ACTION (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -popup_action_dispose (GObject *object) -{ - EPopupAction *self = E_POPUP_ACTION (object); - - if (self->priv->related_action != NULL) { - g_signal_handler_disconnect ( - object, - self->priv->activate_handler_id); - g_signal_handler_disconnect ( - self->priv->related_action, - self->priv->notify_handler_id); - g_clear_object (&self->priv->related_action); - } - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_popup_action_parent_class)->dispose (object); -} - -static void -popup_action_update (GtkActivatable *activatable, - GtkAction *action, - const gchar *property_name) -{ - GObjectClass *class; - GParamSpec *pspec; - GValue *value; - - /* Ignore "action-group" changes" */ - if (strcmp (property_name, "action-group") == 0) - return; - - /* Ignore "visible" changes. */ - if (strcmp (property_name, "visible") == 0) - return; - - value = g_slice_new0 (GValue); - class = G_OBJECT_GET_CLASS (action); - pspec = g_object_class_find_property (class, property_name); - g_value_init (value, pspec->value_type); - - g_object_get_property (G_OBJECT (action), property_name, value); - - if (strcmp (property_name, "sensitive") == 0) - property_name = "visible"; - else if (!gtk_activatable_get_use_action_appearance (activatable)) - goto exit; - - g_object_set_property (G_OBJECT (activatable), property_name, value); - -exit: - g_value_unset (value); - g_slice_free (GValue, value); -} - -static void -popup_action_sync_action_properties (GtkActivatable *activatable, - GtkAction *action) -{ - if (action == NULL) - return; - - /* XXX GTK+ 2.18 is still missing accessor functions for - * "hide-if-empty" and "visible-overflown" properties. - * These are rarely used so we'll skip them for now. */ - - /* A popup action is never shown as insensitive. */ - gtk_action_set_sensitive (GTK_ACTION (activatable), TRUE); - - gtk_action_set_visible ( - GTK_ACTION (activatable), - gtk_action_get_sensitive (action)); - - gtk_action_set_visible_horizontal ( - GTK_ACTION (activatable), - gtk_action_get_visible_horizontal (action)); - - gtk_action_set_visible_vertical ( - GTK_ACTION (activatable), - gtk_action_get_visible_vertical (action)); - - gtk_action_set_is_important ( - GTK_ACTION (activatable), - gtk_action_get_is_important (action)); - - if (!gtk_activatable_get_use_action_appearance (activatable)) - return; - - gtk_action_set_label ( - GTK_ACTION (activatable), - gtk_action_get_label (action)); - - gtk_action_set_short_label ( - GTK_ACTION (activatable), - gtk_action_get_short_label (action)); - - gtk_action_set_tooltip ( - GTK_ACTION (activatable), - gtk_action_get_tooltip (action)); - - gtk_action_set_stock_id ( - GTK_ACTION (activatable), - gtk_action_get_stock_id (action)); - - gtk_action_set_gicon ( - GTK_ACTION (activatable), - gtk_action_get_gicon (action)); - - gtk_action_set_icon_name ( - GTK_ACTION (activatable), - gtk_action_get_icon_name (action)); -} - -static void -e_popup_action_class_init (EPopupActionClass *class) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = popup_action_set_property; - object_class->get_property = popup_action_get_property; - object_class->dispose = popup_action_dispose; - - g_object_class_override_property ( - object_class, - PROP_RELATED_ACTION, - "related-action"); - - g_object_class_override_property ( - object_class, - PROP_USE_ACTION_APPEARANCE, - "use-action-appearance"); -} - -static void -e_popup_action_init (EPopupAction *popup_action) -{ - popup_action->priv = e_popup_action_get_instance_private (popup_action); - popup_action->priv->use_action_appearance = TRUE; - - /* Remain invisible until we have a related action. */ - gtk_action_set_visible (GTK_ACTION (popup_action), FALSE); -} - -static void -e_popup_action_activatable_init (GtkActivatableIface *iface) -{ - iface->update = popup_action_update; - iface->sync_action_properties = popup_action_sync_action_properties; -} - -EPopupAction * -e_popup_action_new (const gchar *name) -{ - g_return_val_if_fail (name != NULL, NULL); - - return g_object_new (E_TYPE_POPUP_ACTION, "name", name, NULL); -} - -void -e_action_group_add_popup_actions (GtkActionGroup *action_group, - const EPopupActionEntry *entries, - guint n_entries) -{ - guint ii; - - g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); - - for (ii = 0; ii < n_entries; ii++) { - EPopupAction *popup_action; - GtkAction *related_action; - const gchar *label; - - label = gtk_action_group_translate_string ( - action_group, entries[ii].label); - - related_action = gtk_action_group_get_action ( - action_group, entries[ii].related); - - if (related_action == NULL) { - g_warning ( - "Related action '%s' not found in " - "action group '%s'", entries[ii].related, - gtk_action_group_get_name (action_group)); - continue; - } - - popup_action = e_popup_action_new (entries[ii].name); - - gtk_activatable_set_related_action ( - GTK_ACTIVATABLE (popup_action), related_action); - - if (label != NULL && *label != '\0') - gtk_action_set_label ( - GTK_ACTION (popup_action), label); - - gtk_action_group_add_action ( - action_group, GTK_ACTION (popup_action)); - - g_object_unref (popup_action); - } -} diff --git a/src/e-util/e-popup-action.h b/src/e-util/e-popup-action.h deleted file mode 100644 index 8ebdcf035c..0000000000 --- a/src/e-util/e-popup-action.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * e-popup-action.h - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* A popup action is an action that lives in a popup menu. It proxies an - * equivalent action in the main menu, with two differences: - * - * 1) If the main menu action is insensitive, the popup action is invisible. - * 2) The popup action may have a different label than the main menu action. - * - * To use: - * - * Create an array of EPopupActionEntry structs. Add the main menu actions - * that serve as related actions for the popup actions to an action group - * first. Then pass the same action group and the EPopupActionEntry array - * to e_action_group_add_popup_actions() to add popup actions. - */ - -#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) -#error "Only should be included directly." -#endif - -#ifndef E_POPUP_ACTION_H -#define E_POPUP_ACTION_H - -#include - -/* Standard GObject macros */ -#define E_TYPE_POPUP_ACTION \ - (e_popup_action_get_type ()) -#define E_POPUP_ACTION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_POPUP_ACTION, EPopupAction)) -#define E_POPUP_ACTION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_POPUP_ACTION, EPopupActionClass)) -#define E_IS_POPUP_ACTION(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_POPUP_ACTION)) -#define E_IS_POPUP_ACTION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_POPUP_ACTION)) -#define E_POPUP_ACTION_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_POPUP_ACTION, EPopupActionClass)) - -G_BEGIN_DECLS - -typedef struct _EPopupAction EPopupAction; -typedef struct _EPopupActionClass EPopupActionClass; -typedef struct _EPopupActionPrivate EPopupActionPrivate; -typedef struct _EPopupActionEntry EPopupActionEntry; - -struct _EPopupAction { - GtkAction parent; - EPopupActionPrivate *priv; -}; - -struct _EPopupActionClass { - GtkActionClass parent_class; -}; - -struct _EPopupActionEntry { - const gchar *name; - const gchar *label; /* optional: overrides the related action */ - const gchar *related; /* name of the related action */ -}; - -GType e_popup_action_get_type (void) G_GNUC_CONST; -EPopupAction * e_popup_action_new (const gchar *name); - -void e_action_group_add_popup_actions - (GtkActionGroup *action_group, - const EPopupActionEntry *entries, - guint n_entries); - -G_END_DECLS - -#endif /* E_POPUP_ACTION_H */ diff --git a/src/e-util/e-proxy-selector.c b/src/e-util/e-proxy-selector.c index c974f2c1b6..5812532e69 100644 --- a/src/e-util/e-proxy-selector.c +++ b/src/e-util/e-proxy-selector.c @@ -170,7 +170,7 @@ proxy_selector_remove_source_cb (GObject *object, static gboolean proxy_selector_action_add_cb (EProxySelector *selector, - GtkAction *action) + EUIAction *action) { AsyncContext *async_context; ESourceRegistry *registry; @@ -217,7 +217,7 @@ proxy_selector_action_add_cb (EProxySelector *selector, static gboolean proxy_selector_action_remove_cb (EProxySelector *selector, - GtkAction *action) + EUIAction *action) { ESource *selected_source; @@ -457,7 +457,7 @@ proxy_selector_constructed (GObject *object) GtkCellRenderer *renderer; GtkTreeSelection *selection; GtkListStore *list_store; - GtkAction *action; + EUIAction *action; const gchar *tooltip; gulong handler_id; @@ -477,12 +477,12 @@ proxy_selector_constructed (GObject *object) action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_ADD); tooltip = _("Create a new proxy profile"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_REMOVE); tooltip = _("Delete the selected proxy profile"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); /* Configure the tree view column. */ @@ -524,7 +524,7 @@ proxy_selector_update_toolbar_actions (ETreeViewFrame *tree_view_frame) { EProxySelector *selector; ESource *selected; - GtkAction *action; + EUIAction *action; gboolean sensitive; selector = E_PROXY_SELECTOR (tree_view_frame); @@ -533,7 +533,7 @@ proxy_selector_update_toolbar_actions (ETreeViewFrame *tree_view_frame) action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_REMOVE); sensitive = e_source_get_removable (selected); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); g_object_unref (selected); diff --git a/src/e-util/e-table-column-selector.c b/src/e-util/e-table-column-selector.c index c648c9fc04..c30b47938f 100644 --- a/src/e-util/e-table-column-selector.c +++ b/src/e-util/e-table-column-selector.c @@ -217,7 +217,7 @@ table_column_selector_constructed (GObject *object) { ETableColumnSelector *selector; ETreeViewFrame *tree_view_frame; - GtkAction *action; + EUIAction *action; GtkTreeView *tree_view; GtkTreeModel *tree_model; GtkTreeSelection *selection; @@ -243,36 +243,36 @@ table_column_selector_constructed (GObject *object) action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_ADD); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_REMOVE); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_TOP); tooltip = _("Move selected column names to top"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_UP); tooltip = _("Move selected column names up one row"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_DOWN); tooltip = _("Move selected column names down one row"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_BOTTOM); tooltip = _("Move selected column names to bottom"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_SELECT_ALL); tooltip = _("Select all column names"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); /* Configure the tree view columns. */ diff --git a/src/e-util/e-tree-view-frame.c b/src/e-util/e-tree-view-frame.c index e1fcded19c..e4adeadbf8 100644 --- a/src/e-util/e-tree-view-frame.c +++ b/src/e-util/e-tree-view-frame.c @@ -40,57 +40,57 @@ /** * E_TREE_VIEW_FRAME_ACTION_ADD: * - * The #GtkAction name for the "add" toolbar button. + * The #EUIAction name for the "add" toolbar button. * - * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #GtkAction. + * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #EUAction. **/ /** * E_TREE_VIEW_FRAME_ACTION_REMOVE: * - * The #GtkAction name for the "remove" toolbar button. + * The #EUIAction name for the "remove" toolbar button. * - * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #GtkAction. + * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #EUIAction. **/ /** * E_TREE_VIEW_FRAME_ACTION_MOVE_TOP: * - * The #GtkAction name for the "move selected items to top" button. + * The #EUIAction name for the "move selected items to top" button. * - * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #GtkAction. + * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #EUIAction. **/ /** * E_TREE_VIEW_FRAME_ACTION_MOVE_UP: * - * The #GtkAction name for the "move selected items up" button. + * The #EUIAction name for the "move selected items up" button. * - * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #GtkAction. + * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #EUIAction. **/ /** * E_TREE_VIEW_FRAME_ACTION_MOVE_DOWN: * - * The #GtkAction name for the "move selected items down" button. + * The #EUIAction name for the "move selected items down" button. * - * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #GtkAction. + * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #EUIAction. **/ /** * E_TREE_VIEW_FRAME_ACTION_MOVE_BOTTOM: * - * The #GtkAction name for the "move selected items to bottom" button. + * The #EUIAction name for the "move selected items to bottom" button. * - * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #GtkAction. + * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #EUIAction. **/ /** * E_TREE_VIEW_FRAME_ACTION_SELECT_ALL: * - * The #GtkAction name for the "select all" button. + * The #EUIAction name for the "select all" button. * - * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #GtkAction. + * Use e_tree_view_frame_lookup_toolbar_action() to obtain the #EUIAction. **/ struct _ETreeViewFramePrivate { @@ -102,7 +102,7 @@ struct _ETreeViewFramePrivate { GtkWidget *scrolled_window; GtkWidget *inline_toolbar; - GHashTable *tool_item_ht; + GHashTable *actions_ht; /* gchar *name ~> EUIAction * */ GtkPolicyType hscrollbar_policy; GtkPolicyType vscrollbar_policy; @@ -135,19 +135,15 @@ tree_view_frame_append_action (ETreeViewFrame *tree_view_frame, const gchar *action_name, const gchar *icon_name) { - GtkAction *action; - GIcon *icon; + EUIAction *action; - icon = g_themed_icon_new_with_default_fallbacks (icon_name); + action = e_ui_action_new ("tree-view-frame", action_name, NULL); - action = g_object_new ( - GTK_TYPE_ACTION, - "name", action_name, "gicon", icon, NULL); + e_ui_action_set_icon_name (action, icon_name); e_tree_view_frame_insert_toolbar_action (tree_view_frame, action, -1); g_object_unref (action); - g_object_unref (icon); } static void @@ -396,23 +392,6 @@ tree_view_frame_action_select_all (ETreeViewFrame *tree_view_frame) gtk_tree_selection_select_all (selection); } -static void -tree_view_frame_action_activate_cb (GtkAction *action, - ETreeViewFrame *tree_view_frame) -{ - GQuark detail; - const gchar *action_name; - gboolean handled = FALSE; - - action_name = gtk_action_get_name (action); - detail = g_quark_from_string (action_name); - - g_signal_emit ( - tree_view_frame, - signals[TOOLBAR_ACTION_ACTIVATE], detail, - action, &handled); -} - static void tree_view_frame_notify_reorderable_cb (GtkTreeView *tree_view, GParamSpec *pspec, @@ -520,7 +499,7 @@ tree_view_frame_dispose (GObject *object) g_clear_object (&self->priv->scrolled_window); g_clear_object (&self->priv->inline_toolbar); - g_hash_table_remove_all (self->priv->tool_item_ht); + g_hash_table_remove_all (self->priv->actions_ht); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_tree_view_frame_parent_class)->dispose (object); @@ -531,7 +510,7 @@ tree_view_frame_finalize (GObject *object) { ETreeViewFrame *self = E_TREE_VIEW_FRAME (object); - g_hash_table_destroy (self->priv->tool_item_ht); + g_hash_table_destroy (self->priv->actions_ht); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_tree_view_frame_parent_class)->finalize (object); @@ -625,11 +604,11 @@ tree_view_frame_constructed (GObject *object) static gboolean tree_view_frame_toolbar_action_activate (ETreeViewFrame *tree_view_frame, - GtkAction *action) + EUIAction *action) { const gchar *action_name; - action_name = gtk_action_get_name (action); + action_name = g_action_get_name (G_ACTION (action)); g_return_val_if_fail (action_name != NULL, FALSE); if (g_str_equal (action_name, E_TREE_VIEW_FRAME_ACTION_MOVE_TOP)) { @@ -663,7 +642,7 @@ tree_view_frame_toolbar_action_activate (ETreeViewFrame *tree_view_frame, static void tree_view_frame_update_toolbar_actions (ETreeViewFrame *tree_view_frame) { - GtkAction *action; + EUIAction *action; GtkTreeView *tree_view; GtkTreeModel *tree_model; GtkTreeSelection *selection; @@ -696,36 +675,36 @@ tree_view_frame_update_toolbar_actions (ETreeViewFrame *tree_view_frame) tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_TOP); visible = gtk_tree_view_get_reorderable (tree_view); sensitive = (n_selected_rows > 0 && !first_row_selected); - gtk_action_set_visible (action, visible); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, visible); + e_ui_action_set_sensitive (action, sensitive); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_UP); visible = gtk_tree_view_get_reorderable (tree_view); sensitive = (n_selected_rows > 0 && !first_row_selected); - gtk_action_set_visible (action, visible); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, visible); + e_ui_action_set_sensitive (action, sensitive); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_DOWN); visible = gtk_tree_view_get_reorderable (tree_view); sensitive = (n_selected_rows > 0 && !last_row_selected); - gtk_action_set_visible (action, visible); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, visible); + e_ui_action_set_sensitive (action, sensitive); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_BOTTOM); visible = gtk_tree_view_get_reorderable (tree_view); sensitive = (n_selected_rows > 0 && !last_row_selected); - gtk_action_set_visible (action, visible); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, visible); + e_ui_action_set_sensitive (action, sensitive); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_SELECT_ALL); visible = (selection_mode == GTK_SELECTION_MULTIPLE); sensitive = (n_selected_rows < n_rows); - gtk_action_set_visible (action, visible); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, visible); + e_ui_action_set_sensitive (action, sensitive); } static void @@ -740,10 +719,8 @@ e_tree_view_frame_class_init (ETreeViewFrameClass *class) object_class->finalize = tree_view_frame_finalize; object_class->constructed = tree_view_frame_constructed; - class->toolbar_action_activate = - tree_view_frame_toolbar_action_activate; - class->update_toolbar_actions = - tree_view_frame_update_toolbar_actions; + class->toolbar_action_activate = tree_view_frame_toolbar_action_activate; + class->update_toolbar_actions = tree_view_frame_update_toolbar_actions; g_object_class_install_property ( object_class, @@ -800,12 +777,12 @@ e_tree_view_frame_class_init (ETreeViewFrameClass *class) /** * ETreeViewFrame::toolbar-action-activate: * @tree_view_frame: the #ETreeViewFrame that received the signal - * @action: the #GtkAction that was activated + * @action: the #EUIAction that was activated * * Emitted when a toolbar action is activated. * * This signal supports "::detail" appendices to the signal name, - * where the "detail" part is the #GtkAction #GtkAction:name. So + * where the "detail" part is the action name. So * you can connect a signal handler to a particular action. **/ signals[TOOLBAR_ACTION_ACTIVATE] = g_signal_new ( @@ -818,15 +795,15 @@ e_tree_view_frame_class_init (ETreeViewFrameClass *class) g_signal_accumulator_true_handled, NULL, NULL, G_TYPE_BOOLEAN, 1, - GTK_TYPE_ACTION); + E_TYPE_UI_ACTION); /** * ETreeViewFrame::update-toolbar-actions: * @tree_view_frame: the #ETreeViewFrame that received the signal * * Requests toolbar actions be updated, usually in response to a - * #GtkTreeSelection change. Handlers should update #GtkAction - * properties like #GtkAction:visible and #GtkAction:sensitive + * #GtkTreeSelection change. Handlers should update action + * properties like #EUIAction:visible and #EUIAction:sensitive * based on the current #ETreeViewFrame:tree-view state. **/ signals[UPDATE_TOOLBAR_ACTIONS] = g_signal_new ( @@ -843,17 +820,8 @@ e_tree_view_frame_class_init (ETreeViewFrameClass *class) static void e_tree_view_frame_init (ETreeViewFrame *tree_view_frame) { - GHashTable *tool_item_ht; - - tool_item_ht = g_hash_table_new_full ( - (GHashFunc) g_str_hash, - (GEqualFunc) g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); - tree_view_frame->priv = e_tree_view_frame_get_instance_private (tree_view_frame); - - tree_view_frame->priv->tool_item_ht = tool_item_ht; + tree_view_frame->priv->actions_ht = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); } /** @@ -1067,10 +1035,32 @@ e_tree_view_frame_set_vscrollbar_policy (ETreeViewFrame *tree_view_frame, g_object_notify (G_OBJECT (tree_view_frame), "vscrollbar-policy"); } +static void +tree_view_frame_tool_item_clicked_cb (GtkToolButton *tool_button, + gpointer user_data) +{ + ETreeViewFrame *self = user_data; + EUIAction *action; + GQuark detail; + const gchar *action_name; + gboolean handled = FALSE; + + action = g_object_get_data (G_OBJECT (tool_button), "tree-view-frame-action"); + g_return_if_fail (action != NULL); + + action_name = g_action_get_name (G_ACTION (action)); + detail = g_quark_from_string (action_name); + + g_signal_emit (self, signals[TOOLBAR_ACTION_ACTIVATE], detail, action, &handled); + + if (!handled) + g_action_activate (G_ACTION (action), NULL); +} + /** * e_tree_view_frame_insert_toolbar_action: * @tree_view_frame: an #ETreeViewFrame - * @action: a #GtkAction + * @action: an #EUIAction * @position: the position of the new action * * Generates a #GtkToolItem from @action and inserts it into the inline @@ -1080,74 +1070,80 @@ e_tree_view_frame_set_vscrollbar_policy (ETreeViewFrame *tree_view_frame, **/ void e_tree_view_frame_insert_toolbar_action (ETreeViewFrame *tree_view_frame, - GtkAction *action, - gint position) + EUIAction *action, + gint position) { GtkToolbar *toolbar; - GtkWidget *tool_item; - GHashTable *tool_item_ht; + GtkToolItem *tool_item; const gchar *action_name; g_return_if_fail (E_IS_TREE_VIEW_FRAME (tree_view_frame)); - g_return_if_fail (GTK_IS_ACTION (action)); + g_return_if_fail (E_IS_UI_ACTION (action)); - action_name = gtk_action_get_name (action); + action_name = g_action_get_name (G_ACTION (action)); g_return_if_fail (action_name != NULL); - tool_item_ht = tree_view_frame->priv->tool_item_ht; toolbar = GTK_TOOLBAR (tree_view_frame->priv->inline_toolbar); - if (g_hash_table_contains (tool_item_ht, action_name)) { - g_warning ( - "%s: Duplicate action name '%s'", - G_STRFUNC, action_name); + if (g_hash_table_contains (tree_view_frame->priv->actions_ht, action_name)) { + g_warning ("%s: Duplicate action name '%s'", G_STRFUNC, action_name); return; } - tool_item = gtk_action_create_tool_item (action); - g_return_if_fail (GTK_IS_TOOL_ITEM (tool_item)); + tool_item = gtk_tool_button_new (NULL, NULL); + gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (tool_item), e_ui_action_get_icon_name (action)); + gtk_tool_button_set_use_underline (GTK_TOOL_BUTTON (tool_item), TRUE); + g_object_set_data_full (G_OBJECT (tool_item), "tree-view-frame-action", + g_object_ref (action), g_object_unref); + + e_binding_bind_property ( + action, "label", + tool_item, "label", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + action, "tooltip", + tool_item, "tooltip-text", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + action, "sensitive", + tool_item, "sensitive", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + action, "visible", + tool_item, "visible", + G_BINDING_SYNC_CREATE); gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (tool_item), position); - g_hash_table_insert ( - tool_item_ht, - g_strdup (action_name), - g_object_ref (tool_item)); + g_hash_table_insert (tree_view_frame->priv->actions_ht, (gpointer) g_action_get_name (G_ACTION (action)), g_object_ref (action)); g_signal_connect ( - action, "activate", - G_CALLBACK (tree_view_frame_action_activate_cb), + tool_item, "clicked", + G_CALLBACK (tree_view_frame_tool_item_clicked_cb), tree_view_frame); } /** * e_tree_view_frame_lookup_toolbar_action: * @tree_view_frame: an #ETreeViewFrame - * @action_name: a #GtkAction name + * @action_name: an #EUIAction name * * Returns the toolbar action named @action_name, or %NULL if no such * toolbar action exists. * - * Returns: a #GtkAction, or %NULL + * Returns: an #EUIAction, or %NULL **/ -GtkAction * +EUIAction * e_tree_view_frame_lookup_toolbar_action (ETreeViewFrame *tree_view_frame, const gchar *action_name) { - GHashTable *tool_item_ht; - GtkActivatable *activatable; - GtkAction *action = NULL; - g_return_val_if_fail (E_IS_TREE_VIEW_FRAME (tree_view_frame), NULL); g_return_val_if_fail (action_name != NULL, NULL); - tool_item_ht = tree_view_frame->priv->tool_item_ht; - activatable = g_hash_table_lookup (tool_item_ht, action_name); - - if (GTK_IS_ACTIVATABLE (activatable)) - action = gtk_activatable_get_related_action (activatable); - - return action; + return g_hash_table_lookup (tree_view_frame->priv->actions_ht, action_name); } /** @@ -1165,4 +1161,3 @@ e_tree_view_frame_update_toolbar_actions (ETreeViewFrame *tree_view_frame) g_signal_emit (tree_view_frame, signals[UPDATE_TOOLBAR_ACTIONS], 0); } - diff --git a/src/e-util/e-tree-view-frame.h b/src/e-util/e-tree-view-frame.h index 9f7883d346..b83774650b 100644 --- a/src/e-util/e-tree-view-frame.h +++ b/src/e-util/e-tree-view-frame.h @@ -24,6 +24,8 @@ #include +#include + /* Standard GObject macros */ #define E_TYPE_TREE_VIEW_FRAME \ (e_tree_view_frame_get_type ()) @@ -74,7 +76,7 @@ struct _ETreeViewFrameClass { /* Signals */ gboolean (*toolbar_action_activate) (ETreeViewFrame *tree_view_frame, - GtkAction *action); + EUIAction *action); void (*update_toolbar_actions) (ETreeViewFrame *tree_view_frame); }; @@ -104,9 +106,9 @@ void e_tree_view_frame_set_vscrollbar_policy GtkPolicyType vscrollbar_policy); void e_tree_view_frame_insert_toolbar_action (ETreeViewFrame *tree_view_frame, - GtkAction *action, + EUIAction *action, gint position); -GtkAction * e_tree_view_frame_lookup_toolbar_action +EUIAction * e_tree_view_frame_lookup_toolbar_action (ETreeViewFrame *tree_view_frame, const gchar *action_name); void e_tree_view_frame_update_toolbar_actions @@ -115,4 +117,3 @@ void e_tree_view_frame_update_toolbar_actions G_END_DECLS #endif /* E_TREE_VIEW_FRAME_H */ - diff --git a/src/e-util/e-ui-action-group.c b/src/e-util/e-ui-action-group.c new file mode 100644 index 0000000000..13f678f55f --- /dev/null +++ b/src/e-util/e-ui-action-group.c @@ -0,0 +1,665 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "evolution-config.h" + +#include +#include + +#include "e-ui-action-group.h" +#include "e-ui-action.h" + +/** + * SECTION: e-ui-action-group + * @include: e-util/e-util.h + * @short_description: Group of UI actions + * + * The #EUIActionGroup is a named group of #EUIAction actions. The group + * allows to sensitize or influence visibility of all the actions in it + * by setting sensitive or visible property of the group itself. + * + * The #EUIActionGroup can serve also as a #GActionMap. + * + * The object is not thread-safe, it's meant to be used only from + * the main/GUI thread. + * + * Since: 3.56 + **/ + +struct _EUIActionGroup { + GSimpleActionGroup parent; + + gchar *name; + GHashTable *items; /* gchar *name ~> EUIAction * (owned) */ + gboolean sensitive; + gboolean visible; +}; + +G_DEFINE_TYPE (EUIActionGroup, e_ui_action_group, G_TYPE_SIMPLE_ACTION_GROUP) + +enum { + PROP_0, + PROP_NAME, + PROP_SENSITIVE, + PROP_VISIBLE, + N_PROPS +}; + +enum { + SIGNAL_ADDED, + SIGNAL_REMOVED, + SIGNAL_ACCEL_ADDED, + SIGNAL_ACCEL_REMOVED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0, }; +static GParamSpec *properties[N_PROPS] = { NULL, }; + +static void +e_ui_action_group_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EUIActionGroup *self = E_UI_ACTION_GROUP (object); + + switch (prop_id) { + case PROP_NAME: + g_free (self->name); + self->name = g_value_dup_string (value); + break; + case PROP_SENSITIVE: + e_ui_action_group_set_sensitive (self, g_value_get_boolean (value)); + break; + case PROP_VISIBLE: + e_ui_action_group_set_visible (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +e_ui_action_group_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EUIActionGroup *self = E_UI_ACTION_GROUP (object); + + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, e_ui_action_group_get_name (self)); + break; + case PROP_SENSITIVE: + g_value_set_boolean (value, e_ui_action_group_get_sensitive (self)); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, e_ui_action_group_get_visible (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +e_ui_action_group_dispose (GObject *object) +{ + EUIActionGroup *self = E_UI_ACTION_GROUP (object); + + e_ui_action_group_remove_all (self); + + G_OBJECT_CLASS (e_ui_action_group_parent_class)->dispose (object); +} + +static void +e_ui_action_group_finalize (GObject *object) +{ + EUIActionGroup *self = E_UI_ACTION_GROUP (object); + + g_clear_pointer (&self->name, g_free); + g_clear_pointer (&self->items, g_hash_table_unref); + + G_OBJECT_CLASS (e_ui_action_group_parent_class)->finalize (object); +} + +static void +e_ui_action_group_class_init (EUIActionGroupClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->set_property = e_ui_action_group_set_property; + object_class->get_property = e_ui_action_group_get_property; + object_class->dispose = e_ui_action_group_dispose; + object_class->finalize = e_ui_action_group_finalize; + + /** + * EUIActionGroup:name: + * + * Name of the action group. + * + * Since: 3.56 + **/ + properties[PROP_NAME] = g_param_spec_string ("name", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIActionGroup:sensitive: + * + * Get or set whether the action group is sensitive, which influences + * all the actions in the group. + * + * Since: 3.56 + **/ + properties[PROP_SENSITIVE] = g_param_spec_boolean ("sensitive", NULL, NULL, TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + + /** + * EUIActionGroup:visible: + * + * Get or set whether the action group is visible, which influences + * all the actions in the group. + * + * Since: 3.56 + **/ + properties[PROP_VISIBLE] = g_param_spec_boolean ("visible", NULL, NULL, TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties); + + /* void added (EUIActionGroup *action_group, + EUIAction *action); */ + /** + * EUIActionGroup::added: + * @action_group: an #EUIActionGroup + * @action: an #EUIAction, which had been just added + * + * A signal emitted when the @action_group added @action into itself. + * + * Since: 3.56 + **/ + signals[SIGNAL_ADDED] = g_signal_new ("added", + E_TYPE_UI_ACTION_GROUP, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + E_TYPE_UI_ACTION); + + /* void removed (EUIActionGroup *action_group, + EUIAction *action); */ + /** + * EUIActionGroup::removed: + * @action_group: an #EUIActionGroup + * @action: an #EUIAction, which had been just removed + * + * A signal emitted when the @action_group removed @action from itself. + * + * Since: 3.56 + **/ + signals[SIGNAL_REMOVED] = g_signal_new ("removed", + E_TYPE_UI_ACTION_GROUP, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + E_TYPE_UI_ACTION); + + /* void accel_added (EUIActionGroup *action_group, + EUIAction *action, + const gchar *accel); */ + /** + * EUIActionGroup::accel-added: + * @action_group: an #EUIActionGroup + * @action: an #EUIAction, whose accel was added + * @accel: the added accel + * + * A signal emitted when one of the @action_group @action has added + * an accelerator string. + * + * Since: 3.56 + **/ + signals[SIGNAL_ACCEL_ADDED] = g_signal_new ("accel-added", + E_TYPE_UI_ACTION_GROUP, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 2, + E_TYPE_UI_ACTION, + G_TYPE_STRING); + + /* void accel_removed (EUIActionGroup *action_group, + EUIAction *action, + const gchar *accel); */ + /** + * EUIActionGroup::accel-removed: + * @action_group: an #EUIActionGroup + * @action: an #EUIAction, whose accel was removed + * @accel: the removed accel + * + * A signal emitted when one of the @action_group @action has removed + * an accelerator string. + * + * Since: 3.56 + **/ + signals[SIGNAL_ACCEL_REMOVED] = g_signal_new ("accel-removed", + E_TYPE_UI_ACTION_GROUP, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 2, + E_TYPE_UI_ACTION, + G_TYPE_STRING); +} + +static void +e_ui_action_group_init (EUIActionGroup *self) +{ + self->items = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + self->sensitive = TRUE; + self->visible = TRUE; +} + +/** + * e_ui_action_group_new: + * @name: (not nullable): a group name + * + * Creates a new #EUIActionGroup named @name. + * + * Returns: (transfer full): a new #EUIActionGroup + * + * Since: 3.56 + **/ +EUIActionGroup * +e_ui_action_group_new (const gchar *name) +{ + g_return_val_if_fail (name != NULL, NULL); + + return g_object_new (E_TYPE_UI_ACTION_GROUP, + "name", name, + NULL); +} + +/** + * e_ui_action_group_get_name: + * @self: an #EUIActionGroup + * + * Get a name of the @self. + * + * Returns: a name of the @self + * + * Since: 3.56 + **/ +const gchar * +e_ui_action_group_get_name (EUIActionGroup *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION_GROUP (self), NULL); + + return self->name; +} + +static void +e_ui_action_group_action_accel_added_cb (EUIAction *action, + const gchar *accel, + gpointer user_data) +{ + EUIActionGroup *self = user_data; + + g_signal_emit (self, signals[SIGNAL_ACCEL_ADDED], 0, action, accel, NULL); +} + +static void +e_ui_action_group_action_accel_removed_cb (EUIAction *action, + const gchar *accel, + gpointer user_data) +{ + EUIActionGroup *self = user_data; + + g_signal_emit (self, signals[SIGNAL_ACCEL_REMOVED], 0, action, accel, NULL); +} + +/** + * e_ui_action_group_add: + * @self: an #EUIActionGroup + * @action: (transfer none): an #EUIAction + * + * Adds an action into the @self. When the @action is already in this group, + * it does nothing. When the @action is part of another group, it's removed + * from it first. In other words, the @action can be part of a single group + * only. + * + * Adding a new action of the same name as another action already in the group + * is considered as a programming error. + * + * Since: 3.56 + **/ +void +e_ui_action_group_add (EUIActionGroup *self, + EUIAction *action) +{ + EUIAction *adept; + const gchar *name; + + g_return_if_fail (E_IS_UI_ACTION_GROUP (self)); + g_return_if_fail (E_IS_UI_ACTION (action)); + + name = g_action_get_name (G_ACTION (action)); + adept = g_hash_table_lookup (self->items, name); + + if (adept == action) + return; + + if (adept) { + g_warning ("%s: Other action of the name '%s' is in the group, skipping", G_STRFUNC, name); + return; + } + + if (!e_ui_action_get_label (action)) + g_warning ("%s: Action '%s' does not have set label", G_STRFUNC, name); + + g_hash_table_insert (self->items, (gpointer) name, g_object_ref (action)); + g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (action)); + e_ui_action_set_action_group (action, self); + + g_signal_connect_object (action, "accel-added", + G_CALLBACK (e_ui_action_group_action_accel_added_cb), self, 0); + g_signal_connect_object (action, "accel-removed", + G_CALLBACK (e_ui_action_group_action_accel_removed_cb), self, 0); + + g_signal_emit (self, signals[SIGNAL_ADDED], 0, action, NULL); +} + +/** + * e_ui_action_group_remove: + * @self: an #EUIActionGroup + * @action: an #EUIAction + * + * Removes @action from the @self. It does nothing when the action + * does not exist in the group. + * + * Trying to remove an action of the same name as another action already + * in the group is considered as a programming error. + * + * See e_ui_action_group_remove_by_name(). + * + * Since: 3.56 + **/ +void +e_ui_action_group_remove (EUIActionGroup *self, + EUIAction *action) +{ + EUIAction *adept; + const gchar *name; + + g_return_if_fail (E_IS_UI_ACTION_GROUP (self)); + g_return_if_fail (E_IS_UI_ACTION (action)); + + name = g_action_get_name (G_ACTION (action)); + adept = g_hash_table_lookup (self->items, name); + + if (adept != action) { + if (adept) + g_warning ("%s: Other action of the name '%s' is in the group, skipping", G_STRFUNC, name); + return; + } + + g_object_ref (action); + + g_hash_table_remove (self->items, (gpointer) name); + e_ui_action_set_action_group (action, NULL); + g_action_map_remove_action (G_ACTION_MAP (self), name); + + g_signal_handlers_disconnect_by_func (action, G_CALLBACK (e_ui_action_group_action_accel_added_cb), self); + g_signal_handlers_disconnect_by_func (action, G_CALLBACK (e_ui_action_group_action_accel_removed_cb), self); + + g_signal_emit (self, signals[SIGNAL_REMOVED], 0, action, NULL); + + g_object_unref (action); +} + +/** + * e_ui_action_group_remove_by_name: + * @self: an #EUIActionGroup + * @action_name: (not nullable): an action name + * + * Removes an action from the @self identified by the @action_name. + * It does nothing, when the group does not contain any such + * named action. + * + * See e_ui_action_group_remove_by_name(). + * + * Since: 3.56 + **/ +void +e_ui_action_group_remove_by_name (EUIActionGroup *self, + const gchar *action_name) +{ + EUIAction *action; + + g_return_if_fail (E_IS_UI_ACTION_GROUP (self)); + g_return_if_fail (action_name != NULL); + + action = g_hash_table_lookup (self->items, action_name); + if (!action) + return; + + e_ui_action_group_remove (self, action); +} + +/** + * e_ui_action_group_remove_all: + * @self: an #EUIActionGroup + * + * Removes all actions from the @self. + * + * Since: 3.56 + **/ +void +e_ui_action_group_remove_all (EUIActionGroup *self) +{ + GPtrArray *actions; + GActionMap *action_map; + GHashTableIter iter; + gpointer value = NULL; + guint ii; + + g_return_if_fail (E_IS_UI_ACTION_GROUP (self)); + + if (!g_hash_table_size (self->items)) + return; + + actions = g_ptr_array_new_full (g_hash_table_size (self->items), g_object_unref); + + g_hash_table_iter_init (&iter, self->items); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + EUIAction *action = value; + g_ptr_array_add (actions, g_object_ref (action)); + } + + g_hash_table_remove_all (self->items); + + action_map = G_ACTION_MAP (self); + + for (ii = 0; ii < actions->len; ii++) { + EUIAction *action = g_ptr_array_index (actions, ii); + e_ui_action_set_action_group (action, NULL); + g_action_map_remove_action (action_map, g_action_get_name (G_ACTION (action))); + g_signal_handlers_disconnect_by_func (action, G_CALLBACK (e_ui_action_group_action_accel_added_cb), self); + g_signal_handlers_disconnect_by_func (action, G_CALLBACK (e_ui_action_group_action_accel_removed_cb), self); + g_signal_emit (self, signals[SIGNAL_REMOVED], 0, action, NULL); + } + + g_ptr_array_unref (actions); +} + +/** + * e_ui_action_group_get_action: + * @self: an #EUIActionGroup + * @action_name: (not nullable): an action name + * + * Looks up an action by its name in the @self. + * + * Returns: (transfer none) (nullable): an #EUIAction of the name @action_name, + * or %NULL, when no such named action exists in the group + * + * Since: 3.56 + **/ +EUIAction * +e_ui_action_group_get_action (EUIActionGroup *self, + const gchar *action_name) +{ + g_return_val_if_fail (E_IS_UI_ACTION_GROUP (self), NULL); + g_return_val_if_fail (action_name != NULL, NULL); + + return g_hash_table_lookup (self->items, action_name); +} + +/** + * e_ui_action_group_list_actions: + * @self: an #EUIActionGroup + * + * List all the actions in the @self. Free the returned #GPtrArray + * with g_ptr_array_unref(), when no longer needed. + * + * Returns: (transfer container) (element-type EUIAction): all actions in the @self + * + * Since: 3.56 + **/ +GPtrArray * +e_ui_action_group_list_actions (EUIActionGroup *self) +{ + GPtrArray *actions; + GHashTableIter iter; + gpointer value = NULL; + + g_return_val_if_fail (E_IS_UI_ACTION_GROUP (self), NULL); + + actions = g_ptr_array_new_full (g_hash_table_size (self->items), g_object_unref); + + g_hash_table_iter_init (&iter, self->items); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + EUIAction *action = value; + g_ptr_array_add (actions, g_object_ref (action)); + } + + return actions; +} + +/** + * e_ui_action_group_get_visible: + * @self: an #EUIActionGroup + * + * Checks whether the group, and also all the actions in the group, can be visible. + * + * Returns: whether the group and all its actions can be visible + * + * Since: 3.56 + **/ +gboolean +e_ui_action_group_get_visible (EUIActionGroup *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION_GROUP (self), FALSE); + + return self->visible; +} + +/** + * e_ui_action_group_set_visible: + * @self: an #EUIActionGroup + * @value: value to set + * + * Sets whether the group, and also all the actions in the group, can be visible. + * + * Since: 3.56 + **/ +void +e_ui_action_group_set_visible (EUIActionGroup *self, + gboolean value) +{ + GHashTableIter iter; + gpointer ht_value = NULL; + + g_return_if_fail (E_IS_UI_ACTION_GROUP (self)); + + if ((!self->visible) == (!value)) + return; + + self->visible = value; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VISIBLE]); + + g_hash_table_iter_init (&iter, self->items); + while (g_hash_table_iter_next (&iter, NULL, &ht_value)) { + GObject *action = ht_value; + g_object_notify (action, "is-visible"); + } +} + +/** + * e_ui_action_group_get_sensitive: + * @self: an #EUIActionGroup + * + * Checks whether the group, and also all the actions in the group, can be sensitive. + * + * Returns: whether the group and all its actions can be sensitive + * + * Since: 3.56 + **/ +gboolean +e_ui_action_group_get_sensitive (EUIActionGroup *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION_GROUP (self), FALSE); + + return self->sensitive; +} + +/** + * e_ui_action_group_set_sensitive: + * @self: an #EUIActionGroup + * @value: a value to set + * + * Sets whether the group, and also all the actions in the group, can be visible. + * + * Since: 3.56 + **/ +void +e_ui_action_group_set_sensitive (EUIActionGroup *self, + gboolean value) +{ + GHashTableIter iter; + gpointer ht_value = NULL; + + g_return_if_fail (E_IS_UI_ACTION_GROUP (self)); + + if ((!self->sensitive) == (!value)) + return; + + self->sensitive = value; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SENSITIVE]); + + g_hash_table_iter_init (&iter, self->items); + while (g_hash_table_iter_next (&iter, NULL, &ht_value)) { + GObject *action = ht_value; + g_object_notify (action, "enabled"); + } +} diff --git a/src/e-util/e-ui-action-group.h b/src/e-util/e-ui-action-group.h new file mode 100644 index 0000000000..230c61898b --- /dev/null +++ b/src/e-util/e-ui-action-group.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) +#error "Only should be included directly." +#endif + +#ifndef E_UI_ACTION_GROUP_H +#define E_UI_ACTION_GROUP_H + +#include +#include + +G_BEGIN_DECLS + +#define E_TYPE_UI_ACTION_GROUP e_ui_action_group_get_type () + +G_DECLARE_FINAL_TYPE (EUIActionGroup, e_ui_action_group, E, UI_ACTION_GROUP, GSimpleActionGroup) + +EUIActionGroup *e_ui_action_group_new (const gchar *name); +const gchar * e_ui_action_group_get_name (EUIActionGroup *self); +void e_ui_action_group_add (EUIActionGroup *self, + EUIAction *action); +void e_ui_action_group_remove (EUIActionGroup *self, + EUIAction *action); +void e_ui_action_group_remove_by_name(EUIActionGroup *self, + const gchar *action_name); +void e_ui_action_group_remove_all (EUIActionGroup *self); +EUIAction * e_ui_action_group_get_action (EUIActionGroup *self, + const gchar *action_name); +GPtrArray * e_ui_action_group_list_actions (EUIActionGroup *self); +gboolean e_ui_action_group_get_visible (EUIActionGroup *self); +void e_ui_action_group_set_visible (EUIActionGroup *self, + gboolean value); +gboolean e_ui_action_group_get_sensitive (EUIActionGroup *self); +void e_ui_action_group_set_sensitive (EUIActionGroup *self, + gboolean value); + +G_END_DECLS + +#endif /* E_UI_ACTION_GROUP_H */ diff --git a/src/e-util/e-ui-action.c b/src/e-util/e-ui-action.c new file mode 100644 index 0000000000..0c3d8f8037 --- /dev/null +++ b/src/e-util/e-ui-action.c @@ -0,0 +1,1757 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "evolution-config.h" + +#include +#include +#include + +#include "e-headerbar-button.h" +#include "e-ui-action-group.h" + +#include "e-ui-action.h" + +/** + * SECTION: e-ui-action + * @include: e-util/e-util.h + * @short_description: a UI action + * + * The #EUIAction is similar to a #GSimpleAction, with added properties + * suitable for easier manipulation of the action appearance. It implements + * a #GAction interface. + * + * The action can be part of a single #EUIActionGroup only. The GAction::enabled + * property considers also the groups sensitive value. + * + * While the @EUIAction:visible property is relevant for the action itself, + * the @EUIAction:is-visible property considers also visibility of the group, if any. + * + * The object is not thread-safe, it's meant to be used only from + * the main/GUI thread. + * + * Since: 3.56 + **/ + +/** + * EUIActionFunc: + * @action: an #EUIAction + * @value: (nullable): a #GVariant value for the function + * @user_data: user data for the function + * + * A function called either on @action activate or change_state signal. + * + * For the activate, the @value is a parameter, with which the activate + * was called. Stateless actions do not provide any parameter. + * + * For the change_state, the @value is a new value the state should be changed to. + * + * Since: 3.56 + **/ + +/** + * EUIActionEntry: + * @name: an action name + * @icon_name: an icon name + * @label: an action label + * @accel: an action accelerator + * @tooltip: an action tooltip + * @activate: (nullable): an #EUIActionFunc callback to call when the action is activated, or %NULL + * @parameter_type: an action parameter type + * @state: an action state for stateful actions + * @change_state: (nullable): an #EUIActionFunc callback to call when the state of the action should be changed, or %NULL + * + * A structure describing an action, which can be created in bulk + * with e_ui_manager_add_actions() function. + * + * Simple actions declare only the @activate callback, where it reacts + * to the action activation. + * + * To create a checkbox-like widgets from the action, set the @state + * to a boolean value (like "true") and provide a @change_state + * function, which will set e_ui_action_set_state (action, value); + * and also react to the change of the state. + * + * To create a radiobutton-like widgets from the action, set the @parameter_type + * for example to string ("s"), the @state to the value the radio group + * should be switched to (like "'value1'") and the @change_state + * function, which calls e_ui_action_set_state (action, value); and reacts + * to the change of the state. Each action in the radio group can use the same + * @change_state callback. Make sure the actions are part of the same radio + * group with the e_ui_action_set_radio_group(). + * + * See #EUIActionEnumEntry + * + * Since: 3.56 + **/ + +/** + * EUIActionEnumEntry: + * @name: an action name + * @icon_name: an icon name + * @label: an action label + * @accel: an action accelerator + * @tooltip: an action tooltip + * @activate: (nullable): an #EUIActionFunc callback to call when the action is activated, or %NULL + * @state: the corresponding enum value, as gint + * + * A structure describing a radio action, whose states are enum values. + * The actions can be created in bulk with e_ui_manager_add_actions_enum() function. + * + * See #EUIActionEntry. + * + * Since: 3.56 + **/ + +/* This is a copy of the GSimpleAction, with added "visible" property */ + +struct _EUIAction { + GObject parent; + + gchar *map_name; + gchar *name; + gchar *icon_name; + gchar *label; + gchar *accel; + gchar *tooltip; + GVariantType *parameter_type; + GVariant *target; /* the first state set; needed for radio groups */ + GVariant *state; + GVariant *state_hint; + GPtrArray *secondary_accels; + GPtrArray *radio_group; + EUIActionGroup *action_group; + gboolean sensitive; + gboolean visible; +}; + +static void e_ui_action_action_iface_init (GActionInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (EUIAction, e_ui_action, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, e_ui_action_action_iface_init)) + +enum { + PROP_0, + PROP_MAP_NAME, + PROP_NAME, + PROP_ICON_NAME, + PROP_LABEL, + PROP_ACCEL, + PROP_TOOLTIP, + PROP_PARAMETER_TYPE, + PROP_ENABLED, + PROP_STATE_TYPE, + PROP_STATE, + PROP_STATE_HINT, + PROP_VISIBLE, + PROP_SENSITIVE, + PROP_IS_VISIBLE, + PROP_ACTIVE, + N_PROPS +}; + +enum { + SIGNAL_CHANGE_STATE, + SIGNAL_ACTIVATE, + SIGNAL_CHANGED, + SIGNAL_ACCEL_ADDED, + SIGNAL_ACCEL_REMOVED, + N_SIGNALS +}; + +static GParamSpec *properties[N_PROPS] = { NULL, }; +static guint signals[N_SIGNALS] = { 0, }; + +static const gchar * +e_ui_action_get_name (GAction *action) +{ + g_return_val_if_fail (E_IS_UI_ACTION (action), NULL); + + return E_UI_ACTION (action)->name; +} + +static const GVariantType * +e_ui_action_get_parameter_type (GAction *action) +{ + g_return_val_if_fail (E_IS_UI_ACTION (action), NULL); + + return E_UI_ACTION (action)->parameter_type; +} + +static GVariant * +e_ui_action_get_state (GAction *action) +{ + EUIAction *self; + + g_return_val_if_fail (E_IS_UI_ACTION (action), NULL); + + self = E_UI_ACTION (action); + + return self->state ? g_variant_ref (self->state) : NULL; +} + +static const GVariantType * +e_ui_action_get_state_type (GAction *action) +{ + EUIAction *self; + + g_return_val_if_fail (E_IS_UI_ACTION (action), NULL); + + self = E_UI_ACTION (action); + + return self->state ? g_variant_get_type (self->state) : NULL; +} + +static GVariant * +e_ui_action_get_state_hint (GAction *action) +{ + EUIAction *self; + + g_return_val_if_fail (E_IS_UI_ACTION (action), NULL); + + self = E_UI_ACTION (action); + + return self->state_hint ? g_variant_ref (self->state_hint) : NULL; +} + +static gboolean +e_ui_action_get_enabled (GAction *action) +{ + EUIAction *self; + + g_return_val_if_fail (E_IS_UI_ACTION (action), FALSE); + + self = E_UI_ACTION (action); + + return self->sensitive && (!self->action_group || e_ui_action_group_get_sensitive (self->action_group)); +} + +static void +e_ui_action_change_state (GAction *action, + GVariant *value) +{ + EUIAction *self = E_UI_ACTION (action); + + /* If the user connected a signal handler then they are responsible + * for handling state changes. + */ + if (g_signal_has_handler_pending (self, signals[SIGNAL_CHANGE_STATE], 0, TRUE)) + g_signal_emit (self, signals[SIGNAL_CHANGE_STATE], 0, value); + + /* If not, then the default behaviour is to just set the state. */ + else + e_ui_action_set_state (self, value); +} + +static void +e_ui_action_activate (GAction *action, + GVariant *parameter) +{ + EUIAction *self = E_UI_ACTION (action); + + g_return_if_fail (self->parameter_type == NULL ? parameter == NULL : + (parameter != NULL && g_variant_is_of_type (parameter, self->parameter_type))); + + if (g_action_get_enabled (action) && e_ui_action_is_visible (self)) { + if (parameter != NULL) + g_variant_ref_sink (parameter); + + /* If the user connected a signal handler then they are responsible + * for handling activation. + */ + if (g_signal_has_handler_pending (self, signals[SIGNAL_ACTIVATE], 0, TRUE)) { + g_signal_emit (self, signals[SIGNAL_ACTIVATE], 0, parameter); + + /* If not, do some reasonable defaults for stateful actions. */ + } else if (self->state) { + /* If we have no parameter and this is a boolean action, toggle. */ + if (parameter == NULL && g_variant_is_of_type (self->state, G_VARIANT_TYPE_BOOLEAN)) { + gboolean was_enabled = g_variant_get_boolean (self->state); + e_ui_action_change_state (action, g_variant_new_boolean (!was_enabled)); + /* else, if the parameter and state type are the same, do a change-state */ + } else if (g_variant_is_of_type (self->state, g_variant_get_type (parameter))) { + e_ui_action_change_state (action, parameter); + } + } + + if (parameter != NULL) + g_variant_unref (parameter); + } +} + +static void +e_ui_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EUIAction *self = E_UI_ACTION (object); + + switch (prop_id) { + case PROP_MAP_NAME: + g_free (self->map_name); + self->map_name = g_value_dup_string (value); + break; + case PROP_NAME: + g_free (self->name); + self->name = g_value_dup_string (value); + break; + case PROP_ICON_NAME: + e_ui_action_set_icon_name (self, g_value_get_string (value)); + break; + case PROP_LABEL: + e_ui_action_set_label (self, g_value_get_string (value)); + break; + case PROP_ACCEL: + e_ui_action_set_accel (self, g_value_get_string (value)); + break; + case PROP_TOOLTIP: + e_ui_action_set_tooltip (self, g_value_get_string (value)); + break; + case PROP_PARAMETER_TYPE: + g_clear_pointer (&self->parameter_type, g_variant_type_free); + self->parameter_type = g_value_dup_boxed (value); + break; + case PROP_ENABLED: + e_ui_action_set_sensitive (self, g_value_get_boolean (value)); + break; + case PROP_STATE: + e_ui_action_set_state (self, g_value_get_variant (value)); + break; + case PROP_STATE_HINT: + e_ui_action_set_state_hint (self, g_value_get_variant (value)); + break; + case PROP_VISIBLE: + e_ui_action_set_visible (self, g_value_get_boolean (value)); + break; + case PROP_SENSITIVE: + e_ui_action_set_sensitive (self, g_value_get_boolean (value)); + break; + case PROP_ACTIVE: + e_ui_action_set_active (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +e_ui_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GAction *action = G_ACTION (object); + + switch (prop_id) { + case PROP_MAP_NAME: + g_value_set_string (value, e_ui_action_get_map_name (E_UI_ACTION (action))); + break; + case PROP_NAME: + g_value_set_string (value, e_ui_action_get_name (action)); + break; + case PROP_ICON_NAME: + g_value_set_string (value, e_ui_action_get_icon_name (E_UI_ACTION (action))); + break; + case PROP_LABEL: + g_value_set_string (value, e_ui_action_get_label (E_UI_ACTION (action))); + break; + case PROP_ACCEL: + g_value_set_string (value, e_ui_action_get_accel (E_UI_ACTION (action))); + break; + case PROP_TOOLTIP: + g_value_set_string (value, e_ui_action_get_tooltip (E_UI_ACTION (action))); + break; + case PROP_PARAMETER_TYPE: + g_value_set_boxed (value, e_ui_action_get_parameter_type (action)); + break; + case PROP_ENABLED: + g_value_set_boolean (value, e_ui_action_get_enabled (action)); + break; + case PROP_STATE_TYPE: + g_value_set_boxed (value, e_ui_action_get_state_type (action)); + break; + case PROP_STATE: + g_value_take_variant (value, e_ui_action_get_state (action)); + break; + case PROP_STATE_HINT: + g_value_take_variant (value, e_ui_action_get_state_hint (action)); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, e_ui_action_get_visible (E_UI_ACTION (action))); + break; + case PROP_SENSITIVE: + g_value_set_boolean (value, e_ui_action_get_sensitive (E_UI_ACTION (action))); + break; + case PROP_ACTIVE: + g_value_set_boolean (value, e_ui_action_get_active (E_UI_ACTION (action))); + break; + case PROP_IS_VISIBLE: + g_value_set_boolean (value, e_ui_action_is_visible (E_UI_ACTION (action))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +e_ui_action_finalize (GObject *object) +{ + EUIAction *self = E_UI_ACTION (object); + + e_ui_action_set_radio_group (self, NULL); + e_ui_action_set_action_group (self, NULL); + + g_clear_pointer (&self->map_name, g_free); + g_clear_pointer (&self->name, g_free); + g_clear_pointer (&self->icon_name, g_free); + g_clear_pointer (&self->label, g_free); + g_clear_pointer (&self->accel, g_free); + g_clear_pointer (&self->tooltip, g_free); + g_clear_pointer (&self->secondary_accels, g_ptr_array_unref); + g_clear_pointer (&self->parameter_type, g_variant_type_free); + g_clear_pointer (&self->target, g_variant_unref); + g_clear_pointer (&self->state, g_variant_unref); + g_clear_pointer (&self->state_hint, g_variant_unref); + + G_OBJECT_CLASS (e_ui_action_parent_class)->finalize (object); +} + +static void +e_ui_action_action_iface_init (GActionInterface *iface) +{ + iface->get_name = e_ui_action_get_name; + iface->get_parameter_type = e_ui_action_get_parameter_type; + iface->get_state_type = e_ui_action_get_state_type; + iface->get_state_hint = e_ui_action_get_state_hint; + iface->get_enabled = e_ui_action_get_enabled; + iface->get_state = e_ui_action_get_state; + iface->change_state = e_ui_action_change_state; + iface->activate = e_ui_action_activate; +} + +static void +e_ui_action_class_init (EUIActionClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->set_property = e_ui_action_set_property; + object_class->get_property = e_ui_action_get_property; + object_class->finalize = e_ui_action_finalize; + + /** + * EUIAction:map-name: + * + * A #GActionMap name the action is declared at. It usually matches #EUIActionGroup + * name, when one is set on the action. + * + * Since: 3.56 + **/ + properties[PROP_MAP_NAME] = g_param_spec_string ("map-name", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:name: + * + * An action name. + * + * Since: 3.56 + **/ + properties[PROP_NAME] = g_param_spec_string ("name", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:icon-name: + * + * An icon name, which can be a standard icon name, or a text with prefix "gicon::", + * which are generated by the action owner through #EUIManager::create-gicon signal. + * The signal is executed without the "gicon::" prefix. + * + * Since: 3.56 + **/ + properties[PROP_ICON_NAME] = g_param_spec_string ("icon-name", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:label: + * + * An action label. + * + * Since: 3.56 + **/ + properties[PROP_LABEL] = g_param_spec_string ("label", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:accel: + * + * An action accelerator. + * + * Since: 3.56 + **/ + properties[PROP_ACCEL] = g_param_spec_string ("accel", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:tooltip: + * + * An action tooltip text (not markup). + * + * Since: 3.56 + **/ + properties[PROP_TOOLTIP] = g_param_spec_string ("tooltip", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:parameter-type: + * + * A parameter type of a stateful action, as a #GVariantType, or %NULL. + * + * Since: 3.56 + **/ + properties[PROP_PARAMETER_TYPE] = g_param_spec_boxed ("parameter-type", NULL, NULL, G_TYPE_VARIANT_TYPE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:enabled: + * + * An enabled state of the action. When the action is part of an action group, + * the @EUIActionGroup:sensitive is consulted together with the @EUIAction:sensitive + * property when determining whether the action is enabled. + * + * Since: 3.56 + **/ + properties[PROP_ENABLED] = g_param_spec_boolean ("enabled", NULL, NULL, TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:state-type: + * + * State type of a stateful action, as a #GVariantType, or %NULL. + * + * Since: 3.56 + **/ + properties[PROP_STATE_TYPE] = g_param_spec_boxed ("state-type", NULL, NULL, G_TYPE_VARIANT_TYPE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:state: + * + * A state of a stateful action, as a #GVariant, or %NULL. + * + * Since: 3.56 + **/ + properties[PROP_STATE] = g_param_spec_variant ("state", NULL, NULL, G_VARIANT_TYPE_ANY, NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:state-hint: + * + * A state hint of a stateful action, as a #GVariantType, or %NULL. + * + * Since: 3.56 + **/ + properties[PROP_STATE_HINT] = g_param_spec_boxed ("state-hint", NULL, NULL, G_TYPE_VARIANT_TYPE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:visible: + * + * Whether the action is visible. It does not consult associated + * #EUIActionGroup visibility. + * + * Since: 3.56 + **/ + properties[PROP_VISIBLE] = g_param_spec_boolean ("visible", NULL, NULL, TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:is-visible: + * + * Read-only property to determine whether both @EUIAction:visible property and + * possibly associated #EUIActionGroup 's visible property are %TRUE. + * + * Since: 3.56 + **/ + properties[PROP_IS_VISIBLE] = g_param_spec_boolean ("is-visible", NULL, NULL, TRUE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:sensitive: + * + * Action's sensitive state. It does not consult associated + * #EUIActionGroup sensitivity. + * + * Since: 3.56 + **/ + properties[PROP_SENSITIVE] = g_param_spec_boolean ("sensitive", NULL, NULL, TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIAction:active: + * + * Action's active state. It is relevant only for stateful actions, like toggle + * actions (with a boolean state) or radio actions (with state and target). + * See e_ui_action_get_active() and e_ui_action_set_active() for more information. + * + * Since: 3.56 + **/ + properties[PROP_ACTIVE] = g_param_spec_boolean ("active", NULL, NULL, TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties); + + /** + * EUIAction::activate: + * @self: an #EUIAction + * @parameter: (nullable): an activation parameter as a #GVariant, or %NULL + * + * A signal emitted when the action should be activated. + * The @parameter is provided only for stateful actions. + * + * Since: 3.56 + **/ + signals[SIGNAL_ACTIVATE] = g_signal_new ("activate", + E_TYPE_UI_ACTION, + G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT, + 0, NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_VARIANT); + + /** + * EUIAction::change-state: + * @self: an #EUIAction + * @new_state: a new state + * + * A signal emitted to set a new state to a stateful action. + * + * Since: 3.56 + **/ + signals[SIGNAL_CHANGE_STATE] = g_signal_new ("change-state", + E_TYPE_UI_ACTION, + G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT, + 0, NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_VARIANT); + + /** + * EUIAction::changed: + * @self: an #EUIAction + * + * A signal emitted when the action changes its content. + * It's meant to be called when the menu content corresponding + * to this action should be regenerated, similar to when + * the #EUIAction:is-visible property changes. + * + * Since: 3.56 + **/ + signals[SIGNAL_CHANGED] = g_signal_new ("changed", + E_TYPE_UI_ACTION, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, NULL, NULL, + NULL, + G_TYPE_NONE, 0, + G_TYPE_NONE); + + /** + * EUIAction::accel-added: + * @self: an #EUIAction + * @accel: the added accelerator string + * + * A signal emitted when the action has either set the primary + * accelerator or it has added a secondary accelerator. + * + * Since: 3.56 + **/ + signals[SIGNAL_ACCEL_ADDED] = g_signal_new ("accel-added", + E_TYPE_UI_ACTION, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + /** + * EUIAction::accel-removed: + * @self: an #EUIAction + * @accel: the removed accelerator string + * + * A signal emitted when the action has either unset the primary + * accelerator or it has removed a secondary accelerator. + * The @accel is the removed accelerator string. + * + * Since: 3.56 + **/ + signals[SIGNAL_ACCEL_REMOVED] = g_signal_new ("accel-removed", + E_TYPE_UI_ACTION, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_STRING); +} + +static void +e_ui_action_init (EUIAction *self) +{ + self->sensitive = TRUE; + self->visible = TRUE; +} + +/** + * e_ui_action_new: + * @map_name: a name of a #GActionMap the action belongs to + * @action_name: a name of the action to be created + * @parameter_type: (nullable): a type of the action parameter, as #GVariantType, or %NULL + * + * Creates a new #EUIAction. + * + * Returns: (transfer full): a new #EUIAction + * + * Since: 3.56 + **/ +EUIAction * +e_ui_action_new (const gchar *map_name, + const gchar *action_name, + const GVariantType *parameter_type) +{ + g_return_val_if_fail (map_name != NULL, NULL); + g_return_val_if_fail (action_name != NULL, NULL); + + return g_object_new (E_TYPE_UI_ACTION, + "map-name", map_name, + "name", action_name, + "parameter-type", parameter_type, + NULL); +} + +/** + * e_ui_action_new_stateful: + * @map_name: a name of a #GActionMap the action belongs to + * @action_name: a name of the action to be created + * @parameter_type: (nullable): a type of the action parameter, as #GVariantType, or %NULL + * @state: a #GVariant for the action to have set a state to + * + * Creates a new stateful #EUIAction. Actions with boolean state are + * usually presented as toggle buttons and menu items, while actions + * with string states are usually presented as radio buttons and menu + * items. Radio actions need to have set radio group with + * e_ui_action_set_radio_group(). + * + * Returns: (transfer full): a new stateful #EUIAction + * + * Since: 3.56 + **/ +EUIAction * +e_ui_action_new_stateful (const gchar *map_name, + const gchar *action_name, + const GVariantType *parameter_type, + GVariant *state) +{ + g_return_val_if_fail (map_name != NULL, NULL); + g_return_val_if_fail (action_name != NULL, NULL); + + return g_object_new (E_TYPE_UI_ACTION, + "map-name", map_name, + "name", action_name, + "parameter-type", parameter_type, + "state", state, + NULL); +} + +/** + * e_ui_action_new_from_entry: + * @map_name: a name of a #GActionMap the action belongs to + * @entry: a single #EUIActionEntry to construct the action from + * @translation_domain: (nullable): a translation domain to use + * to localize the entry members for label and tooltip + * + * Creates a new #EUIAction from the @entry. + * + * Returns: (transfer full): a new #EUIAction + * + * Since: 3.56 + **/ +EUIAction * +e_ui_action_new_from_entry (const gchar *map_name, + const EUIActionEntry *entry, + const gchar *translation_domain) +{ + const GVariantType *parameter_type; + EUIAction *action; + + g_return_val_if_fail (map_name != NULL, NULL); + g_return_val_if_fail (entry != NULL, NULL); + + if (entry->parameter_type) { + if (!g_variant_type_string_is_valid (entry->parameter_type)) { + g_critical ("%s: the type string '%s' given as the parameter type for " + "action '%s' is not a valid GVariant type string. This action will not be added.", + G_STRFUNC, entry->parameter_type, entry->name); + return NULL; + } + + parameter_type = G_VARIANT_TYPE (entry->parameter_type); + } else { + parameter_type = NULL; + } + + if (entry->state) { + GError *error = NULL; + GVariant *state; + + state = g_variant_parse (NULL, entry->state, NULL, NULL, &error); + if (state == NULL) { + g_critical ("%s: GVariant could not parse the state value given for action '%s' " + "('%s'): %s. This action will not be added.", + G_STRFUNC, entry->name, entry->state, error->message); + g_clear_error (&error); + return NULL; + } + + action = e_ui_action_new_stateful (map_name, entry->name, parameter_type, state); + + g_clear_pointer (&state, g_variant_unref); + } else { + action = e_ui_action_new (map_name, entry->name, parameter_type); + } + + if (action) { + const gchar *domain = translation_domain; + + if (!domain || !*domain) + domain = GETTEXT_PACKAGE; + + e_ui_action_set_icon_name (action, entry->icon_name); + e_ui_action_set_label (action, entry->label && *entry->label ? g_dgettext (domain, entry->label) : NULL); + e_ui_action_set_accel (action, entry->accel); + e_ui_action_set_tooltip (action, entry->tooltip && *entry->tooltip ? g_dgettext (domain, entry->tooltip) : NULL); + } + + return action; +} + +/** + * e_ui_action_new_from_enum_entry: + * @map_name: a name of a #GActionMap the action belongs to + * @entry: a single #EUIActionEnumEntry to construct the action from + * @translation_domain: (nullable): a translation domain to use + * to localize the entry members for label and tooltip + * + * Creates a new #EUIAction from the @entry. + * + * Returns: (transfer full): a new #EUIAction + * + * Since: 3.56 + **/ +EUIAction * +e_ui_action_new_from_enum_entry (const gchar *map_name, + const EUIActionEnumEntry *entry, + const gchar *translation_domain) +{ + EUIAction *action; + + g_return_val_if_fail (map_name != NULL, NULL); + g_return_val_if_fail (entry != NULL, NULL); + + action = e_ui_action_new_stateful (map_name, entry->name, G_VARIANT_TYPE_INT32, g_variant_new_int32 (entry->state)); + + if (action) { + const gchar *domain = translation_domain; + + if (!domain || !*domain) + domain = GETTEXT_PACKAGE; + + e_ui_action_set_icon_name (action, entry->icon_name); + e_ui_action_set_label (action, entry->label && *entry->label ? g_dgettext (domain, entry->label) : NULL); + e_ui_action_set_accel (action, entry->accel); + e_ui_action_set_tooltip (action, entry->tooltip && *entry->tooltip ? g_dgettext (domain, entry->tooltip) : NULL); + } + + return action; +} + +/** + * e_ui_action_get_map_name: + * @self: an #EUIAction + * + * Get name of the action map. It usually matches a name of + * an associated #EUIActionGroup. + * + * Returns: action map name of the @self + * + * Since: 3.56 + **/ +const gchar * +e_ui_action_get_map_name (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->map_name; +} + +/** + * e_ui_action_ref_target: + * @self: an #EUIAction + * + * References target of a stateful action. This is usable for radio + * actions, where the state contains the current state of the whole + * radio group, while the target is the value to be set in the group + * when the action is activated. + * + * Returns: (transfer full) (nullable): the target value of the @self, + * or %NULL, when the @self is not a radio action + * + * Since: 3.56 + **/ +GVariant * +e_ui_action_ref_target (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->target ? g_variant_ref (self->target) : NULL; +} + +static void +e_ui_action_set_state_without_radio_group (EUIAction *self, + GVariant *value) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + g_return_if_fail (value != NULL); + + if (!self->state || !g_variant_equal (self->state, value)) { + if (self->state) + g_variant_unref (self->state); + + self->state = g_variant_ref_sink (value); + + if (!self->target && !g_variant_is_of_type (self->state, G_VARIANT_TYPE_BOOLEAN)) + self->target = g_variant_ref_sink (value); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STATE]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIVE]); + } +} + +/** + * e_ui_action_set_state: + * @self: an #EUIAction + * @value: (transfer full): a state to set, as a #GVariant + * + * Sets a state of the @self to @value. + * + * Since: 3.56 + **/ +void +e_ui_action_set_state (EUIAction *self, + GVariant *value) +{ + guint ii; + + g_return_if_fail (E_IS_UI_ACTION (self)); + g_return_if_fail (value != NULL); + + g_variant_ref_sink (value); + + if (self->radio_group) { + /* to have the whole group in the consistent state, because + any listener to notify::state may not get correct result + when checking whether the action is active or not */ + for (ii = 0; ii < self->radio_group->len; ii++) { + EUIAction *item = g_ptr_array_index (self->radio_group, ii); + g_object_freeze_notify (G_OBJECT (item)); + } + } + + e_ui_action_set_state_without_radio_group (self, value); + + if (self->radio_group) { + for (ii = 0; ii < self->radio_group->len; ii++) { + EUIAction *item = g_ptr_array_index (self->radio_group, ii); + + if (item != self) + e_ui_action_set_state_without_radio_group (item, value); + } + + for (ii = 0; ii < self->radio_group->len; ii++) { + EUIAction *item = g_ptr_array_index (self->radio_group, ii); + g_object_thaw_notify (G_OBJECT (item)); + } + } + + g_variant_unref (value); +} + +/** + * e_ui_action_set_state_hint: + * @self: an #EUIAction + * @state_hint: (nullable) (transfer full): a state hint as a #GVariant, or %NULL + * + * Sets or unsets the action state hint. + * + * Since: 3.56 + **/ +void +e_ui_action_set_state_hint (EUIAction *self, + GVariant *state_hint) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (self->state_hint == state_hint) + return; + + if (state_hint) + g_variant_ref_sink (state_hint); + + g_clear_pointer (&self->state_hint, g_variant_unref); + self->state_hint = state_hint; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STATE_HINT]); +} + +/** + * e_ui_action_set_visible: + * @self: an #EUIAction + * @visible: a value to set + * + * Sets whether the @self is visible. + * + * Since: 3.56 + **/ +void +e_ui_action_set_visible (EUIAction *self, + gboolean visible) +{ + GObject *object; + + g_return_if_fail (E_IS_UI_ACTION (self)); + + if ((!self->visible) == (!visible)) + return; + + self->visible = visible; + + object = G_OBJECT (self); + g_object_freeze_notify (object); + g_object_notify_by_pspec (object, properties[PROP_VISIBLE]); + g_object_notify_by_pspec (object, properties[PROP_IS_VISIBLE]); + g_object_thaw_notify (object); +} + +/** + * e_ui_action_get_visible: + * @self: an #EUIAction + * + * Gets whether the action is visible. It does not consider the associated + * group visibility; use e_ui_action_is_visible() instead. + * + * Returns: whether the action itself is visible + * + * Since: 3.56 + **/ +gboolean +e_ui_action_get_visible (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), FALSE); + + return self->visible; +} + +/** + * e_ui_action_set_sensitive: + * @self: an #EUIAction + * @sensitive: a value to set + * + * Sets whether the action is sensitive. + * + * Since: 3.56 + **/ +void +e_ui_action_set_sensitive (EUIAction *self, + gboolean sensitive) +{ + GObject *object; + + g_return_if_fail (E_IS_UI_ACTION (self)); + + if ((!self->sensitive) == (!sensitive)) + return; + + self->sensitive = sensitive; + + object = G_OBJECT (self); + g_object_freeze_notify (object); + g_object_notify_by_pspec (object, properties[PROP_SENSITIVE]); + g_object_notify_by_pspec (object, properties[PROP_ENABLED]); + g_object_thaw_notify (object); +} + +/** + * e_ui_action_get_sensitive: + * @self: an #EUIAction + * + * Gets whether the action is sensitive. It does not consider the associated + * group sensitivity; use g_action_get_enabled() instead. + * + * Returns: whether the action itself is sensitive + * + * Since: 3.56 + **/ +gboolean +e_ui_action_get_sensitive (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), FALSE); + + return self->sensitive; +} + +/** + * e_ui_action_is_visible: + * @self: an #EUIAction + * + * Gets whether the action itself and the associated #EUIActionGroup, + * if any, are both visible. Use e_ui_action_get_visible() to get + * visibility of the action itself. + * + * Returns: whether the @self with the associated action group are visible + * + * Since: 3.56 + **/ +gboolean +e_ui_action_is_visible (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), FALSE); + + return self->visible && (!self->action_group || e_ui_action_group_get_visible (self->action_group)); +} + +/** + * e_ui_action_set_icon_name: + * @self: an #EUIAction + * @icon_name: (nullable): an icon name, or %NULL + * + * Sets or unsets and icon name for the @self. It can be a standard icon name, + * or a text with prefix "gicon::", which are generated by the action owner + * through #EUIManager::create-gicon signal. The signal is executed without + * the "gicon::" prefix. + * + * Since: 3.56 + **/ +void +e_ui_action_set_icon_name (EUIAction *self, + const gchar *icon_name) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (e_util_strcmp0 (self->icon_name, icon_name) == 0) + return; + + g_free (self->icon_name); + self->icon_name = g_strdup (icon_name); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ICON_NAME]); +} + +/** + * e_ui_action_get_icon_name: + * @self: an #EUIAction + * + * Gets the icon name of the @self. + * + * Returns: (nullable): an icon name for the @self, or %NULL, when none is set + * + * Since: 3.56 + **/ +const gchar * +e_ui_action_get_icon_name (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->icon_name; +} + +/** + * e_ui_action_set_label: + * @self: an #EUIAction + * @label: (nullable): a label to set, or %NULL + * + * Sets a label for the action. The label should be already localized. + * + * Since: 3.56 + **/ +void +e_ui_action_set_label (EUIAction *self, + const gchar *label) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (e_util_strcmp0 (self->label, label) == 0) + return; + + g_free (self->label); + self->label = g_strdup (label); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LABEL]); +} + +/** + * e_ui_action_get_label: + * @self: an #EUIAction + * + * Gets a label of the @self. + * + * Returns: (nullable): a label of the @self, or %NULL, when none is set + * + * Since: 3.56 + **/ +const gchar * +e_ui_action_get_label (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->label; +} + +/** + * e_ui_action_set_accel: + * @self: an #EUIAction + * @accel: (nullable): an accelerator string, or %NULL + * + * Sets or unsets an accelerator string for the @self. + * The @accel should be parseable by the gtk_accelerator_parse() + * function. + * + * Since: 3.56 + **/ +void +e_ui_action_set_accel (EUIAction *self, + const gchar *accel) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (e_util_strcmp0 (self->accel, accel) == 0) + return; + + if (self->accel) + g_signal_emit (self, signals[SIGNAL_ACCEL_REMOVED], 0, self->accel, NULL); + + g_free (self->accel); + self->accel = g_strdup (accel); + + if (self->accel) + g_signal_emit (self, signals[SIGNAL_ACCEL_ADDED], 0, self->accel, NULL); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACCEL]); +} + +/** + * e_ui_action_get_accel: + * @self: an #EUIAction + * + * Gets an accelarator string for the @self. + * + * Returns: (nullable): an accelerator string for the @self, or %NULL, when none is set + * + * Since: 3.56 + **/ +const gchar * +e_ui_action_get_accel (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->accel; +} + +/** + * e_ui_action_add_secondary_accel: + * @self: an #EUIAction + * @accel: (not nullable): an accelerator string + * + * Adds a secondary accelerator string for the @self. This is in addition + * to the "accel" property, which is meant to be the main accelerator, + * shown in the GUI and such. + * + * The @accel should be parseable by the gtk_accelerator_parse() + * function. + * + * Since: 3.56 + **/ +void +e_ui_action_add_secondary_accel (EUIAction *self, + const gchar *accel) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + g_return_if_fail (accel != NULL); + + if (!self->secondary_accels) { + self->secondary_accels = g_ptr_array_new_with_free_func (g_free); + } else { + guint ii; + + for (ii = 0; ii < self->secondary_accels->len; ii++) { + const gchar *existing = g_ptr_array_index (self->secondary_accels, ii); + if (e_util_strcmp0 (existing, accel) == 0) + return; + } + } + + g_ptr_array_add (self->secondary_accels, g_strdup (accel)); + + g_signal_emit (self, signals[SIGNAL_ACCEL_ADDED], 0, accel, NULL); +} + +/** + * e_ui_action_get_secondary_accels: + * @self: an #EUIAction + * + * Gets an array of the secondary accelarators for the @self. The caller should + * not modify the array in any way. + * + * Returns: (nullable) (transfer container) (element-type utf-8): an array + * of the secondary accelerator strings for the @self, or %NULL, when none is set + * + * Since: 3.56 + **/ +GPtrArray * +e_ui_action_get_secondary_accels (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->secondary_accels; +} + +/** + * e_ui_action_remove_secondary_accels: + * @self: an #EUIAction + * + * Removes all secondary accelerator strings. + * + * Since: 3.56 + **/ +void +e_ui_action_remove_secondary_accels (EUIAction *self) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (self->secondary_accels) { + guint ii; + + for (ii = 0; ii < self->secondary_accels->len; ii++) { + const gchar *accel = g_ptr_array_index (self->secondary_accels, ii); + + g_signal_emit (self, signals[SIGNAL_ACCEL_REMOVED], 0, accel, NULL); + } + } + + g_clear_pointer (&self->secondary_accels, g_ptr_array_unref); +} + +/** + * e_ui_action_set_tooltip: + * @self: an #EUIAction + * @tooltip: (nullable): a tooltip text to set, or %NULL + * + * Sets or unsets a tooltip text (not markup) for the @self. + * + * Since: 3.56 + **/ +void +e_ui_action_set_tooltip (EUIAction *self, + const gchar *tooltip) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (e_util_strcmp0 (self->tooltip, tooltip) == 0) + return; + + g_free (self->tooltip); + self->tooltip = g_strdup (tooltip); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TOOLTIP]); +} + +/** + * e_ui_action_get_tooltip: + * @self: an #EUIAction + * + * Gets tooltip text for the @self. + * + * Returns: (nullable): a tooltip text (not markup) for the @self, or %NULL, when none is set. + * + * Since: 3.56 + **/ +const gchar * +e_ui_action_get_tooltip (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->tooltip; +} + +/** + * e_ui_action_set_radio_group: + * @self: an #EUIAction + * @radio_group: (nullable) (transfer none) (element-type EUIAction): a radio group to use, or %NULL + * + * Stateful actions can be grouped together, by setting the same radio + * group to each action. When not %NULL, the @self references the @radio_group, + * thus the caller can just create one array, set it to each action + * and then unref it. + * + * An action can be in a single radio group only. Trying to set a different + * radio group when one is already set is considered a programming error. + * + * Since: 3.56 + **/ +void +e_ui_action_set_radio_group (EUIAction *self, + GPtrArray *radio_group) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (!radio_group) { + if (self->radio_group) { + g_ptr_array_remove (self->radio_group, self); + g_clear_pointer (&self->radio_group, g_ptr_array_unref); + } + return; + } + + if (self->radio_group && self->radio_group != radio_group) { + g_warning ("%s: Action '%s' is already in another radio group", G_STRFUNC, self->name); + return; + } + + if (self->radio_group == radio_group) + return; + + g_return_if_fail (self->radio_group == NULL); + + self->radio_group = g_ptr_array_ref (radio_group); + g_ptr_array_add (self->radio_group, self); /* do not ref the 'self', due to circular dependency */ +} + +/** + * e_ui_action_get_radio_group: + * @self: an #EUIAction + * + * Gets the radio group the @self is part of. The array is owned by the @self, + * it cannot be modified neither freed by the caller. + * + * Returns: (nullable) (transfer none) (element-type EUIAction): a radio group + * the @self is part of, or %NULL + * + * Since: 3.56 + **/ +GPtrArray * +e_ui_action_get_radio_group (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->radio_group; +} + +/** + * e_ui_action_set_action_group: + * @self: an #EUIAction + * @action_group: (nullable): an #EUIActionGroup to set, or %NULL + * + * Sets the @self as being part of the @action_group, or unsets the group, + * when it's %NULL. An action cannot be part of multiple action groups, + * thus when trying to set a different action group the action is removed + * from the previous group (unlike e_ui_action_set_radio_group(), which + * does not move an action between radio groups automatically). + * + * The @action_group usually matches the @EUIAction:map-name property. + * + * See e_ui_action_get_sensitive(), e_ui_action_get_visible(), + * e_ui_action_is_visible(). + * + * Since: 3.56 + **/ +void +e_ui_action_set_action_group (EUIAction *self, + struct _EUIActionGroup *action_group) +{ + GObject *object; + gboolean old_enabled, old_is_visible; + + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (self->action_group == action_group) + return; + + old_enabled = e_ui_action_get_enabled (G_ACTION (self)); + old_is_visible = e_ui_action_is_visible (self); + + if (self->action_group) { + EUIActionGroup *old_action_group = self->action_group; + /* to avoid recursion */ + self->action_group = NULL; + e_ui_action_group_remove (old_action_group, self); + } + + if (action_group) { + self->action_group = action_group; + e_ui_action_group_add (action_group, self); + } + + object = G_OBJECT (self); + g_object_freeze_notify (object); + + if ((!old_enabled) != (!e_ui_action_get_enabled (G_ACTION (self)))) + g_object_notify_by_pspec (object, properties[PROP_ENABLED]); + + if ((!old_is_visible) != (!e_ui_action_is_visible (self))) + g_object_notify_by_pspec (object, properties[PROP_IS_VISIBLE]); + + g_object_thaw_notify (object); +} + +/** + * e_ui_action_get_action_group: + * @self: an #EUIAction + * + * Gets an action group the @self is part of. + * + * Returns: (transfer none) (nullable): an #EUIActionGroup the @self is part of, + * or %NULL, when none is set + * + * Since: 3.56 + **/ +struct _EUIActionGroup * +e_ui_action_get_action_group (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), NULL); + + return self->action_group; +} + +/** + * e_ui_action_get_active: + * @self: an #EUIAction + * + * Checks whether the @self state is the active, aka current, value. + * + * For toggle actions (with boolean state) returns whether the state is %TRUE. + * For radio actions returns whether the state matches the action target. + * For stateless actions returns FALSE. + * + * Returns: whether the @self is active + * + * Since: 3.56 + **/ +gboolean +e_ui_action_get_active (EUIAction *self) +{ + g_return_val_if_fail (E_IS_UI_ACTION (self), FALSE); + + if (!self->state) + return FALSE; + + if (self->target) + return g_variant_equal (self->state, self->target); + + return g_variant_is_of_type (self->state, G_VARIANT_TYPE_BOOLEAN) && + g_variant_get_boolean (self->state); +} + +/** + * e_ui_action_set_active: + * @self: an #EUIAction + * @active: value to set + * + * Sets whether the @self state is the @active, aka current, value. + * + * For toggle actions (with boolean state) sets the @active directly. + * For radio actions sets the state to the @self target when @active is %TRUE, + * otherwise does nothing. For stateless actions does nothing. + * + * Since: 3.56 + **/ +void +e_ui_action_set_active (EUIAction *self, + gboolean active) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + if (!self->state) + return; + + if (g_variant_is_of_type (self->state, G_VARIANT_TYPE_BOOLEAN)) { + e_ui_action_set_state (self, g_variant_new_boolean (active)); + return; + } + + if (self->target && active) + e_ui_action_set_state (self, self->target); +} + +/** + * e_ui_action_emit_changed: + * @self: an #EUIAction + * + * Emits the #EUIAction::changed signal on the @self. + * + * Since: 3.56 + **/ +void +e_ui_action_emit_changed (EUIAction *self) +{ + g_return_if_fail (E_IS_UI_ACTION (self)); + + g_signal_emit (self, signals[SIGNAL_CHANGED], 0, NULL); +} + +/** + * e_ui_action_util_gvalue_to_enum_state: + * @binding: a #GBinding + * @from_value: a source #GValue + * @to_value: a destination #GValue + * @user_data: unused binding user data + * + * A utility function, which can be used as a transformation function + * of a #GBinding from an enum property to an enum state of an #EUIAction + * created by e_ui_action_new_from_enum_entry(). + * + * Returns: %TRUE + * + * Since: 3.56 + **/ +gboolean +e_ui_action_util_gvalue_to_enum_state (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + gint value; + + if (G_VALUE_HOLDS_ENUM (from_value)) + value = g_value_get_enum (from_value); + else + value = g_value_get_int (from_value); + + g_value_set_variant (to_value, g_variant_new_int32 (value)); + + return TRUE; +} + +/** + * e_ui_action_util_enum_state_to_gvalue: + * @binding: a #GBinding + * @from_value: a source #GValue + * @to_value: a destination #GValue + * @user_data: unused binding user data + * + * A utility function, which can be used as a transformation function + * of a #GBinding from an enum state of an #EUIAction created by + * e_ui_action_new_from_enum_entry() to an enum property. + * + * Returns: %TRUE + * + * Since: 3.56 + **/ +gboolean +e_ui_action_util_enum_state_to_gvalue (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + GVariant *value = g_value_get_variant (from_value); + + if (G_VALUE_HOLDS_ENUM (to_value)) + g_value_set_enum (to_value, value ? g_variant_get_int32 (value) : -1); + else + g_value_set_int (to_value, value ? g_variant_get_int32 (value) : -1); + + return TRUE; +} + +/** + * e_ui_action_util_assign_to_widget: + * @action: an #EUIAction + * @widget: a #GtkWidget + * + * Assigns @action to the @widget, syncing visible, sensitive and tooltip properties, + * together with the actionable properties. + * + * Since: 3.56 + **/ +void +e_ui_action_util_assign_to_widget (EUIAction *action, + GtkWidget *widget) +{ + gchar full_action_name[128]; + gint would_copy_bytes; + GtkActionable *actionable; + GVariant *target; + + g_return_if_fail (E_IS_UI_ACTION (action)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + would_copy_bytes = g_snprintf (full_action_name, sizeof (full_action_name), "%s.%s", + e_ui_action_get_map_name (action), + g_action_get_name (G_ACTION (action))); + g_warn_if_fail (would_copy_bytes < sizeof (full_action_name) - 1); + + actionable = GTK_ACTIONABLE (widget); + target = e_ui_action_ref_target (action); + + gtk_actionable_set_action_target_value (actionable, target); + gtk_actionable_set_action_name (actionable, full_action_name); + + g_clear_pointer (&target, g_variant_unref); + + e_binding_bind_property (action, "visible", + widget, "visible", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property (action, "sensitive", + widget, "sensitive", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property (action, "tooltip", + widget, "tooltip-text", + G_BINDING_SYNC_CREATE); +} diff --git a/src/e-util/e-ui-action.h b/src/e-util/e-ui-action.h new file mode 100644 index 0000000000..f4d99e0873 --- /dev/null +++ b/src/e-util/e-ui-action.h @@ -0,0 +1,125 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) +#error "Only should be included directly." +#endif + +#ifndef E_UI_ACTION_H +#define E_UI_ACTION_H + +#include + +G_BEGIN_DECLS + +struct _EUIActionGroup; +struct _GtkWidget; + +#define E_TYPE_UI_ACTION e_ui_action_get_type () + +G_DECLARE_FINAL_TYPE (EUIAction, e_ui_action, E, UI_ACTION, GObject) + +typedef void (* EUIActionFunc) (EUIAction *action, + GVariant *value, + gpointer user_data); + +typedef struct _EUIActionEntry { + const gchar *name; + const gchar *icon_name; + const gchar *label; + const gchar *accel; + const gchar *tooltip; + EUIActionFunc activate; + const gchar *parameter_type; + const gchar *state; + EUIActionFunc change_state; +} EUIActionEntry; + +typedef struct _EUIActionEnumEntry { + const gchar *name; + const gchar *icon_name; + const gchar *label; + const gchar *accel; + const gchar *tooltip; + EUIActionFunc activate; + gint state; +} EUIActionEnumEntry; + +/* The EUIAction implements GAction, thus use its API to get to the name and other properties. */ + +EUIAction * e_ui_action_new (const gchar *map_name, + const gchar *action_name, + const GVariantType *parameter_type); +EUIAction * e_ui_action_new_stateful (const gchar *map_name, + const gchar *action_name, + const GVariantType *parameter_type, + GVariant *state); +EUIAction * e_ui_action_new_from_entry (const gchar *map_name, + const EUIActionEntry *entry, + const gchar *translation_domain); +EUIAction * e_ui_action_new_from_enum_entry (const gchar *map_name, + const EUIActionEnumEntry *entry, + const gchar *translation_domain); +const gchar * e_ui_action_get_map_name (EUIAction *self); +GVariant * e_ui_action_ref_target (EUIAction *self); +void e_ui_action_set_state (EUIAction *self, + GVariant *value); +void e_ui_action_set_state_hint (EUIAction *self, + GVariant *state_hint); +void e_ui_action_set_visible (EUIAction *self, + gboolean visible); +gboolean e_ui_action_get_visible (EUIAction *self); +void e_ui_action_set_sensitive (EUIAction *self, + gboolean sensitive); +gboolean e_ui_action_get_sensitive (EUIAction *self); +gboolean e_ui_action_is_visible (EUIAction *self); +void e_ui_action_set_icon_name (EUIAction *self, + const gchar *icon_name); +const gchar * e_ui_action_get_icon_name (EUIAction *self); +void e_ui_action_set_label (EUIAction *self, + const gchar *label); +const gchar * e_ui_action_get_label (EUIAction *self); +void e_ui_action_set_accel (EUIAction *self, + const gchar *accel); +const gchar * e_ui_action_get_accel (EUIAction *self); +void e_ui_action_add_secondary_accel (EUIAction *self, + const gchar *accel); +GPtrArray * e_ui_action_get_secondary_accels(EUIAction *self); /* const gchar * */ +void e_ui_action_remove_secondary_accels + (EUIAction *self); +void e_ui_action_set_tooltip (EUIAction *self, + const gchar *tooltip); +const gchar * e_ui_action_get_tooltip (EUIAction *self); +void e_ui_action_set_radio_group (EUIAction *self, + GPtrArray *radio_group); +/* const */ GPtrArray * + e_ui_action_get_radio_group (EUIAction *self); +void e_ui_action_set_action_group (EUIAction *self, + struct _EUIActionGroup *action_group); +struct _EUIActionGroup * + e_ui_action_get_action_group (EUIAction *self); +gboolean e_ui_action_get_active (EUIAction *self); +void e_ui_action_set_active (EUIAction *self, + gboolean active); +void e_ui_action_emit_changed (EUIAction *self); + +gboolean e_ui_action_util_gvalue_to_enum_state + (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data); +gboolean e_ui_action_util_enum_state_to_gvalue + (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data); +void e_ui_action_util_assign_to_widget + (EUIAction *action, + struct _GtkWidget *widget); + +G_END_DECLS + +#endif /* E_UI_ACTION_H */ diff --git a/src/e-util/e-ui-manager.c b/src/e-util/e-ui-manager.c new file mode 100644 index 0000000000..e2992afb26 --- /dev/null +++ b/src/e-util/e-ui-manager.c @@ -0,0 +1,2229 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "evolution-config.h" + +#include + +#include + +#include "e-headerbar.h" +#include "e-headerbar-button.h" +#include "e-misc-utils.h" +#include "e-ui-action.h" +#include "e-ui-menu.h" +#include "e-ui-parser.h" +#include "e-util-enumtypes.h" + +#include "e-ui-manager.h" + +/** + * SECTION: e-ui-manager + * @include: e-util/e-util.h + * @short_description: a UI manager + * + * The #EUIManager is a central point of managing headerbars, toolbars, menubars + * and context menus in the application. + * The #EUIParser is used to read the .eui definition from an XML file or data. + * Each item in the definition corresponds to an #EUIAction, which should be added + * with the e_ui_manager_add_actions() or e_ui_manager_add_actions_enum() before + * the corresponding items are created with the e_ui_manager_create_item(). + * + * The e_ui_manager_set_action_groups_widget() is used to assign a widget to + * which the action groups should be inserted (for example a #GtkWindow, but + * can be other as well). + * + * The #GtkAccelGroup returned from the e_ui_manager_get_accel_group() needs + * to be added to the #GtkWindow with gtk_window_add_accel_group(). + * + * The object is not thread-safe, it's meant to be used only from + * the main/GUI thread. + * + * Since: 3.56 + **/ + +struct _EUIManager { + GObject parent; + + EUIParser *parser; + GtkAccelGroup *accel_group; + GHashTable *action_groups; /* gchar * ~> EUIActionGroup * */ + GHashTable *gicons; /* gchar * ~> GIcon * */ + GHashTable *groups; /* gchar * ~> GPtrArray * { EUIAction }; used for radio groups */ + + GWeakRef action_groups_widget; + + guint frozen; + gboolean changed_while_frozen; +}; + +enum { + SIGNAL_CHANGED, + SIGNAL_FREEZE, + SIGNAL_THAW, + SIGNAL_CREATE_ITEM, + SIGNAL_CREATE_GICON, + SIGNAL_IGNORE_ACCEL, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0, }; + +G_DEFINE_TYPE (EUIManager, e_ui_manager, G_TYPE_OBJECT) + +static void +e_ui_manager_gather_groups_recr (EUIManager *self, + EUIElement *elem) +{ + if (!elem) + return; + + if (e_ui_element_get_kind (elem) == E_UI_ELEMENT_KIND_ITEM) { + const gchar *group = e_ui_element_item_get_group (elem); + + if (group && *group && e_ui_element_item_get_action (elem)) { + EUIAction *action; + + action = e_ui_manager_get_action (self, e_ui_element_item_get_action (elem)); + if (action) { + GPtrArray *group_array; + + group_array = g_hash_table_lookup (self->groups, group); + + if (!group_array) { + group_array = g_ptr_array_new (); + g_hash_table_insert (self->groups, g_strdup (group), group_array); + } + + e_ui_action_set_radio_group (action, group_array); + } else { + g_warning ("%s: Action '%s' for group '%s' not found", G_STRFUNC, e_ui_element_item_get_action (elem), group); + } + } + } else if (e_ui_element_get_n_children (elem) > 0) { + guint ii, sz = e_ui_element_get_n_children (elem); + for (ii = 0; ii < sz; ii++) { + EUIElement *child = e_ui_element_get_child (elem, ii); + e_ui_manager_gather_groups_recr (self, child); + } + } +} + +static void +e_ui_manager_gather_groups (EUIManager *self) +{ + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, self->groups); + + while (g_hash_table_iter_next (&iter, NULL, &value)) { + GPtrArray *group_array = value; + guint ii; + + /* go from the back, the unset modifies content of the group_array */ + for (ii = group_array->len; ii-- > 0;) { + EUIAction *action = g_ptr_array_index (group_array, ii); + e_ui_action_set_radio_group (action, NULL); + } + } + + g_hash_table_remove_all (self->groups); + + e_ui_manager_gather_groups_recr (self, e_ui_parser_get_root (self->parser)); + + /* update the state, thus there's only one (or none) group item selected */ + g_hash_table_iter_init (&iter, self->groups); + + while (g_hash_table_iter_next (&iter, NULL, &value)) { + GPtrArray *group_array = value; + + if (group_array->len) { + EUIAction *action = g_ptr_array_index (group_array, 0); + GVariant *state; + + state = g_action_get_state (G_ACTION (action)); + if (state) { + /* while setting the same value, the function will update other group members with it */ + e_ui_action_set_state (action, state); + g_variant_unref (state); + } + } + } +} + +static void +e_ui_manager_changed (EUIManager *self) +{ + if (self->frozen) { + self->changed_while_frozen = TRUE; + return; + } + + e_ui_manager_gather_groups (self); + g_signal_emit (self, signals[SIGNAL_CHANGED], 0, NULL); +} + +static void +e_ui_manager_parser_changed_cb (EUIParser *parser, + gpointer user_data) +{ + EUIManager *self = user_data; + + e_ui_manager_changed (self); +} + +static void +e_ui_manager_dispose (GObject *object) +{ + EUIManager *self = E_UI_MANAGER (object); + + e_ui_manager_set_action_groups_widget (self, NULL); + + G_OBJECT_CLASS (e_ui_manager_parent_class)->dispose (object); +} + +static void +e_ui_manager_finalize (GObject *object) +{ + EUIManager *self = E_UI_MANAGER (object); + + g_clear_object (&self->parser); + g_clear_object (&self->accel_group); + g_clear_pointer (&self->action_groups, g_hash_table_unref); + g_clear_pointer (&self->gicons, g_hash_table_unref); + g_clear_pointer (&self->groups, g_hash_table_unref); + g_weak_ref_clear (&self->action_groups_widget); + + G_OBJECT_CLASS (e_ui_manager_parent_class)->finalize (object); +} + +static void +e_ui_manager_class_init (EUIManagerClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->dispose = e_ui_manager_dispose; + object_class->finalize = e_ui_manager_finalize; + + /* void changed (EUIManager *manager); */ + /** + * EUIManager::changed: + * @manager: an #EUIManager + * + * A signal called when the @manager content changed. It's a signal to + * regenerate the UI elements. + * + * Since: 3.56 + **/ + signals[SIGNAL_CHANGED] = g_signal_new ("changed", + E_TYPE_UI_MANAGER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0, + G_TYPE_NONE); + + /* void freeze (EUIManager *manager); */ + /** + * EUIManager::freeze: + * @manager: an #EUIManager + * + * A signal called when the @manager has called e_ui_manager_freeze(). + * + * Since: 3.56 + **/ + signals[SIGNAL_FREEZE] = g_signal_new ("freeze", + E_TYPE_UI_MANAGER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 0, + G_TYPE_NONE); + + /* void thaw (EUIManager *manager, + gboolean changed_while_frozen); */ + /** + * EUIManager::thaw: + * @manager: an #EUIManager + * @changed_while_frozen: whether changed while had been frozen + * + * A signal called when the @manager has called e_ui_manager_thaw(). + * When the @changed_while_frozen is set to %TRUE, there will also + * be called the #EUIManager::changed signal once the @manager + * is completely unfrozen. + * + * Since: 3.56 + **/ + signals[SIGNAL_THAW] = g_signal_new ("thaw", + E_TYPE_UI_MANAGER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_BOOLEAN); + + /* gboolean create_item (EUIManager *manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item); */ + /** + * EUIManager::create-item: (skip) + * @manager: an #EUIManager + * @elem: an #EUIElement to create the item for + * @action: an associated @EUIAction for the new item + * @for_kind: for which part of the UI the item should be created; it influences the type of the returned item + * @out_item: (out) (transfer full): a location to set the created item to + * + * Return %TRUE, when could create the item described by @elem with associated @action and + * sets it into the @out_item. The @for_kind can only be %E_UI_ELEMENT_KIND_HEADERBAR, + * %E_UI_ELEMENT_KIND_TOOLBAR or %E_UI_ELEMENT_KIND_MENU. + * + * For the %E_UI_ELEMENT_KIND_HEADERBAR any widget can be returned, though the mostly + * used might be an #EHeaderBarButton. + * + * For the %E_UI_ELEMENT_KIND_TOOLBAR only a #GtkToolItem descendant is expected. + * + * For the %E_UI_ELEMENT_KIND_MENU only a #GMenuItem descendant is expected. + * + * It's expected only one handler can create the item, thus the first + * which returns %TRUE will stop further signal emission. + * + * Returns: %TRUE when the item was created and set into the @out_item, + * %FALSE when cannot create the item + * + * Since: 3.56 + **/ + signals[SIGNAL_CREATE_ITEM] = g_signal_new ("create-item", + E_TYPE_UI_MANAGER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + g_signal_accumulator_true_handled, NULL, + NULL, + G_TYPE_BOOLEAN, 4, + G_TYPE_POINTER, /* EUIElement */ + E_TYPE_UI_ACTION, + E_TYPE_UI_ELEMENT_KIND, + G_TYPE_POINTER); + + /* gboolean create_gicon (EUIManager *manager, + const gchar *name, + GIcon **out_gicon); */ + /** + * EUIManager::create-gicon: + * @manager: an #EUIManager + * @name: a custom icon name + * @out_gicon: (out) (transfer full): an output location to store a created #GIcon to + * + * The actions can have defined custom icons as "gicon::name", + * aka with a "gicon::" prefix, which are looked for by the name (without + * the special prefix) using this callback. + * + * It's expected only one handler can create the #GIcon, thus the first + * which returns %TRUE will stop further signal emission. + * + * Returns: %TRUE when the item was created and set into the @out_gicon, + * %FALSE when cannot create the item + * + * Since: 3.56 + **/ + signals[SIGNAL_CREATE_GICON] = g_signal_new ("create-gicon", + E_TYPE_UI_MANAGER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + g_signal_accumulator_true_handled, NULL, + NULL, + G_TYPE_BOOLEAN, 2, + G_TYPE_STRING, + G_TYPE_POINTER); + + /* gboolean ignore_accel (EUIManager *manager, + EUIAction *action); */ + /** + * EUIManager::ignore-accel: + * @manager: an #EUIManager + * @action: an #EUIAction whose accelerator is about to be activated + * + * The signal allows to ignore accelerators to be activated. + * + * Multiple signal handlers can be connected, the first which + * returns %TRUE will stop the signal emission and the accelerator + * will be ignored. When all handlers return %FALSE, the accelerator + * will be used and the @action will be activated. + * + * Returns: %TRUE, when the accel should be ignored, %FALSE to + * allow the accel to be activated. + * + * Since:3.56 + **/ + signals[SIGNAL_IGNORE_ACCEL] = g_signal_new ("ignore-accel", + E_TYPE_UI_MANAGER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, + g_signal_accumulator_true_handled, NULL, + NULL, + G_TYPE_BOOLEAN, 1, + E_TYPE_UI_ACTION); +} + +static void +e_ui_manager_init (EUIManager *self) +{ + g_weak_ref_init (&self->action_groups_widget, NULL); + + self->parser = e_ui_parser_new (); + self->accel_group = gtk_accel_group_new (); + self->action_groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + self->gicons = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + self->groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); + + g_signal_connect_object (self->parser, "changed", + G_CALLBACK (e_ui_manager_parser_changed_cb), self, 0); +} + +/** + * e_ui_manager_new: + * + * Creates a new #EUIManager. Use g_object_unref() to free it, when no longer needed. + * + * Returns: (transfer full): a new #EUIManager + * + * Since: 3.56 + **/ +EUIManager * +e_ui_manager_new (void) +{ + return g_object_new (E_TYPE_UI_MANAGER, NULL); +} + +/** + * e_ui_manager_get_parser: + * @self: an #EUIManager + * + * Gets an #EUIParser associated with the @self. Any UI definitions + * are loaded into it and the layouts are read from it. + * + * Returns: (transfer none): an #EUIParser + * + * Since: 3.56 + **/ +EUIParser * +e_ui_manager_get_parser (EUIManager *self) +{ + g_return_val_if_fail (E_IS_UI_MANAGER (self), NULL); + + return self->parser; +} + +/** + * e_ui_manager_get_accel_group: + * @self: an #EUIManager + * + * Gets a #GtkAccelGroup associated with the @self. Actions + * with configured accelerators register themselves to this accel + * group. + * + * It should be added to a #GtkWindow with gtk_window_add_accel_group(). + * + * Returns: (transfer none): a #GtkAccelGroup + * + * Since: 3.56 + **/ +GtkAccelGroup * +e_ui_manager_get_accel_group (EUIManager *self) +{ + g_return_val_if_fail (E_IS_UI_MANAGER (self), NULL); + + return self->accel_group; +} + +/** + * e_ui_manager_freeze: + * @self: an #EUIManager + * + * Freezes change notifications on the @self. The function + * can be called multiple times, only each call should be + * followed by a corresponding e_ui_manager_thaw(). + * + * Since: 3.56 + **/ +void +e_ui_manager_freeze (EUIManager *self) +{ + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (self->frozen + 1 > self->frozen); + + self->frozen++; + + g_signal_emit (self, signals[SIGNAL_FREEZE], 0, NULL); +} + +/** + * e_ui_manager_thaw: + * @self: an #EUIManager + * + * Reverts effect of one e_ui_manager_freeze() call. + * It's a programming error to call this function when + * the @self is not frozen. + * + * Since: 3.56 + **/ +void +e_ui_manager_thaw (EUIManager *self) +{ + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (self->frozen > 0); + + self->frozen--; + + g_signal_emit (self, signals[SIGNAL_THAW], 0, self->changed_while_frozen, NULL); + + if (!self->frozen && self->changed_while_frozen) { + self->changed_while_frozen = FALSE; + + e_ui_manager_changed (self); + } +} + +/** + * e_ui_manager_is_frozen: + * @self: an #EUIManager + * + * Check whether the change notifications are frozen + * with e_ui_manager_freeze() call. + * + * Returns: whether change notifications are frozen + * + * Since: 3.56 + **/ +gboolean +e_ui_manager_is_frozen (EUIManager *self) +{ + g_return_val_if_fail (E_IS_UI_MANAGER (self), FALSE); + + return self->frozen > 0; +} + +static gboolean +e_ui_manager_can_process_accel (EUIManager *self, + EUIAction *action) +{ + gboolean ignore = FALSE; + + if (!e_ui_action_is_visible (action) || + !g_action_get_enabled (G_ACTION (action))) { + return FALSE; + } + + g_signal_emit (self, signals[SIGNAL_IGNORE_ACCEL], 0, action, &ignore); + + return !ignore; +} + +typedef struct _EAccelClosure { + GClosure parent; + EUIManager *manager; /* not referenced */ +} EAccelClosure; + +static void +e_ui_manager_closure_accel_activate (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + GAction *action = G_ACTION (closure->data); + EAccelClosure *accel_closure = (EAccelClosure *) closure; + + if (e_ui_manager_can_process_accel (accel_closure->manager, E_UI_ACTION (action))) { + const GVariantType *param_type; + + param_type = g_action_get_parameter_type (action); + if (!param_type) { + g_action_activate (action, NULL); + } else if (param_type == G_VARIANT_TYPE_BOOLEAN) { + GVariant *current_value = g_action_get_state (action); + GVariant *new_value; + + new_value = g_variant_new_boolean (current_value ? !g_variant_get_boolean (current_value) : TRUE); + g_variant_ref_sink (new_value); + + g_action_activate (action, new_value); + + g_clear_pointer (¤t_value, g_variant_unref); + g_clear_pointer (&new_value, g_variant_unref); + } else { + GVariant *target; + + target = e_ui_action_ref_target (E_UI_ACTION (action)); + g_action_activate (action, target); + g_clear_pointer (&target, g_variant_unref); + } + + /* accelerator was handled */ + g_value_set_boolean (return_value, TRUE); + } +} + +static void +e_ui_manager_connect_accel_cb (EUIManager *self, + EUIAction *action, + const gchar *accel, + gpointer user_data) +{ + guint key = 0; + GdkModifierType mods = 0; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + + if (!self->accel_group || !accel || !*accel) + return; + + gtk_accelerator_parse (accel, &key, &mods); + + if (key != 0) { + GClosure *closure; + EAccelClosure *accel_closure; + + closure = g_closure_new_object (sizeof (GClosure), G_OBJECT (action)); + g_closure_set_marshal (closure, e_ui_manager_closure_accel_activate); + + accel_closure = (EAccelClosure *) closure; + accel_closure->manager = self; + + gtk_accel_group_connect (self->accel_group, key, mods, GTK_ACCEL_LOCKED, closure); + } else { + EUIActionGroup *action_group = e_ui_action_get_action_group (action); + + g_warning ("%s: Failed to parse accel '%s' on action '%s.%s'", G_STRFUNC, accel, + action_group ? e_ui_action_group_get_name (action_group) : "no-group-set", + g_action_get_name (G_ACTION (action))); + } +} + + +static void +e_ui_manager_disconnect_accel_cb (EUIManager *self, + EUIAction *action, + const gchar *accel, + gpointer user_data) +{ + guint key = 0; + GdkModifierType mods = 0; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + + if (!self->accel_group || !accel || !*accel) + return; + + gtk_accelerator_parse (accel, &key, &mods); + + if (key != 0) + gtk_accel_group_disconnect_key (self->accel_group, key, mods); +} + +static void +e_ui_manager_foreach_action_accel (EUIManager *self, + EUIAction *action, + void (*func) (EUIManager *self, + EUIAction *action, + const gchar *accel, + gpointer user_data), + gpointer user_data) +{ + GPtrArray *secondary_accels; + const gchar *accel; + + accel = e_ui_action_get_accel (action); + if (accel && *accel) + func (self, action, accel, user_data); + + secondary_accels = e_ui_action_get_secondary_accels (action); + if (secondary_accels) { + guint ii; + + for (ii = 0; ii < secondary_accels->len; ii++) { + accel = g_ptr_array_index (secondary_accels, ii); + + if (accel && *accel) + func (self, action, accel, user_data); + } + } +} + +static void +e_ui_manager_add_action_accel (EUIManager *self, + EUIAction *action) +{ + e_ui_manager_foreach_action_accel (self, action, e_ui_manager_connect_accel_cb, NULL); +} + +static void +e_ui_manager_add_action_internal (EUIManager *self, + EUIActionGroup *action_group, + EUIAction *action, + EUIActionFunc activate, + EUIActionFunc change_state, + gpointer user_data) +{ + if (activate) + g_signal_connect (action, "activate", G_CALLBACK (activate), user_data); + + if (change_state) + g_signal_connect (action, "change-state", G_CALLBACK (change_state), user_data); + + /* this calls e_ui_manager_add_action_accel() in the group's "added" signal handler */ + e_ui_action_group_add (action_group, action); +} + +/** + * e_ui_manager_add_actions: + * @self: an #EUIManager + * @group_name: (not nullable): a name of an action group to add the actions to + * @translation_domain: (nullable): translation domain for the @entries' localized members, or %NULL + * @entries: action entries to be added, as #EUIActionEntry array + * @n_entries: how many items @entries has, or -1 when NULL-terminated + * @user_data: user data to pass to action callbacks + * + * Just like g_action_map_add_action_entries(), only uses #EUIAction instead + * of #GSimpleAction actions and adds the actions into a named action group. + * When there is no action group of the @group_name, a new is added. + * + * The @translation_domain can be #NULL, in which case the Evolution's translation + * domain is used. It's used also when the @translation_domain is an empty string. + * + * Since: 3.56 + **/ +void +e_ui_manager_add_actions (EUIManager *self, + const gchar *group_name, + const gchar *translation_domain, + const EUIActionEntry *entries, + gint n_entries, + gpointer user_data) +{ + EUIActionGroup *action_group; + const gchar *domain; + guint ii; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (group_name != NULL); + g_return_if_fail (entries != NULL || n_entries == 0); + + domain = translation_domain; + if (!domain || !*domain) + domain = GETTEXT_PACKAGE; + + action_group = e_ui_manager_get_action_group (self, group_name); + + for (ii = 0; n_entries < 0 ? entries[ii].name != NULL : ii < n_entries; ii++) { + const EUIActionEntry *entry = &(entries[ii]); + EUIAction *action; + + action = e_ui_action_new_from_entry (group_name, entry, domain); + if (!action) + continue; + + e_ui_manager_add_action_internal (self, action_group, action, entry->activate, entry->change_state, user_data); + + g_object_unref (action); + } + + e_ui_manager_changed (self); +} + +/** + * e_ui_manager_add_actions_enum: + * @self: an #EUIManager + * @group_name: (not nullable): a name of an action group to add the actions to + * @translation_domain: (nullable): translation domain for the @entries' localized members, or %NULL + * @entries: action entries to be added, as #EUIActionEnumEntry array + * @n_entries: how many items @entries has, or -1 when NULL-terminated + * @user_data: user data to pass to action callbacks + * + * The same as e_ui_manager_add_actions(), only creates radio actions, whose + * states correspond to certain enum value. If bindings between the action's + * state and a corresponding enum #GObject property is needed, a utility function + * e_ui_action_util_gvalue_to_enum_state() and e_ui_action_util_enum_state_to_gvalue() + * can be used to transform the value from the #GObject to an action state or vice versa. + * + * The @translation_domain can be %NULL, in which case the Evolution's translation + * domain is used. It's used also when the @translation_domain is an empty string. + * + * Since: 3.56 + **/ +void +e_ui_manager_add_actions_enum (EUIManager *self, + const gchar *group_name, + const gchar *translation_domain, + const EUIActionEnumEntry *entries, + gint n_entries, + gpointer user_data) +{ + EUIActionGroup *action_group; + const gchar *domain; + guint ii; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (group_name != NULL); + g_return_if_fail (entries != NULL || n_entries == 0); + + domain = translation_domain; + if (!domain || !*domain) + domain = GETTEXT_PACKAGE; + + action_group = e_ui_manager_get_action_group (self, group_name); + + for (ii = 0; n_entries < 0 ? entries[ii].name != NULL : ii < n_entries; ii++) { + const EUIActionEnumEntry *entry = &(entries[ii]); + EUIAction *action; + + action = e_ui_action_new_from_enum_entry (group_name, entry, domain); + if (!action) + continue; + + e_ui_manager_add_action_internal (self, action_group, action, entry->activate, (EUIActionFunc) e_ui_action_set_state, user_data); + + g_object_unref (action); + } + + e_ui_manager_changed (self); +} + +/** + * e_ui_manager_add_action: + * @self: an #EUIManager + * @group_name: (not nullable): a name of an action group to add the action to + * @action: (transfer none): the action to add + * @activate: (nullable): an optional callback to call on "activate" signal, or %NULL + * @change_state: (nullable): an optional callback to call on "change-state" signal, or %NULL + * @user_data: user data to pass to action callbacks + * + * Adds a single @action to the @group_name. The actions group cannot contain + * an action of the same name. + * + * Since: 3.56 + **/ +void +e_ui_manager_add_action (EUIManager *self, + const gchar *group_name, + EUIAction *action, + EUIActionFunc activate, + EUIActionFunc change_state, + gpointer user_data) +{ + EUIActionGroup *action_group; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (group_name != NULL); + g_return_if_fail (E_IS_UI_ACTION (action)); + + action_group = e_ui_manager_get_action_group (self, group_name); + e_ui_manager_add_action_internal (self, action_group, action, activate, change_state, user_data); + + e_ui_manager_changed (self); +} + +/** + * e_ui_manager_add_actions_with_eui_data: + * @self: an #EUIManager + * @group_name: (not nullable): a name of an action group to add the actions to + * @translation_domain: (nullable): translation domain for the @entries' localized members, or %NULL + * @entries: action entries to be added, as #EUIActionEntry array + * @n_entries: how many items @entries has, or -1 when NULL-terminated + * @user_data: user data to pass to action callbacks + * @eui: Evolution UI definition + * + * Combines e_ui_manager_add_actions() with e_ui_parser_merge_data(), in this order, + * printing any errors in the @eui into the terminal. This can be used to add built-in + * UI definition with the related actions in a single call. + * + * Since: 3.56 + **/ +void +e_ui_manager_add_actions_with_eui_data (EUIManager *self, + const gchar *group_name, + const gchar *translation_domain, + const EUIActionEntry *entries, + gint n_entries, + gpointer user_data, + const gchar *eui) +{ + GError *local_error = NULL; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (group_name != NULL); + g_return_if_fail (entries != NULL || n_entries == 0); + g_return_if_fail (eui != NULL); + + e_ui_manager_add_actions (self, group_name, translation_domain, entries, n_entries, user_data); + + if (!e_ui_parser_merge_data (e_ui_manager_get_parser (self), eui, -1, &local_error)) + g_critical ("%s: Failed to merge built-in UI definition: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error"); + + g_clear_error (&local_error); +} + +/** + * e_ui_manager_add_action_groups_to_widget: + * @self: an #EUIManager + * @widget: a #GtkWidget + * + * Adds all currently known action groups into the @widget with + * gtk_widget_insert_action_group(). In contrast to e_ui_manager_set_action_groups_widget(), + * this does not add any later added action groups into the @widget. + * In other words, this is a one-time operation only. + * + * Since: 3.56 + **/ +void +e_ui_manager_add_action_groups_to_widget (EUIManager *self, + GtkWidget *widget) +{ + GHashTableIter iter; + gpointer key = NULL, value = NULL; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (GTK_IS_WIDGET (widget)); + + g_hash_table_iter_init (&iter, self->action_groups); + while (g_hash_table_iter_next (&iter, &key, &value)) { + const gchar *name = key; + EUIActionGroup *group = value; + + gtk_widget_insert_action_group (widget, name, G_ACTION_GROUP (group)); + } +} + +/** + * e_ui_manager_set_action_groups_widget: + * @self: an #EUIManager + * @widget: (nullable): a #GtkWidget, or %NULL + * + * Sets the @widget to be the one where all action groups will + * be inserted. When the @self creates a new action group, it + * is automatically added into the @widget. + * + * When the @widget is %NULL, any previous widget is unset. + * + * Overwriting any existing @widget will remove the groups + * from the previous widget first. + * + * Since: 3.56 + **/ +void +e_ui_manager_set_action_groups_widget (EUIManager *self, + GtkWidget *widget) +{ + GtkWidget *current; + GHashTableIter iter; + gpointer key = NULL, value = NULL; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + if (widget) + g_return_if_fail (GTK_IS_WIDGET (widget)); + + current = g_weak_ref_get (&self->action_groups_widget); + + if (current == widget) { + g_clear_object (¤t); + return; + } + + g_hash_table_iter_init (&iter, self->action_groups); + while (g_hash_table_iter_next (&iter, &key, &value)) { + const gchar *name = key; + EUIActionGroup *group = value; + + if (current) + gtk_widget_insert_action_group (current, name, NULL); + + if (widget) + gtk_widget_insert_action_group (widget, name, G_ACTION_GROUP (group)); + } + + g_weak_ref_set (&self->action_groups_widget, widget); + + g_clear_object (¤t); +} + +/** + * e_ui_manager_ref_action_groups_widget: + * @self: an #EUIManager + * + * References a #GtkWidget, which is used to add action groups to. + * + * The returned widget, if not %NULL, should be dereferenced + * with g_object_unref(), when no longer needed. + * + * Returns: (transfer full) (nullable): a referenced #GtkWidget used + * to add action groups to, or %NULL, when none is set + * + * Since: 3.56 + **/ +GtkWidget * +e_ui_manager_ref_action_groups_widget (EUIManager *self) +{ + g_return_val_if_fail (E_IS_UI_MANAGER (self), NULL); + + return g_weak_ref_get (&self->action_groups_widget); +} + +/** + * e_ui_manager_has_action_group: + * @self: an #EUIManager + * @name: an action group name + * + * Check whether an action group named @name already exists in @self. + * + * Returns: %TRUE, when the action group exists, %FALSE otherwise + * + * Since: 3.56 + **/ +gboolean +e_ui_manager_has_action_group (EUIManager *self, + const gchar *name) +{ + g_return_val_if_fail (E_IS_UI_MANAGER (self), FALSE); + g_return_val_if_fail (name != NULL, FALSE); + + return g_hash_table_lookup (self->action_groups, name) != NULL; +} + +static void +e_ui_manager_action_group_action_added_cb (EUIActionGroup *action_group, + EUIAction *action, + gpointer user_data) +{ + EUIManager *self = user_data; + + e_ui_manager_add_action_accel (self, action); +} + +static void +e_ui_manager_action_group_action_removed_cb (EUIActionGroup *action_group, + EUIAction *action, + gpointer user_data) +{ + EUIManager *self = user_data; + + e_ui_manager_foreach_action_accel (self, action, e_ui_manager_disconnect_accel_cb, NULL); +} + +static void +e_ui_manager_claim_new_action_group (EUIManager *self, + EUIActionGroup *action_group) /* (transfer full) */ +{ + GtkWidget *action_groups_widget; + GPtrArray *actions; + const gchar *name; + guint ii; + + name = e_ui_action_group_get_name (action_group); + + g_hash_table_insert (self->action_groups, (gpointer) name, action_group); + + actions = e_ui_action_group_list_actions (action_group); + for (ii = 0; ii < actions->len; ii++) { + EUIAction *action = g_ptr_array_index (actions, ii); + + e_ui_manager_add_action_accel (self, action); + } + + g_clear_pointer (&actions, g_ptr_array_unref); + + action_groups_widget = g_weak_ref_get (&self->action_groups_widget); + if (action_groups_widget) { + gtk_widget_insert_action_group (action_groups_widget, name, G_ACTION_GROUP (action_group)); + g_clear_object (&action_groups_widget); + } + + g_signal_connect_object (action_group, "added", + G_CALLBACK (e_ui_manager_action_group_action_added_cb), self, 0); + g_signal_connect_object (action_group, "removed", + G_CALLBACK (e_ui_manager_action_group_action_removed_cb), self, 0); + g_signal_connect_object (action_group, "accel-added", + G_CALLBACK (e_ui_manager_connect_accel_cb), self, G_CONNECT_SWAPPED); + g_signal_connect_object (action_group, "accel-removed", + G_CALLBACK (e_ui_manager_disconnect_accel_cb), self, G_CONNECT_SWAPPED); +} + +/** + * e_ui_manager_get_action_group: + * @self: an #EUIManager + * @name: an action group name + * + * Gets an #EUIActionGroup named @name. If no such exists, a new is created. + * Use e_ui_manager_has_action_group() to check whether an action group exists. + * + * Returns: (transfer none): an #EUIActionGroup named @name + * + * Since: 3.56 + **/ +EUIActionGroup * +e_ui_manager_get_action_group (EUIManager *self, + const gchar *name) +{ + EUIActionGroup *action_group; + + g_return_val_if_fail (E_IS_UI_MANAGER (self), NULL); + g_return_val_if_fail (name != NULL, NULL); + + action_group = g_hash_table_lookup (self->action_groups, name); + if (!action_group) { + action_group = e_ui_action_group_new (name); + + e_ui_manager_claim_new_action_group (self, action_group); + } + + return action_group; +} + +/** + * e_ui_manager_add_action_group: + * @self: an #EUIManager + * @action_group: (transfer none): an #EUIActionGroup to add + * + * Adds an existing action group to the @self, being able to + * call actions from it. The function does nothing when the @action_group + * is already part of the @self, nonetheless it's considered a programming + * error to try to add a different group of the same name into the @self. + * + * Since: 3.56 + **/ +void +e_ui_manager_add_action_group (EUIManager *self, + EUIActionGroup *action_group) +{ + EUIActionGroup *existing_group; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (E_IS_UI_ACTION_GROUP (action_group)); + + existing_group = g_hash_table_lookup (self->action_groups, e_ui_action_group_get_name (action_group)); + + if (existing_group && existing_group != action_group) { + g_warning ("%s: A different action group of the name '%s' already exists, ignoring the new group", + G_STRFUNC, e_ui_action_group_get_name (action_group)); + return; + } else if (existing_group == action_group) { + return; + } + + e_ui_manager_claim_new_action_group (self, g_object_ref (action_group)); +} + +/** + * e_ui_manager_get_action: + * @self: an #EUIManager + * @name: an action name + * + * Looks up an #EUIAction by its @name among all known action maps and returns it. + * + * Returns: (nullable) (transfer none): an #EUIAction named @name, or %NULL, if not found + * + * Since: 3.56 + **/ +EUIAction * +e_ui_manager_get_action (EUIManager *self, + const gchar *name) +{ + GHashTableIter iter; + gpointer key = NULL, value = NULL; + + g_return_val_if_fail (E_IS_UI_MANAGER (self), NULL); + g_return_val_if_fail (name != NULL, NULL); + + g_hash_table_iter_init (&iter, self->action_groups); + while (g_hash_table_iter_next (&iter, &key, &value)) { + const gchar *group_name = key; + EUIActionGroup *action_group = value; + + if (action_group) { + EUIAction *action; + + action = e_ui_action_group_get_action (action_group, name); + if (action) { + if (E_IS_UI_ACTION (action)) + return action; + + g_warning ("%s: Found action '%s' in action group '%s', but it's not an EUIAction, it's %s instead", + G_STRFUNC, name, group_name, G_OBJECT_TYPE_NAME (action)); + break; + } + } + } + + return NULL; +} + +/** + * e_ui_manager_get_gicon: + * @self: an #EUIManager + * @name: a #GIcon name to retrieve + * + * Retrieves a named #GIcon. These are cached. The signal "create-gicon" + * is used to create icons prefixed with "gicon::" in the .eui definitions, + * as they are custom icons. The @name is without this prefix. + * + * While returning %NULL is possible, it's considered an error and + * a runtime warning is printed on the terminal, thus there should + * always be a "create-gicon" signal handler providing the #GIcon. + * + * Returns: (transfer none) (nullable): a #GIcon named @name, or %NULL, if not found + * + * Since: 3.56 + **/ +GIcon * +e_ui_manager_get_gicon (EUIManager *self, + const gchar *name) +{ + GIcon *gicon = NULL; + + g_return_val_if_fail (E_IS_UI_MANAGER (self), NULL); + g_return_val_if_fail (name != NULL, NULL); + + gicon = g_hash_table_lookup (self->gicons, name); + + if (!gicon) { + gboolean handled = FALSE; + + g_signal_emit (self, signals[SIGNAL_CREATE_GICON], 0, name, &gicon, &handled); + + if (!gicon) { + g_warning ("%s: Nothing created gicon '%s'", G_STRFUNC, name); + gicon = g_themed_icon_new ("image-missing"); + } + + g_hash_table_insert (self->gicons, g_strdup (name), gicon); + } + + return gicon; +} + +static gboolean +eum_parent_is_header_bar_button (GtkWidget *child) +{ + while (child && !E_IS_HEADER_BAR_BUTTON (child)) + child = gtk_widget_get_parent (child); + + return child != NULL; +} + +static void +e_ui_manager_add_css_classes (EUIManager *self, + GtkWidget *item, + const gchar *css_classes) /* space-separated */ +{ + EHeaderBarButton *header_bar_button = NULL; + GtkStyleContext *style_context; + + if (!item || !css_classes || !*css_classes) + return; + + header_bar_button = E_IS_HEADER_BAR_BUTTON (item) ? E_HEADER_BAR_BUTTON (item) : NULL; + style_context = gtk_widget_get_style_context (item); + + if (strchr (css_classes, ' ')) { + gchar **strv = g_strsplit (css_classes, " ", -1); + guint ii; + + for (ii = 0; strv && strv[ii]; ii++) { + gchar *css_class = g_strchomp (strv[ii]); + + if (*css_class) { + if (header_bar_button) + e_header_bar_button_css_add_class (header_bar_button, css_class); + else + gtk_style_context_add_class (style_context, css_class); + } + } + + g_strfreev (strv); + } else { + if (header_bar_button) + e_header_bar_button_css_add_class (header_bar_button, css_classes); + else + gtk_style_context_add_class (style_context, css_classes); + } +} + +static GObject * +e_ui_manager_create_headerbar_item (EUIManager *self, + EUIElement *elem, + EUIAction *action) +{ + GtkWidget *item; + + item = e_header_bar_button_new (e_ui_action_get_label (action), action, self); + + if (e_ui_element_item_get_icon_only_is_set (elem)) + e_header_bar_button_set_show_icon_only (E_HEADER_BAR_BUTTON (item), e_ui_element_item_get_icon_only (elem)); + + e_ui_manager_add_css_classes (self, item, e_ui_element_item_get_css_classes (elem)); + e_ui_manager_update_item_from_action (self, item, action); + + return G_OBJECT (item); +} + +static GObject * +e_ui_manager_create_toolbar_item (EUIManager *self, + EUIElement *elem, + EUIAction *action) +{ + GtkToolButton *item = NULL; + GVariant *state; + + state = g_action_get_state (G_ACTION (action)); + + if (e_ui_action_get_radio_group (action)) + item = GTK_TOOL_BUTTON (gtk_toggle_tool_button_new ()); + else if (state && g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) + item = GTK_TOOL_BUTTON (gtk_toggle_tool_button_new ()); + else + item = GTK_TOOL_BUTTON (gtk_tool_button_new (NULL, NULL)); + + g_clear_pointer (&state, g_variant_unref); + + e_ui_manager_add_css_classes (self, GTK_WIDGET (item), e_ui_element_item_get_css_classes (elem)); + gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), e_ui_element_item_get_important (elem)); + e_ui_manager_update_item_from_action (self, item, action); + + return G_OBJECT (item); +} + +static GObject * +e_ui_manager_create_menu_item (EUIManager *self, + EUIElement *elem, + EUIAction *action) +{ + GMenuItem *item; + + item = g_menu_item_new (NULL, NULL); + + e_ui_manager_update_item_from_action (self, item, action); + + if (e_ui_element_item_get_text_only_is_set (elem) && + e_ui_element_item_get_text_only (elem)) + g_menu_item_set_attribute (item, "icon", NULL); + + return G_OBJECT (item); +} + +static GObject * +e_ui_manager_create_item_one (EUIManager *self, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind) +{ + GObject *item = NULL; + gboolean handled = FALSE; + + g_return_val_if_fail (elem != NULL, NULL); + g_return_val_if_fail (action != NULL, NULL); + g_return_val_if_fail (for_kind == E_UI_ELEMENT_KIND_MENU || for_kind == E_UI_ELEMENT_KIND_HEADERBAR || for_kind == E_UI_ELEMENT_KIND_TOOLBAR, NULL); + + g_signal_emit (self, signals[SIGNAL_CREATE_ITEM], 0, elem, action, for_kind, &item, &handled); + + if (!handled && !item) { + switch (for_kind) { + case E_UI_ELEMENT_KIND_HEADERBAR: + item = e_ui_manager_create_headerbar_item (self, elem, action); + break; + case E_UI_ELEMENT_KIND_TOOLBAR: + item = e_ui_manager_create_toolbar_item (self, elem, action); + break; + case E_UI_ELEMENT_KIND_MENU: + item = e_ui_manager_create_menu_item (self, elem, action); + break; + default: + g_warn_if_reached (); + break; + } + } + + return item; +} + +static void +emu_traverse_headerbar_rec (EUIManager *self, + EHeaderBar *eheaderbar, + GtkHeaderBar *gtkheaderbar, + EUIElement *parent_elem, + gboolean add_to_start, + GHashTable *groups, + gboolean *inout_need_separator, + gboolean *inout_any_added) +{ + guint ii, len; + + len = e_ui_element_get_n_children (parent_elem); + + for (ii = 0; ii < len; ii++) { + EUIElement *elem = e_ui_element_get_child (parent_elem, add_to_start ? ii : len - ii - 1); + EUIAction *action; + + if (!elem) + continue; + + switch (e_ui_element_get_kind (elem)) { + case E_UI_ELEMENT_KIND_ITEM: + action = e_ui_manager_get_action (self, e_ui_element_item_get_action (elem)); + if (action) { + GObject *item; + + item = e_ui_manager_create_item_one (self, elem, action, E_UI_ELEMENT_KIND_HEADERBAR); + if (item) { + GPtrArray *radio_group; + + if (*inout_any_added && *inout_need_separator) { + GtkWidget *separator; + + separator = gtk_separator_new (GTK_ORIENTATION_VERTICAL); + gtk_widget_set_visible (separator, TRUE); + + if (eheaderbar) { + if (add_to_start) + e_header_bar_pack_start (eheaderbar, separator, 0); + else + e_header_bar_pack_end (eheaderbar, separator, 0); + } else { + if (add_to_start) + gtk_header_bar_pack_start (gtkheaderbar, separator); + else + gtk_header_bar_pack_end (gtkheaderbar, separator); + } + } + + *inout_any_added = TRUE; + *inout_need_separator = FALSE; + + radio_group = e_ui_action_get_radio_group (action); + if (radio_group && GTK_IS_RADIO_BUTTON (item)) { + GSList **pgroup; + + pgroup = g_hash_table_lookup (groups, radio_group); + if (pgroup) { + gtk_radio_button_set_group (GTK_RADIO_BUTTON (item), *pgroup); + } else { + pgroup = g_new0 (GSList *, 1); + *pgroup = gtk_radio_button_get_group (GTK_RADIO_BUTTON (item)); + g_hash_table_insert (groups, radio_group, pgroup); + } + } + + if (eheaderbar) { + if (add_to_start) + e_header_bar_pack_start (eheaderbar, GTK_WIDGET (item), e_ui_element_item_get_label_priority (elem)); + else + e_header_bar_pack_end (eheaderbar, GTK_WIDGET (item), e_ui_element_item_get_label_priority (elem)); + } else { + if (add_to_start) + gtk_header_bar_pack_start (gtkheaderbar, GTK_WIDGET (item)); + else + gtk_header_bar_pack_end (gtkheaderbar, GTK_WIDGET (item)); + } + } + } else { + g_warning ("%s: Cannot find action '%s' for an item", G_STRFUNC, e_ui_element_item_get_action (elem)); + } + break; + case E_UI_ELEMENT_KIND_SEPARATOR: + *inout_need_separator = *inout_any_added; + break; + case E_UI_ELEMENT_KIND_PLACEHOLDER: + emu_traverse_headerbar_rec (self, eheaderbar, gtkheaderbar, elem, add_to_start, groups, inout_need_separator, inout_any_added); + break; + default: + g_warn_if_reached (); + break; + } + } +} + +static void +emu_traverse_headerbar (EUIManager *self, + EHeaderBar *eheaderbar, + GtkHeaderBar *gtkheaderbar, + EUIElement *elem) +{ + GHashTable *groups; /* gpointer group ~> GSList ** */ + gboolean need_separator = FALSE; + gboolean any_added = FALSE; + guint ii, len; + + groups = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + + len = e_ui_element_get_n_children (elem); + for (ii = 0; ii < len; ii++) { + EUIElement *subelem = e_ui_element_get_child (elem, ii); + + if (e_ui_element_get_kind (subelem) == E_UI_ELEMENT_KIND_START || + e_ui_element_get_kind (subelem) == E_UI_ELEMENT_KIND_END) { + emu_traverse_headerbar_rec (self, eheaderbar, gtkheaderbar, subelem, + e_ui_element_get_kind (subelem) == E_UI_ELEMENT_KIND_START, + groups, &need_separator, &any_added); + } else { + g_warn_if_reached (); + } + } + + g_hash_table_destroy (groups); +} + +static void +emu_headerbar_handle_changed_cb (EUIManager *self, + gpointer user_data) +{ + EHeaderBar *headerbar = user_data; + EUIElement *elem; + const gchar *id; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (E_IS_HEADER_BAR (headerbar)); + + e_header_bar_remove_all (headerbar); + + id = gtk_widget_get_name (GTK_WIDGET (headerbar)); + g_return_if_fail (id != NULL); + g_return_if_fail (e_ui_parser_get_root (self->parser) != NULL); + + elem = e_ui_element_get_child_by_id (e_ui_parser_get_root (self->parser), id); + if (!elem) { + g_warning ("%s: Cannot find item with id '%s'", G_STRFUNC, id); + return; + } + + emu_traverse_headerbar (self, headerbar, NULL, elem); +} + +static GObject * +e_ui_manager_create_item_for_headerbar (EUIManager *self, + EUIElement *elem) +{ + GtkWidget *widget; + + g_return_val_if_fail (elem != NULL, NULL); + + if (e_ui_element_headerbar_get_use_gtk_type (elem)) { + GtkHeaderBar *gtkheaderbar; + + widget = gtk_header_bar_new (); + gtkheaderbar = GTK_HEADER_BAR (widget); + + gtk_header_bar_set_show_close_button (gtkheaderbar, TRUE); + + emu_traverse_headerbar (self, NULL, gtkheaderbar, elem); + } else { + EHeaderBar *eheaderbar; + + widget = e_header_bar_new (); + eheaderbar = E_HEADER_BAR (widget); + + g_signal_connect_object (self, "changed", + G_CALLBACK (emu_headerbar_handle_changed_cb), eheaderbar, 0); + + emu_traverse_headerbar (self, eheaderbar, NULL, elem); + } + + gtk_widget_set_name (widget, e_ui_element_get_id (elem)); + + return G_OBJECT (widget); +} + +static void +emu_traverse_toolbar_rec (EUIManager *self, + GtkToolbar *toolbar, + EUIElement *parent_elem, + GHashTable *groups, + gboolean *inout_need_separator, + gboolean *inout_any_added) +{ + guint ii, len; + + len = e_ui_element_get_n_children (parent_elem); + + for (ii = 0; ii < len; ii++) { + EUIElement *elem = e_ui_element_get_child (parent_elem, ii); + EUIAction *action; + + if (!elem) + continue; + + switch (e_ui_element_get_kind (elem)) { + case E_UI_ELEMENT_KIND_ITEM: + action = e_ui_manager_get_action (self, e_ui_element_item_get_action (elem)); + if (action) { + GObject *item; + + item = e_ui_manager_create_item_one (self, elem, action, E_UI_ELEMENT_KIND_TOOLBAR); + if (item) { + if (GTK_IS_TOOL_ITEM (item)) { + if (*inout_any_added && *inout_need_separator) { + GtkToolItem *separator; + + separator = gtk_separator_tool_item_new (); + gtk_toolbar_insert (toolbar, separator, -1); + } + + *inout_any_added = TRUE; + *inout_need_separator = FALSE; + + gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (item), -1); + } else { + g_warning ("%s: Expected GtkToolItem, but received %s for action '%s.%s'", G_STRFUNC, + G_OBJECT_TYPE_NAME (item), e_ui_action_get_map_name (action), e_ui_element_item_get_action (elem)); + g_object_ref_sink (item); + g_clear_object (&item); + } + } + } else { + g_warning ("%s: Cannot find action '%s' for an item", G_STRFUNC, e_ui_element_item_get_action (elem)); + } + break; + case E_UI_ELEMENT_KIND_SEPARATOR: + *inout_need_separator = *inout_any_added; + break; + case E_UI_ELEMENT_KIND_PLACEHOLDER: + emu_traverse_toolbar_rec (self, toolbar, elem, groups, inout_need_separator, inout_any_added); + break; + default: + g_warn_if_reached (); + break; + } + } +} + +static void +emu_traverse_toolbar (EUIManager *self, + GtkToolbar *toolbar, + EUIElement *elem) +{ + GHashTable *groups; /* gpointer group ~> GSList ** */ + gboolean need_separator = FALSE; + gboolean any_added = FALSE; + + groups = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + + emu_traverse_toolbar_rec (self, toolbar, elem, groups, &need_separator, &any_added); + + g_hash_table_destroy (groups); +} + +static void +emu_toolbar_handle_changed_cb (EUIManager *self, + gpointer user_data) +{ + GtkContainer *toolbar = user_data; + GList *children, *link; + EUIElement *elem; + const gchar *id; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (GTK_IS_TOOLBAR (toolbar)); + + children = gtk_container_get_children (toolbar); + for (link = children; link; link = g_list_next (link)) { + gtk_container_remove (toolbar, link->data); + } + + g_list_free (children); + + id = gtk_widget_get_name (GTK_WIDGET (toolbar)); + g_return_if_fail (id != NULL); + g_return_if_fail (e_ui_parser_get_root (self->parser) != NULL); + + elem = e_ui_element_get_child_by_id (e_ui_parser_get_root (self->parser), id); + if (!elem) { + g_warning ("%s: Cannot find item with id '%s'", G_STRFUNC, id); + return; + } + + emu_traverse_toolbar (self, GTK_TOOLBAR (toolbar), elem); +} + +static GObject * +e_ui_manager_create_item_for_toolbar (EUIManager *self, + EUIElement *elem) +{ + GtkToolbar *toolbar; + + g_return_val_if_fail (elem != NULL, NULL); + + toolbar = GTK_TOOLBAR (gtk_toolbar_new ()); + gtk_widget_set_name (GTK_WIDGET (toolbar), e_ui_element_get_id (elem)); + + if (e_ui_element_toolbar_get_primary (elem)) { + gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (toolbar)), + GTK_STYLE_CLASS_PRIMARY_TOOLBAR); + } + + e_util_setup_toolbar_icon_size (toolbar, GTK_ICON_SIZE_BUTTON); + + g_signal_connect_object (self, "changed", + G_CALLBACK (emu_toolbar_handle_changed_cb), toolbar, 0); + + emu_traverse_toolbar (self, toolbar, elem); + + return G_OBJECT (toolbar); +} + +static void +eum_traverse_menu (EUIManager *self, + EUIMenu *ui_menu, + EUIElement *parent_elem, + GMenu *parent_menu, + gboolean is_popup, + GMenu **inout_section) +{ + GMenu *section = *inout_section; + guint ii, len; + + len = e_ui_element_get_n_children (parent_elem); + + for (ii = 0; ii < len; ii++) { + EUIElement *elem = e_ui_element_get_child (parent_elem, ii); + EUIAction *action; + + if (!elem) + continue; + + switch (e_ui_element_get_kind (elem)) { + case E_UI_ELEMENT_KIND_SUBMENU: + action = e_ui_manager_get_action (self, e_ui_element_submenu_get_action (elem)); + if (action) { + e_ui_menu_track_action (ui_menu, action); + + if (e_ui_action_is_visible (action) && + (!is_popup || g_action_get_enabled (G_ACTION (action)))) { + GMenu *submenu; + GMenu *subsection = NULL; + + submenu = g_menu_new (); + + eum_traverse_menu (self, ui_menu, elem, submenu, is_popup, &subsection); + + if (subsection && g_menu_model_get_n_items (G_MENU_MODEL (subsection)) > 0) + g_menu_append_section (submenu, NULL, G_MENU_MODEL (subsection)); + + g_clear_object (&subsection); + + if (g_menu_model_get_n_items (G_MENU_MODEL (submenu)) > 0) { + GMenuItem *item; + + if (!section) + section = g_menu_new (); + + item = g_menu_item_new_submenu (e_ui_action_get_label (action), G_MENU_MODEL (submenu)); + e_ui_manager_update_item_from_action (self, item, action); + + g_menu_append_item (section, item); + + g_clear_object (&item); + } + + g_clear_object (&submenu); + } + } else { + g_warning ("%s: Cannot find action '%s' for a submenu", G_STRFUNC, e_ui_element_submenu_get_action (elem)); + } + break; + case E_UI_ELEMENT_KIND_ITEM: + action = e_ui_manager_get_action (self, e_ui_element_item_get_action (elem)); + if (action) { + e_ui_menu_track_action (ui_menu, action); + + if (e_ui_action_is_visible (action) && + (!is_popup || g_action_get_enabled (G_ACTION (action)))) { + GObject *item; + + item = e_ui_manager_create_item_one (self, elem, action, E_UI_ELEMENT_KIND_MENU); + if (item) { + if (G_IS_MENU_ITEM (item)) { + if (!section) + section = g_menu_new (); + g_menu_append_item (section, G_MENU_ITEM (item)); + } else { + g_warning ("%s: Expected GMenuItem, but received %s for action '%s.%s'", G_STRFUNC, + G_OBJECT_TYPE_NAME (item), e_ui_action_get_map_name (action), e_ui_element_item_get_action (elem)); + } + g_clear_object (&item); + } + } + } else { + g_warning ("%s: Cannot find action '%s' for an item", G_STRFUNC, e_ui_element_item_get_action (elem)); + } + break; + case E_UI_ELEMENT_KIND_SEPARATOR: + if (section && g_menu_model_get_n_items (G_MENU_MODEL (section)) > 0) { + if (parent_menu) + g_menu_append_section (parent_menu, NULL, G_MENU_MODEL (section)); + else + e_ui_menu_append_section (ui_menu, G_MENU_MODEL (section)); + } + + g_clear_object (§ion); + break; + case E_UI_ELEMENT_KIND_PLACEHOLDER: + eum_traverse_menu (self, ui_menu, elem, parent_menu, is_popup, §ion); + break; + default: + g_warn_if_reached (); + break; + } + } + + *inout_section = section; +} + +static GObject * +e_ui_manager_create_item_for_menu (EUIManager *self, + EUIElement *elem) +{ + EUIMenu *ui_menu; + guint ii; + + g_return_val_if_fail (elem != NULL, NULL); + + ui_menu = e_ui_menu_new (self, e_ui_element_get_id (elem)); + + /* to match the freeze count, because the ui_menu listens for both "freeze" + and "thaw" signals where it will receive only the "thaw" signal without + the corresponding "freeze" signal for this frozen count */ + for (ii = 0; ii < self->frozen; ii++) { + e_ui_menu_freeze (ui_menu); + } + + return G_OBJECT (ui_menu); +} + +/** + * e_ui_manager_create_item: + * @self: an #EUIManager + * @id: an identifier of the toplevel item + * + * Creates a new item corresponding to the identifier @id. This + * is supposed to be part of the @self's #EUIParser on the toplevel, + * thus either a menu, a headerbar or a toolbar. It's an error to ask + * for an item which does not exist. + * + * The returned #GObject is an #EUIMenu (a #GMenuModel descendant) for the menu, + * an #EHeaderBar for the headerbar and a #GtkToolbar for the toolbar. + * + * Returns: (transfer full): a new #GObject for the @id + * + * Since: 3.56 + **/ +GObject * +e_ui_manager_create_item (EUIManager *self, + const gchar *id) +{ + EUIElement *elem; + GObject *object = NULL; + + g_return_val_if_fail (E_IS_UI_MANAGER (self), NULL); + g_return_val_if_fail (id != NULL, NULL); + g_return_val_if_fail (e_ui_parser_get_root (self->parser) != NULL, NULL); + + elem = e_ui_element_get_child_by_id (e_ui_parser_get_root (self->parser), id); + if (!elem) { + g_warning ("%s: Cannot find item with id '%s'", G_STRFUNC, id); + return NULL; + } + + switch (e_ui_element_get_kind (elem)) { + case E_UI_ELEMENT_KIND_HEADERBAR: + object = e_ui_manager_create_item_for_headerbar (self, elem); + break; + case E_UI_ELEMENT_KIND_TOOLBAR: + object = e_ui_manager_create_item_for_toolbar (self, elem); + break; + case E_UI_ELEMENT_KIND_MENU: + object = e_ui_manager_create_item_for_menu (self, elem); + break; + default: + g_warn_if_reached (); + break; + } + + if (GTK_IS_WIDGET (object)) + gtk_widget_set_visible (GTK_WIDGET (object), TRUE); + + return object; +} + +/** + * e_ui_manager_fill_menu: + * @self: an #EUIManager + * @id: a menu ID to fill the @ui_menu with + * @ui_menu: an #EUIMenu to be filled + * + * Fills the @ui_menu with the menu definition with ID @id. + * This is meant to be used by #EUIMenu itself during its rebuild. + * + * Since: 3.56 + **/ +void +e_ui_manager_fill_menu (EUIManager *self, + const gchar *id, + EUIMenu *ui_menu) +{ + EUIElement *elem; + GMenu *section = NULL; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (id != NULL); + g_return_if_fail (E_IS_UI_MENU (ui_menu)); + g_return_if_fail (e_ui_parser_get_root (self->parser) != NULL); + + elem = e_ui_element_get_child_by_id (e_ui_parser_get_root (self->parser), id); + if (!elem) { + g_warning ("%s: Cannot find menu with id '%s'", G_STRFUNC, id); + return; + } + + if (e_ui_element_get_kind (elem) != E_UI_ELEMENT_KIND_MENU) { + g_warning ("%s: Item with ID '%s' is not a menu, it's '%s' instead", G_STRFUNC, + id, e_enum_to_string (E_TYPE_UI_ELEMENT_KIND, e_ui_element_get_kind (elem))); + return; + } + + eum_traverse_menu (self, ui_menu, elem, NULL, e_ui_element_menu_get_is_popup (elem), §ion); + + if (section && g_menu_model_get_n_items (G_MENU_MODEL (section)) > 0) + e_ui_menu_append_section (ui_menu, G_MENU_MODEL (section)); + + g_clear_object (§ion); +} + +static gboolean +e_ui_manager_transform_without_underscores_cb (GBinding *binding, + const GValue *from_value, + GValue *to_value, + gpointer user_data) +{ + const gchar *text = g_value_get_string (from_value); + + if (!text || !strchr (text, '_')) + g_value_set_string (to_value, text); + else + g_value_take_string (to_value, e_str_without_underscores (text)); + + return TRUE; +} + +static void +e_ui_manager_create_named_binding (EUIManager *self, + gboolean strip_underscores, + const gchar *binding_name, + EUIAction *action, + const gchar *action_prop_name, + gpointer item, + const gchar *item_prop_name) +{ + GWeakRef *weakref; + GBinding *binding; + + weakref = g_object_get_data (G_OBJECT (item), binding_name); + binding = weakref ? g_weak_ref_get (weakref) : NULL; + if (binding) { + g_binding_unbind (binding); + g_object_unref (binding); + } + + if (strip_underscores) { + binding = e_binding_bind_property_full (action, action_prop_name, + item, item_prop_name, + G_BINDING_SYNC_CREATE, + e_ui_manager_transform_without_underscores_cb, + NULL, NULL, NULL); + } else { + binding = e_binding_bind_property (action, action_prop_name, + item, item_prop_name, + G_BINDING_SYNC_CREATE); + } + + g_object_set_data_full (G_OBJECT (item), binding_name, e_weak_ref_new (binding), (GDestroyNotify) e_weak_ref_free); +} + +static void +e_ui_manager_synchro_menu_item_attribute (EUIAction *action, + const gchar *prop_name, + GMenuItem *item) +{ + const gchar *value; + + if (g_strcmp0 (prop_name, "label") == 0) { + value = e_ui_action_get_label (action); + g_menu_item_set_label (item, value ? value : ""); + } else if (g_strcmp0 (prop_name, "accel") == 0) { + value = e_ui_action_get_accel (action); + g_menu_item_set_attribute (item, "accel", value ? "s" : NULL, value); + } else { + g_warning ("%s: Unhandled property '%s'", G_STRFUNC, prop_name); + } +} + +static void +e_ui_manager_synchro_menu_item_attribute_cb (EUIAction *action, + GParamSpec *param, + GMenuItem *item) +{ + g_return_if_fail (param != NULL); + + e_ui_manager_synchro_menu_item_attribute (action, param->name, item); +} + +/** + * e_ui_manager_update_item_from_action: + * @self: an #EUIManager + * @item: an item object, its type varies based on the place of use + * @action: an #EUIAction to update the @item with + * + * Updates properties of the @item with the values from the @action. + * The function can handle only #GMenuItem, #GtkToolButton, + * #GtkButton and #EHeaderBarButton descendants. + * + * Passing other than supported types into the function is + * considered a programming error. + * + * Since: 3.56 + **/ +void +e_ui_manager_update_item_from_action (EUIManager *self, + gpointer item, + EUIAction *action) +{ + GAction *gaction; + GVariant *target; + const GVariantType *param_type; + const gchar *value; + gchar *action_name_full; + + g_return_if_fail (E_IS_UI_MANAGER (self)); + g_return_if_fail (E_IS_UI_ACTION (action)); + + if (!item) + return; + + gaction = G_ACTION (action); + value = g_action_get_name (gaction); + param_type = g_action_get_parameter_type (gaction); + target = e_ui_action_ref_target (action); + + action_name_full = g_strconcat (e_ui_action_get_map_name (action), ".", value, NULL); + + if (G_IS_MENU_ITEM (item)) { + g_menu_item_set_action_and_target_value (item, action_name_full, param_type && target ? target : NULL); + + g_signal_handlers_disconnect_by_func (action, G_CALLBACK (e_ui_manager_synchro_menu_item_attribute_cb), item); + + g_signal_connect_object (action, "notify::label", + G_CALLBACK (e_ui_manager_synchro_menu_item_attribute_cb), item, 0); + g_signal_connect_object (action, "notify::accel", + G_CALLBACK (e_ui_manager_synchro_menu_item_attribute_cb), item, 0); + + e_ui_manager_synchro_menu_item_attribute (action, "label", item); + e_ui_manager_synchro_menu_item_attribute (action, "accel", item); + + value = e_ui_action_get_icon_name (action); + if (value) { + if (g_str_has_prefix (value, "gicon::")) { + GIcon *icon; + + icon = e_ui_manager_get_gicon (self, value + 7); + if (icon) + g_menu_item_set_icon (item, icon); + } else { + g_menu_item_set_attribute (item, "icon", "s", value); + } + } + } else if (GTK_IS_TOOL_BUTTON (item)) { + gtk_actionable_set_action_name (GTK_ACTIONABLE (item), action_name_full); + if (param_type && target) + gtk_actionable_set_action_target_value (GTK_ACTIONABLE (item), target); + + gtk_tool_button_set_use_underline (item, TRUE); + + value = e_ui_action_get_icon_name (action); + if (value) { + if (g_str_has_prefix (value, "gicon::")) { + GIcon *icon; + + icon = e_ui_manager_get_gicon (self, value + 7); + if (icon) { + GtkWidget *image; + + image = gtk_image_new_from_gicon (icon, gtk_tool_item_get_icon_size (item)); + gtk_widget_set_visible (image, TRUE); + gtk_tool_button_set_icon_widget (item, image); + } + } else { + gtk_tool_button_set_icon_name (item, value); + } + } + + e_ui_manager_create_named_binding (self, FALSE, "EUIManager::binding:label", + action, "label", + item, "label"); + + e_ui_manager_create_named_binding (self, FALSE, "EUIManager::binding:tooltip", + action, "tooltip", + item, "tooltip-text"); + } else if (GTK_IS_BUTTON (item)) { + gboolean headerbar_parent; + + gtk_actionable_set_action_name (GTK_ACTIONABLE (item), action_name_full); + if (param_type && target) + gtk_actionable_set_action_target_value (GTK_ACTIONABLE (item), target); + + headerbar_parent = E_IS_HEADER_BAR_BUTTON (gtk_widget_get_parent (item)); + + /* mnemonics on the header bar button can steal menu mnemonics */ + gtk_button_set_use_underline (item, !headerbar_parent); + + value = e_ui_action_get_icon_name (action); + if (value) { + GtkWidget *image = NULL; + + if (g_str_has_prefix (value, "gicon::")) { + GIcon *icon; + + icon = e_ui_manager_get_gicon (self, value + 7); + if (icon) + image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON); + } else { + image = gtk_image_new_from_icon_name (value, GTK_ICON_SIZE_BUTTON); + } + + if (image) { + gtk_button_set_image (item, image); + gtk_widget_show (image); + } else { + gtk_button_set_image (item, NULL); + } + } else { + gtk_button_set_image (item, NULL); + } + + e_ui_manager_create_named_binding (self, headerbar_parent, "EUIManager::binding:label", + action, "label", + item, "label"); + + e_ui_manager_create_named_binding (self, FALSE, "EUIManager::binding:tooltip", + action, "tooltip", + item, "tooltip-text"); + } else if (E_IS_HEADER_BAR_BUTTON (item)) { + } else { + g_warning ("%s: Do not know how to update item '%s'", G_STRFUNC, + item ? G_OBJECT_TYPE_NAME (item) : "null"); + } + + if (GTK_IS_WIDGET (item)) { + /* This is called for both labeled and icon-only buttons of the EHeaderBarButton + widget, but those two take care of the correct visibility on their own, + thus do not influence it here. */ + if (!eum_parent_is_header_bar_button (gtk_widget_get_parent (item))) { + e_ui_manager_create_named_binding (self, FALSE, "EUIManager::binding:visible", + action, "is-visible", + item, "visible"); + } + + e_ui_manager_create_named_binding (self, FALSE, "EUIManager::binding:enabled", + action, "enabled", + item, "sensitive"); + } + + g_clear_pointer (&target, g_variant_unref); + g_clear_pointer (&action_name_full, g_free); +} + + +/** + * e_ui_manager_create_item_from_menu_model: + * @self: an #EUIManager + * @elem: (nullable): corresponding #EUIElement, or %NULL + * @action: an #EUIAction + * @for_kind: for which part of the UI the item should be created; it influences the type of the returned item + * @menu_model: (transfer none): a #GMenuModel to use for the created item + * + * Creates a new UI item suitable for the @for_kind, containing the @menu_model. + * For %E_UI_ELEMENT_KIND_MENU returns a submenu #GMenuItem; + * for %E_UI_ELEMENT_KIND_TOOLBAR returns a #GtkMenuToolButton and + * for %E_UI_ELEMENT_KIND_HEADERBAR returns an #EHeaderBarButton. + * + * This might be usually called from #EUIManager 's "create-item" callback. + * + * Returns: (transfer full): a new UI item + * + * Since: 3.56 + **/ +GObject * +e_ui_manager_create_item_from_menu_model (EUIManager *self, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GMenuModel *menu_model) +{ + GObject *item = NULL; + + g_return_val_if_fail (E_IS_UI_MANAGER (self), NULL); + g_return_val_if_fail (E_IS_UI_ACTION (action), NULL); + g_return_val_if_fail (G_IS_MENU_MODEL (menu_model), NULL); + + if (for_kind == E_UI_ELEMENT_KIND_MENU) { + item = G_OBJECT (g_menu_item_new_submenu (e_ui_action_get_label (action), menu_model)); + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + GtkToolItem *tool_item; + GtkWidget *menu; + + menu = gtk_menu_new_from_model (menu_model); + tool_item = gtk_menu_tool_button_new (NULL, e_ui_action_get_label (action)); + gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), menu); + + if (elem) { + e_ui_manager_add_css_classes (self, GTK_WIDGET (tool_item), e_ui_element_item_get_css_classes (elem)); + gtk_tool_item_set_is_important (tool_item, e_ui_element_item_get_important (elem)); + } else { + gtk_tool_item_set_is_important (tool_item, TRUE); + } + + e_ui_manager_update_item_from_action (self, tool_item, action); + e_ui_action_util_assign_to_widget (action, GTK_WIDGET (tool_item)); + + item = G_OBJECT (tool_item); + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + GtkWidget *widget, *menu; + + menu = gtk_menu_new_from_model (menu_model); + + widget = e_header_bar_button_new (e_ui_action_get_label (action), action, self); + + e_header_bar_button_take_menu (E_HEADER_BAR_BUTTON (widget), menu); + + e_binding_bind_property ( + action, "sensitive", + widget, "sensitive", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + action, "visible", + widget, "visible", + G_BINDING_SYNC_CREATE); + + item = G_OBJECT (widget); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, g_action_get_name (G_ACTION (action))); + } + + return item; +} diff --git a/src/e-util/e-ui-manager.h b/src/e-util/e-ui-manager.h new file mode 100644 index 0000000000..0c1c489224 --- /dev/null +++ b/src/e-util/e-ui-manager.h @@ -0,0 +1,97 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) +#error "Only should be included directly." +#endif + +#ifndef E_UI_MANAGER_H +#define E_UI_MANAGER_H + +#include + +#include +#include +#include +#include + +G_BEGIN_DECLS + +struct _EUIMenu; + +#define E_TYPE_UI_MANAGER e_ui_manager_get_type () + +G_DECLARE_FINAL_TYPE (EUIManager, e_ui_manager, E, UI_MANAGER, GObject) + +EUIManager * e_ui_manager_new (void); +EUIParser * e_ui_manager_get_parser (EUIManager *self); +GtkAccelGroup * e_ui_manager_get_accel_group (EUIManager *self); +void e_ui_manager_freeze (EUIManager *self); +void e_ui_manager_thaw (EUIManager *self); +gboolean e_ui_manager_is_frozen (EUIManager *self); +void e_ui_manager_add_actions (EUIManager *self, + const gchar *group_name, + const gchar *translation_domain, + const EUIActionEntry *entries, + gint n_entries, + gpointer user_data); +void e_ui_manager_add_actions_enum (EUIManager *self, + const gchar *group_name, + const gchar *translation_domain, + const EUIActionEnumEntry *entries, + gint n_entries, + gpointer user_data); +void e_ui_manager_add_action (EUIManager *self, + const gchar *group_name, + EUIAction *action, + EUIActionFunc activate, + EUIActionFunc change_state, + gpointer user_data); +void e_ui_manager_add_actions_with_eui_data + (EUIManager *self, + const gchar *group_name, + const gchar *translation_domain, + const EUIActionEntry *entries, + gint n_entries, + gpointer user_data, + const gchar *eui); +void e_ui_manager_add_action_groups_to_widget + (EUIManager *self, + GtkWidget *widget); +void e_ui_manager_set_action_groups_widget + (EUIManager *self, + GtkWidget *widget); +GtkWidget * e_ui_manager_ref_action_groups_widget + (EUIManager *self); +gboolean e_ui_manager_has_action_group (EUIManager *self, + const gchar *name); +EUIActionGroup *e_ui_manager_get_action_group (EUIManager *self, + const gchar *name); +void e_ui_manager_add_action_group (EUIManager *self, + EUIActionGroup *action_group); +EUIAction * e_ui_manager_get_action (EUIManager *self, + const gchar *name); +GIcon * e_ui_manager_get_gicon (EUIManager *self, + const gchar *name); +GObject * e_ui_manager_create_item (EUIManager *self, + const gchar *id); +void e_ui_manager_fill_menu (EUIManager *self, + const gchar *id, + struct _EUIMenu *ui_menu); +void e_ui_manager_update_item_from_action + (EUIManager *self, + gpointer item, + EUIAction *action); +GObject * e_ui_manager_create_item_from_menu_model + (EUIManager *self, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GMenuModel *menu_model); + +G_END_DECLS + +#endif /* E_UI_MANAGER_H */ diff --git a/src/e-util/e-ui-menu.c b/src/e-util/e-ui-menu.c new file mode 100644 index 0000000000..4ee3070e99 --- /dev/null +++ b/src/e-util/e-ui-menu.c @@ -0,0 +1,517 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "evolution-config.h" + +#include + +#include "e-ui-action.h" +#include "e-ui-manager.h" + +#include "e-ui-menu.h" + +/** + * SECTION: e-ui-menu + * @include: e-util/e-util.h + * @short_description: a UI menu + * + * #EUIMenu is a #GMenuModel descendant, which takes care of an #EUIAction + * visibility and regenerates its content when any of the actions hides/shows + * itself or when the associated #EUIManager changes. + * + * The object is not thread-safe, it's meant to be used only from + * the main/GUI thread. + * + * Since: 3.56 + **/ + +struct _EUIMenu { + GMenuModel parent; + + GHashTable *tracked_actions; /* EUIAction * ~> NULL */ + GMenu *real_menu; + EUIManager *manager; + gchar *id; + + guint frozen; + gboolean changed_while_frozen; +}; + +G_DEFINE_TYPE (EUIMenu, e_ui_menu, G_TYPE_MENU_MODEL) + +enum { + PROP_0, + PROP_MANAGER, + PROP_ID, + N_PROPS +}; + +static GParamSpec *properties[N_PROPS] = { NULL, }; + +static void +e_ui_menu_thaw_internal (EUIMenu *self) +{ + g_return_if_fail (E_IS_UI_MENU (self)); + g_return_if_fail (self->frozen > 0); + + self->frozen--; + + if (!self->frozen && self->changed_while_frozen) { + self->changed_while_frozen = FALSE; + + e_ui_menu_rebuild (self); + } +} + +static void +e_ui_menu_manager_freeze_cb (EUIManager *manager, + gpointer user_data) +{ + EUIMenu *self = user_data; + + e_ui_menu_freeze (self); +} + +static void +e_ui_menu_manager_thaw_cb (EUIManager *manager, + gboolean changed_while_frozen, + gpointer user_data) +{ + EUIMenu *self = user_data; + + self->changed_while_frozen = self->changed_while_frozen || changed_while_frozen; + + e_ui_menu_thaw_internal (self); +} + +static void +e_ui_menu_items_changed_cb (GMenuModel *parent, + gint position, + gint removed, + gint added, + gpointer user_data) +{ + EUIMenu *self = user_data; + + g_menu_model_items_changed (G_MENU_MODEL (self), position, removed, added); +} + +static gboolean +e_ui_menu_is_mutable (GMenuModel *self) +{ + return TRUE; +} + +static gint +e_ui_menu_get_n_items (GMenuModel *model) +{ + EUIMenu *self = E_UI_MENU (model); + + return g_menu_model_get_n_items (G_MENU_MODEL (self->real_menu)); +} + +static void +e_ui_menu_get_item_attributes (GMenuModel *model, + gint position, + GHashTable **table) +{ + EUIMenu *self = E_UI_MENU (model); + GMenuModelClass *klass; + + klass = G_MENU_MODEL_GET_CLASS (self->real_menu); + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->get_item_attributes != NULL); + + klass->get_item_attributes (G_MENU_MODEL (self->real_menu), position, table); +} + +static void +e_ui_menu_get_item_links (GMenuModel *model, + gint position, + GHashTable **table) +{ + EUIMenu *self = E_UI_MENU (model); + GMenuModelClass *klass; + + klass = G_MENU_MODEL_GET_CLASS (self->real_menu); + g_return_if_fail (klass != NULL); + g_return_if_fail (klass->get_item_links != NULL); + + klass->get_item_links (G_MENU_MODEL (self->real_menu), position, table); +} + +static void +e_ui_menu_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EUIMenu *self = E_UI_MENU (object); + + switch (prop_id) { + case PROP_MANAGER: + g_clear_object (&self->manager); + self->manager = g_value_dup_object (value); + break; + case PROP_ID: + g_free (self->id); + self->id = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +e_ui_menu_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EUIMenu *self = E_UI_MENU (object); + + switch (prop_id) { + case PROP_MANAGER: + g_value_set_object (value, e_ui_menu_get_manager (self)); + break; + case PROP_ID: + g_value_set_string (value, e_ui_menu_get_id (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +e_ui_menu_constructed (GObject *object) +{ + EUIMenu *self = E_UI_MENU (object); + + G_OBJECT_CLASS (e_ui_menu_parent_class)->constructed (object); + + g_return_if_fail (self->manager != NULL); + g_return_if_fail (self->id != NULL); + + e_ui_menu_rebuild (self); + + g_signal_connect_object (self->manager, "changed", + G_CALLBACK (e_ui_menu_rebuild), self, G_CONNECT_SWAPPED); + g_signal_connect_object (self->manager, "freeze", + G_CALLBACK (e_ui_menu_manager_freeze_cb), self, 0); + g_signal_connect_object (self->manager, "thaw", + G_CALLBACK (e_ui_menu_manager_thaw_cb), self, 0); +} + +static void +e_ui_menu_finalize (GObject *object) +{ + EUIMenu *self = E_UI_MENU (object); + + e_ui_menu_remove_all (self); + + g_clear_pointer (&self->tracked_actions, g_hash_table_unref); + g_clear_pointer (&self->id, g_free); + g_clear_object (&self->real_menu); + g_clear_object (&self->manager); + + G_OBJECT_CLASS (e_ui_menu_parent_class)->finalize (object); +} + +static void +e_ui_menu_class_init (EUIMenuClass *klass) +{ + GObjectClass *object_class; + GMenuModelClass *model_class; + + model_class = G_MENU_MODEL_CLASS (klass); + model_class->is_mutable = e_ui_menu_is_mutable; + model_class->get_n_items = e_ui_menu_get_n_items; + model_class->get_item_attributes = e_ui_menu_get_item_attributes; + model_class->get_item_links = e_ui_menu_get_item_links; + + object_class = G_OBJECT_CLASS (klass); + object_class->set_property = e_ui_menu_set_property; + object_class->get_property = e_ui_menu_get_property; + object_class->constructed = e_ui_menu_constructed; + object_class->finalize = e_ui_menu_finalize; + + /** + * EUIMenu:manager: + * + * An #EUIManager associated with the menu. + * + * Since: 3.56 + **/ + properties[PROP_MANAGER] = g_param_spec_object ("manager", NULL, NULL, + E_TYPE_UI_MANAGER, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * EUIMenu:id: + * + * Identifier of the menu to be read from the #EUIManager. + * + * Since: 3.56 + **/ + properties[PROP_ID] = g_param_spec_string ("id", NULL, NULL, NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties); +} + +static void +e_ui_menu_init (EUIMenu *self) +{ + self->tracked_actions = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); + self->real_menu = g_menu_new (); + + g_signal_connect_object (self->real_menu, "items-changed", + G_CALLBACK (e_ui_menu_items_changed_cb), self, 0); +} + +/** + * e_ui_menu_new: + * @manager: an *EUIManager + * @id: a menu identifier to use the created #EUIMenu with + * + * Creates a new #EUIMenu, which will use the @manager to get + * its content from under identifier @id. + * + * Returns: (transfer full): a new #EUIMenu + * + * Since: 3.56 + **/ +EUIMenu * +e_ui_menu_new (EUIManager *manager, + const gchar *id) +{ + return g_object_new (E_TYPE_UI_MENU, + "manager", manager, + "id", id, + NULL); +} + +/** + * e_ui_menu_get_manager: + * @self: an #EUIMenu + * + * Gets an associated #EUIManager. + * + * Returns: (transfer none): an associated #EUIManager + * + * Since: 3.56 + **/ +EUIManager * +e_ui_menu_get_manager (EUIMenu *self) +{ + g_return_val_if_fail (E_IS_UI_MENU (self), NULL); + + return self->manager; +} + +/** + * e_ui_menu_get_id: + * @self: an #EUIMenu + * + * Gets an identifier of the menu to populate the @self with. + * + * Returns: a menu identifier + * + * Since: 3.56 + **/ +const gchar * +e_ui_menu_get_id (EUIMenu *self) +{ + g_return_val_if_fail (E_IS_UI_MENU (self), NULL); + + return self->id; +} + +/** + * e_ui_menu_append_item: + * @self: an #EUIMenu + * @action: (nullable): an #EUIAction, or %NULL + * @item: a #GMenuItem to append + * + * Appends a #GMenuItem descendant @item into the menu, which can + * be related to the @action. When the @action is not %NULL, its + * state is tracked and the menu is regenerated whenever the state + * changed (and when needed). + * + * Since: 3.56 + **/ +void +e_ui_menu_append_item (EUIMenu *self, + EUIAction *action, + GMenuItem *item) +{ + g_return_if_fail (E_IS_UI_MENU (self)); + g_return_if_fail (G_IS_MENU_ITEM (item)); + + if (action) + e_ui_menu_track_action (self, action); + + g_menu_append_item (self->real_menu, item); +} + +/** + * e_ui_menu_append_section: + * @self: an #EUIMenu + * @section: a #GMenuModel + * + * Appends a #GMenuModel as a new section in the @self. + * + * Since: 3.56 + **/ +void +e_ui_menu_append_section (EUIMenu *self, + GMenuModel *section) +{ + g_return_if_fail (E_IS_UI_MENU (self)); + g_return_if_fail (G_IS_MENU_MODEL (section)); + + g_menu_append_section (self->real_menu, NULL, section); +} + +/** + * e_ui_menu_track_action: + * @self: an #EUIMenu + * @action: (not nullable): an #EUIAction + * + * Tracks a state change of the @action and regenerates the menu + * content when needed. + * + * Since: 3.56 + **/ +void +e_ui_menu_track_action (EUIMenu *self, + EUIAction *action) +{ + g_return_if_fail (E_IS_UI_MENU (self)); + g_return_if_fail (E_IS_UI_ACTION (action)); + + if (!g_hash_table_contains (self->tracked_actions, action)) { + g_signal_connect_swapped (action, "notify::is-visible", G_CALLBACK (e_ui_menu_rebuild), self); + g_signal_connect_swapped (action, "changed", G_CALLBACK (e_ui_menu_rebuild), self); + g_hash_table_add (self->tracked_actions, g_object_ref (action)); + } +} + +/** + * e_ui_menu_freeze: + * @self: an #EUIMenu + * + * Freezes rebuild of the menu content. Useful when filling the content. + * The function can be called multiple times, only each call needs + * a pair call of the e_ui_menu_thaw() to revert the effect of this function. + * + * Since: 3.56 + **/ +void +e_ui_menu_freeze (EUIMenu *self) +{ + g_return_if_fail (E_IS_UI_MENU (self)); + g_return_if_fail (self->frozen + 1 > self->frozen); + + self->frozen++; +} + +/** + * e_ui_menu_thaw: + * @self: an #EUIMenu + * + * Pair function for the e_ui_menu_freeze(). It's a programming + * error to thaw a menu, which is not frozen. + * + * Since: 3.56 + **/ +void +e_ui_menu_thaw (EUIMenu *self) +{ + g_return_if_fail (E_IS_UI_MENU (self)); + g_return_if_fail (self->frozen > 0); + + e_ui_menu_thaw_internal (self); +} + +/** + * e_ui_menu_is_frozen: + * @self: an #EUIMenu + * + * Gets whether the @self is frozen for rebuild. It can be frozen with + * the e_ui_menu_freeze() and unfrozen with the e_ui_menu_thaw(). + * + * Returns: whether rebuild of the @self is frozen + * + * Since: 3.56 + **/ +gboolean +e_ui_menu_is_frozen (EUIMenu *self) +{ + g_return_val_if_fail (E_IS_UI_MENU (self), FALSE); + + return self->frozen > 0; +} + +/** + * e_ui_menu_rebuild: + * @self: an #EUIMenu + * + * Rebuilds the @self content. If the rebuild is frozen (see e_ui_menu_freeze()), + * the rebuild is postponed until the rebuild is allowed again. + * + * Since: 3.56 + **/ +void +e_ui_menu_rebuild (EUIMenu *self) +{ + g_return_if_fail (E_IS_UI_MENU (self)); + + if (self->frozen) { + self->changed_while_frozen = TRUE; + return; + } + + e_ui_menu_remove_all (self); + e_ui_manager_fill_menu (self->manager, self->id, self); +} + +/** + * e_ui_menu_remove_all: + * @self: an #EUIMenu + * + * Cleans up content of the @self, including tracked actions + * and all the menu items. + * + * Since: 3.56 + **/ +void +e_ui_menu_remove_all (EUIMenu *self) +{ + GHashTableIter iter; + gpointer key; + + g_return_if_fail (E_IS_UI_MENU (self)); + + g_menu_remove_all (self->real_menu); + + g_hash_table_iter_init (&iter, self->tracked_actions); + while (g_hash_table_iter_next (&iter, &key, NULL)) { + EUIAction *action = key; + + g_signal_handlers_disconnect_by_func (action, G_CALLBACK (e_ui_menu_rebuild), self); + } + + g_hash_table_remove_all (self->tracked_actions); +} diff --git a/src/e-util/e-ui-menu.h b/src/e-util/e-ui-menu.h new file mode 100644 index 0000000000..0e020fed6c --- /dev/null +++ b/src/e-util/e-ui-menu.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) +#error "Only should be included directly." +#endif + +#ifndef E_UI_MENU_H +#define E_UI_MENU_H + +#include + +#include +#include + +G_BEGIN_DECLS + +#define E_TYPE_UI_MENU e_ui_menu_get_type () + +G_DECLARE_FINAL_TYPE (EUIMenu, e_ui_menu, E, UI_MENU, GMenuModel) + +EUIMenu * e_ui_menu_new (EUIManager *manager, + const gchar *id); +EUIManager * e_ui_menu_get_manager (EUIMenu *self); +const gchar * e_ui_menu_get_id (EUIMenu *self); +void e_ui_menu_append_item (EUIMenu *self, + EUIAction *action, + GMenuItem *item); +void e_ui_menu_append_section (EUIMenu *self, + GMenuModel *section); +void e_ui_menu_track_action (EUIMenu *self, + EUIAction *action); +void e_ui_menu_freeze (EUIMenu *self); +void e_ui_menu_thaw (EUIMenu *self); +gboolean e_ui_menu_is_frozen (EUIMenu *self); +void e_ui_menu_rebuild (EUIMenu *self); +void e_ui_menu_remove_all (EUIMenu *self); + +G_END_DECLS + +#endif /* E_UI_MENU_H */ diff --git a/src/e-util/e-ui-parser.c b/src/e-util/e-ui-parser.c new file mode 100644 index 0000000000..275aecbc2c --- /dev/null +++ b/src/e-util/e-ui-parser.c @@ -0,0 +1,1469 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "evolution-config.h" + +#include +#include + +#include "e-misc-utils.h" +#include "e-util-enums.h" + +#include "e-ui-parser.h" + +/** + * SECTION: e-ui-parser + * @include: e-util/e-util.h + * @short_description: a UI definition parser + * + * #EUIParser parses UI definitions for menus, headerbar and toolbar from an XML data. + * It's associated with an #EUIManager. + * + * The object is not thread-safe, it's meant to be used only from + * the main/GUI thread. + * + * Since: 3.56 + **/ + +/* + Example: + + + + + + + + + + + + + + + + " + " + " + " + " + " + " + " + " + + + + + + + + + + + + + + + + + + + + +*/ + +static const gchar * +e_ui_element_kind_to_string (EUIElementKind kind) +{ + switch (kind) { + case E_UI_ELEMENT_KIND_UNKNOWN: + return "unknown"; + case E_UI_ELEMENT_KIND_ROOT: + return "eui"; + case E_UI_ELEMENT_KIND_HEADERBAR: + return "headerbar"; + case E_UI_ELEMENT_KIND_TOOLBAR: + return "toolbar"; + case E_UI_ELEMENT_KIND_MENU: + return "menu"; + case E_UI_ELEMENT_KIND_SUBMENU: + return "submenu"; + case E_UI_ELEMENT_KIND_PLACEHOLDER: + return "placeholder"; + case E_UI_ELEMENT_KIND_SEPARATOR: + return "separator"; + case E_UI_ELEMENT_KIND_START: + return "start"; + case E_UI_ELEMENT_KIND_END: + return "end"; + case E_UI_ELEMENT_KIND_ITEM: + return "item"; + } + + return "???"; +} + +struct _EUIElement { + EUIElementKind kind; + gchar *id; + GPtrArray *children; + union { + /* menu properties */ + struct _menu { + gboolean is_popup; + } menu; + + /* submenu properties */ + struct _submenu { + gchar *action; + } submenu; + + /* headerbar properties */ + struct _headerbar { + gboolean use_gtk_type; + } headerbar; + + /* toolbar properties */ + struct _toolbar { + gboolean primary; + } toolbar; + + /* item properties */ + struct _item { + guint label_priority; + gint order; + gint icon_only; + gint text_only; + gboolean important; + gchar *css_classes; + gchar *action; + gchar *group; + } item; + } data; +}; + +static EUIElement * +e_ui_element_new (EUIElementKind kind, + const gchar *id) +{ + EUIElement *self; + + self = g_new0 (EUIElement, 1); + self->kind = kind; + self->id = g_strdup (id); + + if (kind == E_UI_ELEMENT_KIND_ITEM) { + self->data.item.label_priority = G_MAXUINT32; + self->data.item.order = 0; + self->data.item.icon_only = G_MAXINT32; + self->data.item.text_only = G_MAXINT32; + self->data.item.important = FALSE; + } + + return self; +} + +static void +e_ui_element_free (EUIElement *self) +{ + if (!self) + return; + + g_clear_pointer (&self->id, g_free); + g_clear_pointer (&self->children, g_ptr_array_unref); + + if (self->kind == E_UI_ELEMENT_KIND_SUBMENU) { + g_clear_pointer (&self->data.submenu.action, g_free); + } else if (self->kind == E_UI_ELEMENT_KIND_ITEM) { + g_clear_pointer (&self->data.item.css_classes, g_free); + g_clear_pointer (&self->data.item.action, g_free); + g_clear_pointer (&self->data.item.group, g_free); + } + + g_free (self); +} + +static void +e_ui_element_add_child (EUIElement *parent, + EUIElement *child /* (transfer full) */) +{ + g_return_if_fail (parent != NULL); + g_return_if_fail (child != NULL); + + if (!parent->children) + parent->children = g_ptr_array_new_with_free_func ((GDestroyNotify) e_ui_element_free); + + g_ptr_array_add (parent->children, child); +} + +/** + * e_ui_element_get_kind: + * @self: an #EUIElement + * + * Gets the kind of the @self. + * + * Returns: an #EUIElementKind of the @self + * + * Since: 3.56 + **/ +EUIElementKind +e_ui_element_get_kind (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, E_UI_ELEMENT_KIND_UNKNOWN); + return self->kind; +} + +/** + * e_ui_element_get_id: + * @self: an #EUIElement + * + * Gets the identifier of the @self. + * + * Returns: (nullable): an identifier of the @self + * + * Since: 3.56 + **/ +const gchar * +e_ui_element_get_id (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, NULL); + return self->id; +} + +/** + * e_ui_element_get_n_children: + * @self: an #EUIElement + * + * Gets how many children the element has. + * + * Returns: count of children of the @self + * + * Since: 3.56 + **/ +guint +e_ui_element_get_n_children (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, 0); + return self->children ? self->children->len : 0; +} + +/** + * e_ui_element_get_child: + * @self: an #EUIElement + * @index: an index of the child to get + * + * Gets a child at @index, which should be less + * than e_ui_element_get_n_children(). + * + * Returns: (transfer none) (nullable): a child element at index @index, + * or %NULL, when @index is out of bounds + * + * Since: 3.56 + **/ +EUIElement * +e_ui_element_get_child (EUIElement *self, + guint index) +{ + g_return_val_if_fail (self != NULL, NULL); + + if (!self->children || index >= self->children->len) + return NULL; + + return g_ptr_array_index (self->children, index); +} + +/** + * e_ui_element_get_child_by_id: + * @self: an #EUIElement + * @id: an identified of the child to get + * + * Gets a child by its identifier. It searches the direct + * children of the @self only. + * + * Returns: (transfer none) (nullable): a child element with identifier @id, + * or %NULL, when not found + * + * Since: 3.56 + **/ +EUIElement * +e_ui_element_get_child_by_id (EUIElement *self, + const gchar *id) +{ + guint ii; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (id != NULL, NULL); + + for (ii = 0; self->children && ii < self->children->len; ii++) { + EUIElement *adept = g_ptr_array_index (self->children, ii); + + if (g_strcmp0 (adept->id, id) == 0) + return adept; + } + + return NULL; +} + +static void +e_ui_element_export (const EUIElement *self, + GString *str, + gint indent) +{ + if (!self) + return; + + if (indent >= 0) + g_string_append_printf (str, "%*s", indent * 2, ""); + + g_string_append_printf (str, "<%s", e_ui_element_kind_to_string (self->kind)); + + if (self->id) + e_util_markup_append_escaped (str, " id='%s'", self->id); + + if (self->kind == E_UI_ELEMENT_KIND_MENU) { + if (self->data.menu.is_popup) + g_string_append (str, " is-popup='true'"); + } else if (self->kind == E_UI_ELEMENT_KIND_SUBMENU) { + if (self->data.submenu.action) + e_util_markup_append_escaped (str, " action='%s'", self->data.submenu.action); + } else if (self->kind == E_UI_ELEMENT_KIND_HEADERBAR) { + if (self->data.headerbar.use_gtk_type) + g_string_append (str, " type='gtk'"); + } else if (self->kind == E_UI_ELEMENT_KIND_TOOLBAR) { + if (self->data.toolbar.primary) + g_string_append (str, " primary='true'"); + } else if (self->kind == E_UI_ELEMENT_KIND_ITEM) { + if (self->data.item.action) + e_util_markup_append_escaped (str, " action='%s'", self->data.item.action); + if (self->data.item.group) + e_util_markup_append_escaped (str, " group='%s'", self->data.item.group); + if (self->data.item.label_priority != G_MAXUINT32) + g_string_append_printf (str, " label_priority='%u'", self->data.item.label_priority); + if (self->data.item.icon_only != G_MAXINT32) + g_string_append_printf (str, " icon_only='%s'", self->data.item.icon_only ? "true" : "false"); + if (self->data.item.text_only != G_MAXINT32) + g_string_append_printf (str, " text_only='%s'", self->data.item.text_only ? "true" : "false"); + if (self->data.item.important) + g_string_append (str, " important='true'"); + if (self->data.item.css_classes) + g_string_append_printf (str, " css_classes='%s'", self->data.item.css_classes); + if (self->data.item.order) + g_string_append_printf (str, " order='%d'", self->data.item.order); + } + + if (self->children) { + guint ii; + + g_string_append_c (str, '>'); + + if (indent >= 0) + g_string_append_c (str, '\n'); + + for (ii = 0; ii < self->children->len; ii++) { + const EUIElement *subelem = g_ptr_array_index (self->children, ii); + e_ui_element_export (subelem, str, indent >= 0 ? indent + 1 : indent); + } + + if (indent >= 0) + g_string_append_printf (str, "%*s", indent * 2, ""); + + g_string_append_printf (str, "", e_ui_element_kind_to_string (self->kind)); + } else { + g_string_append (str, "/>"); + } + + if (indent >= 0) + g_string_append_c (str, '\n'); +} + +/* menu element functions */ + +/** + * e_ui_element_menu_get_is_popup: + * @self: an #EUIElement + * + * Gets a whether a menu is a popup (context) menu. Such menu hides actions + * when they are insensitive. The default value is %FALSE. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_MENU. + * + * Returns: whether the menu is a popup menu + * + * Since: 3.56 + **/ +gboolean +e_ui_element_menu_get_is_popup (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_MENU, FALSE); + + return self->data.menu.is_popup; +} + +/* submenu element functions */ + +/** + * e_ui_element_submenu_get_action: + * @self: an #EUIElement + * + * Gets a submenu action name. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_SUBMENU. + * + * Returns: an action name for the submenu element + * + * Since: 3.56 + **/ +const gchar * +e_ui_element_submenu_get_action (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_SUBMENU, NULL); + + return self->data.submenu.action; +} + +/* headerbar element functions */ + +/** + * e_ui_element_headerbar_get_use_gtk_type: + * @self: an #EUIElement + * + * Gets whether a #GtkHeaderBar should be created, instead of an #EHeaderBar. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_HEADERBAR. + * + * Returns: whether create #GtkHeaderBar + * + * Since: 3.56 + **/ +gboolean +e_ui_element_headerbar_get_use_gtk_type (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_HEADERBAR, FALSE); + + return self->data.headerbar.use_gtk_type; +} + +/* toolbar element functions */ + +/** + * e_ui_element_toolbar_get_primary: + * @self: an #EUIElement + * + * Gets whether the toolbar is a primary toolbar. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_TOOLBAR. + * + * Returns: whether the toolbar is a primary toolbar + * + * Since: 3.56 + **/ +gboolean +e_ui_element_toolbar_get_primary (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_TOOLBAR, FALSE); + + return self->data.toolbar.primary; +} + +/* item element functions */ + +/** + * e_ui_element_item_get_label_priority: + * @self: an #EUIElement + * + * Gets a label priority value for an item element. It is set only + * for headerbar items. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: a label priority + * + * Since: 3.56 + **/ +guint +e_ui_element_item_get_label_priority (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, 0); + + return self->data.item.label_priority; +} + +/** + * e_ui_element_item_get_order: + * @self: an #EUIElement + * + * Gets order of the button in the header bar. Items with lower number + * are added before items with higher number. The default value is zero, + * meaning use the order as added through the .eui file. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: order index of the header bar item + * + * Since: 3.56 + **/ +gint +e_ui_element_item_get_order (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, 0); + + return self->data.item.order; +} + +/** + * e_ui_element_item_get_icon_only_is_set: + * @self: an #EUIElement + * + * Gets whether an item has set icon-only property. The default value is %FALSE. + * It is set only for headerbar items. Use e_ui_element_item_get_icon_only() + * to get the actual value. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: whether the icon-only property is set + * + * Since: 3.56 + **/ +gboolean +e_ui_element_item_get_icon_only_is_set (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, FALSE); + + return self->data.item.icon_only != G_MAXINT32; +} + +/** + * e_ui_element_item_get_icon_only: + * @self: an #EUIElement + * + * Gets whether an item may show only icon. The default value is %FALSE. + * It is set only for headerbar items. Use e_ui_element_item_get_icon_only_is_set() + * to check whether the value had been set. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: whether to show only icon + * + * Since: 3.56 + **/ +gboolean +e_ui_element_item_get_icon_only (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, FALSE); + + if (!e_ui_element_item_get_icon_only_is_set (self)) + return FALSE; + + return self->data.item.icon_only != 0; +} + +/** + * e_ui_element_item_get_text_only_is_set: + * @self: an #EUIElement + * + * Gets whether an item has set text-only property. The default value is %FALSE. + * Use e_ui_element_item_get_text_only() to get the actual value. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: whether the text-only property is set + * + * Since: 3.56 + **/ +gboolean +e_ui_element_item_get_text_only_is_set (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, FALSE); + + return self->data.item.text_only != G_MAXINT32; +} + +/** + * e_ui_element_item_get_text_only: + * @self: an #EUIElement + * + * Gets whether an item may show only text. The default value is %FALSE. + * Use e_ui_element_item_get_text_only_is_set() + * to check whether the value had been set. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: whether to show only text + * + * Since: 3.56 + **/ +gboolean +e_ui_element_item_get_text_only (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, FALSE); + + if (!e_ui_element_item_get_text_only_is_set (self)) + return FALSE; + + return self->data.item.text_only != 0; +} + +/** + * e_ui_element_item_get_important: + * @self: an #EUIElement + * + * Gets whether an item is important. The default value is %FALSE. + * It's used for items inside toolbars. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: whether the item is important + * + * Since: 3.56 + **/ +gboolean +e_ui_element_item_get_important (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, FALSE); + + return self->data.item.important; +} + +/** + * e_ui_element_item_get_css_classes: + * @self: an #EUIElement + * + * Gets a space-separated list of CSS classes to add on the item. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: (nullable): a space-separated list of CSS classes to add on a GtkWidget, + * or %NULL, when not set + * + * Since: 3.56 + **/ +const gchar * +e_ui_element_item_get_css_classes (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, NULL); + + return self->data.item.css_classes; +} + +/** + * e_ui_element_item_get_action: + * @self: an #EUIElement + * + * Gets a item action name. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: an action name + * + * Since: 3.56 + **/ +const gchar * +e_ui_element_item_get_action (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, NULL); + + return self->data.item.action; +} + +/** + * e_ui_element_item_get_group: + * @self: an #EUIElement + * + * Gets a radio group name. + * + * This can be called only on elements of kind %E_UI_ELEMENT_KIND_ITEM. + * + * Returns: (nullable): a radio group name of an item, or %NULL, + * when the item is not part of any radio group + * + * Since: 3.56 + **/ +const gchar * +e_ui_element_item_get_group (const EUIElement *self) +{ + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (self->kind == E_UI_ELEMENT_KIND_ITEM, NULL); + + return self->data.item.group; +} + +/* ***************************************************************** */ + +struct _EUIParser { + GObject parent; + + EUIElement *root; +}; + +enum { + SIGNAL_CHANGED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0, }; + +G_DEFINE_TYPE (EUIParser, e_ui_parser, G_TYPE_OBJECT) + +static void +e_ui_parser_finalize (GObject *object) +{ + EUIParser *self = E_UI_PARSER (object); + + g_clear_pointer (&self->root, e_ui_element_free); + + G_OBJECT_CLASS (e_ui_parser_parent_class)->finalize (object); +} + +static void +e_ui_parser_class_init (EUIParserClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = e_ui_parser_finalize; + + /** + * EUIParser::changed: + * @parser: an #EUIParser + * + * Emitted when the content of the @parser changes. + * + * Since: 3.56 + **/ + signals[SIGNAL_CHANGED] = g_signal_new ("changed", + E_TYPE_UI_PARSER, + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0, + G_TYPE_NONE); +} + +static void +e_ui_parser_init (EUIParser *self) +{ +} + +/** + * e_ui_parser_new: + * + * Creates a new #EUIParser. Use g_object_unref() to free it, when no longer needed. + * + * Returns: (transfer full): a new #EUIParser + * + * Since: 3.56 + **/ +EUIParser * +e_ui_parser_new (void) +{ + return g_object_new (E_TYPE_UI_PARSER, NULL); +} + +/** + * e_ui_parser_merge_file: + * @self: an #EUIParser + * @filename: a filename to merge + * @error: an output location to store a #GError at, or %NULL + * + * Adds content of the @filename into the UI definition. Items with + * the same identifier are reused, allowing to add new items into + * existing hierarchy. + * + * Returns: whether could successfully parse the file content. On failure, + * the @error is set. + * + * Since: 3.56 + **/ +gboolean +e_ui_parser_merge_file (EUIParser *self, + const gchar *filename, + GError **error) +{ + gchar *full_filename = NULL; + gchar *content = NULL; + gsize content_len = 0; + gboolean success; + + g_return_val_if_fail (E_IS_UI_PARSER (self), FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + + if (!strchr (filename, G_DIR_SEPARATOR)) + full_filename = g_build_filename (EVOLUTION_UIDIR, filename, NULL); + + success = g_file_get_contents (full_filename ? full_filename : filename, &content, &content_len, error); + + g_free (full_filename); + + if (!success) + return FALSE; + + success = e_ui_parser_merge_data (self, content, content_len, error); + + g_free (content); + + return success; +} + +static EUIElement * /* (transfer full) */ +ui_parser_xml_read_item_element (const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gboolean for_headerbar, + gboolean for_menu, + GError **error) +{ + EUIElement *ui_elem; + const gchar *action = NULL; + const gchar *group = NULL; + const gchar *label_priority = NULL; + const gchar *icon_only = NULL; + const gchar *text_only = NULL; + const gchar *important = NULL; + const gchar *css_classes = NULL; + const gchar *order = NULL; + gint order_index = 0; + + if (for_headerbar) { + if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, + G_MARKUP_COLLECT_STRING, "action", &action, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "group", &group, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "css_classes", &css_classes, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "label_priority", &label_priority, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "icon_only", &icon_only, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "order", &order, + G_MARKUP_COLLECT_INVALID)) + return NULL; + + if (order && *order) { + gchar *endptr = NULL; + + order_index = (gint) g_ascii_strtoll (order, &endptr, 10); + if (!order_index && endptr == order) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Element <%s> can have optional 'order' attribute of type integer, but the value '%s' is not a valid integer", element_name, order); + return NULL; + } + } else { + order = NULL; + } + } else if (for_menu) { + if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, + G_MARKUP_COLLECT_STRING, "action", &action, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "group", &group, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "css_classes", &css_classes, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "text_only", &text_only, + G_MARKUP_COLLECT_INVALID)) + return NULL; + } else { + if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, + G_MARKUP_COLLECT_STRING, "action", &action, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "group", &group, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "css_classes", &css_classes, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "important", &important, + G_MARKUP_COLLECT_INVALID)) + return NULL; + } + + if (icon_only && *icon_only && + g_strcmp0 (icon_only, "true") != 0 && + g_strcmp0 (icon_only, "false") != 0) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "The 'icon-only' expects only 'true' or 'false' value, but '%s' was provided instead", icon_only); + return NULL; + } + + if (text_only && *text_only && + g_strcmp0 (text_only, "true") != 0 && + g_strcmp0 (text_only, "false") != 0) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "The 'text-only' expects only 'true' or 'false' value, but '%s' was provided instead", text_only); + return NULL; + } + + if (important && *important && + g_strcmp0 (important, "true") != 0 && + g_strcmp0 (important, "false") != 0) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "The 'important' expects only 'true' or 'false' value, but '%s' was provided instead", important); + return NULL; + } + + ui_elem = e_ui_element_new (E_UI_ELEMENT_KIND_ITEM, NULL); + ui_elem->data.item.css_classes = e_util_strdup_strip (css_classes); + ui_elem->data.item.action = e_util_strdup_strip (action); + ui_elem->data.item.group = e_util_strdup_strip (group); + ui_elem->data.item.important = g_strcmp0 (important, "true") == 0; + + if (icon_only && *icon_only) + ui_elem->data.item.icon_only = g_strcmp0 (icon_only, "true") == 0 ? 1 : 0; + + if (text_only && *text_only) + ui_elem->data.item.text_only = g_strcmp0 (text_only, "true") == 0 ? 1 : 0; + + if (label_priority && *label_priority) { + guint64 value; + + value = g_ascii_strtoull (label_priority, NULL, 10); + ui_elem->data.item.label_priority = value; + } + + if (order) + ui_elem->data.item.order = order_index; + + return ui_elem; +} + +typedef struct _ParseData { + EUIParser *self; + GSList *elems_stack; + gboolean changed; +} ParseData; + +/* returns whether handled, not whether succeeded */ +static gboolean +ui_parser_xml_handle_item_separator_placeholder (ParseData *pd, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gboolean item_for_headerbar, + gboolean item_for_menu, + GError **error) +{ + EUIElement *ui_elem = NULL, *parent_ui_elem; + gboolean is_existing = FALSE; + + parent_ui_elem = pd->elems_stack->data; + + if (g_strcmp0 (element_name, "item") == 0) { + ui_elem = ui_parser_xml_read_item_element (element_name, attribute_names, attribute_values, item_for_headerbar, item_for_menu, error); + if (!ui_elem) + return TRUE; + } else if (g_strcmp0 (element_name, "separator") == 0) { + ui_elem = e_ui_element_new (E_UI_ELEMENT_KIND_SEPARATOR, NULL); + } else if (g_strcmp0 (element_name, "placeholder") == 0) { + const gchar *id = NULL; + + if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, + G_MARKUP_COLLECT_STRING, "id", &id, + G_MARKUP_COLLECT_INVALID)) + return TRUE; + + ui_elem = e_ui_element_get_child_by_id (parent_ui_elem, id); + if (ui_elem) { + if (ui_elem->kind != E_UI_ELEMENT_KIND_PLACEHOLDER) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Duplicate element id \"%s\" of different kind detected, existing kind <%s>, requested kind ", + id, e_ui_element_kind_to_string (ui_elem->kind)); + return TRUE; + } + + is_existing = TRUE; + } else { + ui_elem = e_ui_element_new (E_UI_ELEMENT_KIND_PLACEHOLDER, id); + } + } else { + return FALSE; + } + + if (!is_existing) { + e_ui_element_add_child (parent_ui_elem, ui_elem); + pd->changed = TRUE; + } + + if (ui_elem->kind == E_UI_ELEMENT_KIND_PLACEHOLDER) + pd->elems_stack = g_slist_prepend (pd->elems_stack, ui_elem); + + return TRUE; +} + +static void +ui_parser_xml_handle_menu_submenu_start_element (ParseData *pd, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + GError **error) +{ + EUIElement *ui_elem = NULL, *parent_ui_elem; + const gchar *id = NULL, *action = NULL; + + if (ui_parser_xml_handle_item_separator_placeholder (pd, element_name, attribute_names, attribute_values, FALSE, TRUE, error)) + return; + + if (g_strcmp0 (element_name, "submenu") == 0) { + if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "id", &id, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "action", &action, + G_MARKUP_COLLECT_INVALID)) + return; + } else { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unknown element <%s>, expected , , or ", element_name); + return; + } + + /* to not need to specify both 'id' and 'action' attributes */ + if (action && !id) + id = action; + + parent_ui_elem = pd->elems_stack->data; + if (id) + ui_elem = e_ui_element_get_child_by_id (parent_ui_elem, id); + if (ui_elem) { + if (ui_elem->kind != E_UI_ELEMENT_KIND_SUBMENU) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Duplicate element id \"%s\" of different kind detected, existing kind <%s>, requested kind ", + id, e_ui_element_kind_to_string (ui_elem->kind)); + return; + } + } else if (!action) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Element <%s> requires 'action' attribute", element_name); + return; + } else { + ui_elem = e_ui_element_new (E_UI_ELEMENT_KIND_SUBMENU, id); + e_ui_element_add_child (parent_ui_elem, ui_elem); + pd->changed = TRUE; + + if (action) + ui_elem->data.submenu.action = e_util_strdup_strip (action); + } + + pd->elems_stack = g_slist_prepend (pd->elems_stack, ui_elem); +} + +static void +ui_parser_xml_handle_subroot_start_element (ParseData *pd, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + GError **error) +{ + EUIElementKind elem_kind = E_UI_ELEMENT_KIND_UNKNOWN; + EUIElement *ui_elem, *parent_ui_elem; + const gchar *id = NULL; + const gchar *type = NULL; + const gchar *primary = NULL; + gboolean is_popup = FALSE; + + if (g_strcmp0 (element_name, "headerbar") == 0) { + elem_kind = E_UI_ELEMENT_KIND_HEADERBAR; + } else if (g_strcmp0 (element_name, "menu") == 0) { + elem_kind = E_UI_ELEMENT_KIND_MENU; + } else if (g_strcmp0 (element_name, "toolbar") == 0) { + elem_kind = E_UI_ELEMENT_KIND_TOOLBAR; + } else { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unknown element <%s>, expected , or ", element_name); + return; + } + + if (elem_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, + G_MARKUP_COLLECT_STRING, "id", &id, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "type", &type, + G_MARKUP_COLLECT_INVALID)) + return; + + if (type && *type && g_strcmp0 (type, "gtk") != 0) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Element <%s> can have optional 'type' attribute of value 'gtk' only, but type '%s' provided", element_name, type); + return; + } + } else if (elem_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, + G_MARKUP_COLLECT_STRING, "id", &id, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "primary", &primary, + G_MARKUP_COLLECT_INVALID)) + return; + + if (primary && *primary && g_strcmp0 (primary, "true") != 0 && g_strcmp0 (primary, "false") != 0) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Element <%s> can have optional 'primary' attribute of value 'true' or 'false' only, but value '%s' provided", element_name, primary); + return; + } + } else { /* E_UI_ELEMENT_KIND_MENU */ + const gchar *is_popup_str = NULL; + + if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error, + G_MARKUP_COLLECT_STRING, "id", &id, + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "is-popup", &is_popup_str, + G_MARKUP_COLLECT_INVALID)) + return; + + if (is_popup_str && *is_popup_str && g_strcmp0 (is_popup_str, "true") != 0 && g_strcmp0 (is_popup_str, "false") != 0) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Element <%s> can have optional 'is-popup' attribute of value 'true' or 'false' only, but value '%s' provided", element_name, is_popup_str); + return; + } + + is_popup = g_strcmp0 (is_popup_str, "true") == 0; + } + + parent_ui_elem = pd->elems_stack->data; + ui_elem = e_ui_element_get_child_by_id (parent_ui_elem, id); + if (ui_elem) { + if (ui_elem->kind != elem_kind) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Duplicate element id \"%s\" of different kind detected, existing kind <%s>, requested kind <%s>", + id, e_ui_element_kind_to_string (ui_elem->kind), e_ui_element_kind_to_string (elem_kind)); + return; + } + } else { + ui_elem = e_ui_element_new (elem_kind, id); + + if (type && *type && g_strcmp0 (type, "gtk") == 0) + ui_elem->data.headerbar.use_gtk_type = TRUE; + if (primary && *primary && g_strcmp0 (primary, "true") == 0) + ui_elem->data.toolbar.primary = TRUE; + if (is_popup) + ui_elem->data.menu.is_popup = TRUE; + + e_ui_element_add_child (parent_ui_elem, ui_elem); + pd->changed = TRUE; + } + + pd->elems_stack = g_slist_prepend (pd->elems_stack, ui_elem); +} + +static gint +ui_parser_sort_by_order_cmp (gconstpointer aa, + gconstpointer bb) +{ + const EUIElement *elem1 = *((EUIElement **) aa); + const EUIElement *elem2 = *((EUIElement **) bb); + + if (!elem1 || !elem2) { + if (elem1) + return 1; + if (elem2) + return -1; + return 0; + } + + return e_ui_element_item_get_order (elem1) - e_ui_element_item_get_order (elem2); +} + +static void +ui_parser_xml_handle_start_end (ParseData *pd, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + GError **error) +{ + EUIElementKind elem_kind = E_UI_ELEMENT_KIND_UNKNOWN; + EUIElement *ui_elem = NULL, *parent_ui_elem; + guint ii; + + if (g_strcmp0 (element_name, "start") == 0) { + elem_kind = E_UI_ELEMENT_KIND_START; + } else if (g_strcmp0 (element_name, "end") == 0) { + elem_kind = E_UI_ELEMENT_KIND_END; + } else { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unknown element <%s>, expected or ", element_name); + return; + } + + if (attribute_names != NULL && attribute_names[0]) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, + "Element <%s> doesn't have any attributes", element_name); + return; + } + + parent_ui_elem = pd->elems_stack->data; + + for (ii = 0; ii < e_ui_element_get_n_children (parent_ui_elem); ii++) { + ui_elem = e_ui_element_get_child (parent_ui_elem, ii); + if (ui_elem && ui_elem->kind == elem_kind) + break; + else + ui_elem = NULL; + } + + if (!ui_elem) { + ui_elem = e_ui_element_new (elem_kind, e_ui_element_kind_to_string (elem_kind)); + e_ui_element_add_child (parent_ui_elem, ui_elem); + pd->changed = TRUE; + } + + pd->elems_stack = g_slist_prepend (pd->elems_stack, ui_elem); +} + +static void +ui_parser_xml_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + ParseData *pd = user_data; + EUIElement *ui_elem; + EUIElementKind parent_kind; + GSList *stack_link; + + if (!pd->elems_stack) { + if (g_strcmp0 (element_name, "eui") != 0) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unknown element <%s>, expected ", element_name); + return; + } + + if (!pd->self->root) { + pd->self->root = e_ui_element_new (E_UI_ELEMENT_KIND_ROOT, NULL); + pd->changed = TRUE; + } + + pd->elems_stack = g_slist_prepend (pd->elems_stack, pd->self->root); + + return; + } + + ui_elem = pd->elems_stack->data; + parent_kind = ui_elem->kind; + + stack_link = pd->elems_stack; + + while (parent_kind == E_UI_ELEMENT_KIND_PLACEHOLDER && stack_link && stack_link->next) { + EUIElement *parent_ui_elem; + + parent_ui_elem = stack_link->next->data; + parent_kind = parent_ui_elem->kind; + + stack_link = stack_link->next; + } + + if (parent_kind == E_UI_ELEMENT_KIND_ROOT) { + ui_parser_xml_handle_subroot_start_element (pd, element_name, attribute_names, attribute_values, error); + } else if (parent_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + ui_parser_xml_handle_start_end (pd, element_name, attribute_names, attribute_values, error); + } else if (parent_kind == E_UI_ELEMENT_KIND_START || parent_kind == E_UI_ELEMENT_KIND_END) { + if (!ui_parser_xml_handle_item_separator_placeholder (pd, element_name, attribute_names, attribute_values, TRUE, FALSE, error)) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unknown element <%s>, expected , or ", element_name); + } + } else if (parent_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + if (!ui_parser_xml_handle_item_separator_placeholder (pd, element_name, attribute_names, attribute_values, FALSE, FALSE, error)) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unknown element <%s>, expected , or ", element_name); + } + } else if (parent_kind == E_UI_ELEMENT_KIND_MENU || + parent_kind == E_UI_ELEMENT_KIND_SUBMENU) { + ui_parser_xml_handle_menu_submenu_start_element (pd, element_name, attribute_names, attribute_values, error); + } else { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unknown element <%s> under <%s>", element_name, e_ui_element_kind_to_string (parent_kind)); + } +} + +static void +ui_parser_xml_end_element (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + ParseData *pd = user_data; + + if (g_strcmp0 (element_name, "eui") == 0) { + if (!pd->elems_stack) { + g_set_error_literal (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "Ends without root element"); + } else if (g_slist_length (pd->elems_stack) != 1) { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, + "Expected end with single elem stack, but the stack has %u items", + g_slist_length (pd->elems_stack)); + } else if (pd->elems_stack->data != pd->self->root) { + g_set_error_literal (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "Ends with incorrect stack top"); + } else { + pd->elems_stack = g_slist_remove (pd->elems_stack, pd->elems_stack->data); + } + } else if (g_strcmp0 (element_name, "item") == 0 || + g_strcmp0 (element_name, "separator") == 0) { + } else if (pd->elems_stack) { + EUIElementKind expect_kind = E_UI_ELEMENT_KIND_UNKNOWN; + + if (g_strcmp0 (element_name, "headerbar") == 0) + expect_kind = E_UI_ELEMENT_KIND_HEADERBAR; + else if (g_strcmp0 (element_name, "toolbar") == 0) + expect_kind = E_UI_ELEMENT_KIND_TOOLBAR; + else if (g_strcmp0 (element_name, "menu") == 0) + expect_kind = E_UI_ELEMENT_KIND_MENU; + else if (g_strcmp0 (element_name, "submenu") == 0) + expect_kind = E_UI_ELEMENT_KIND_SUBMENU; + else if (g_strcmp0 (element_name, "placeholder") == 0) + expect_kind = E_UI_ELEMENT_KIND_PLACEHOLDER; + else if (g_strcmp0 (element_name, "start") == 0) + expect_kind = E_UI_ELEMENT_KIND_START; + else if (g_strcmp0 (element_name, "end") == 0) + expect_kind = E_UI_ELEMENT_KIND_END; + else + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "Unexpected element end <%s>", element_name); + + if (expect_kind != E_UI_ELEMENT_KIND_UNKNOWN) { + EUIElement *ui_elem = pd->elems_stack->data; + + if (ui_elem->kind == expect_kind) + pd->elems_stack = g_slist_remove (pd->elems_stack, pd->elems_stack->data); + else + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "Unexpected element <%s> on stack, but ended was <%s>", + e_ui_element_kind_to_string (ui_elem->kind), element_name); + + if (expect_kind == E_UI_ELEMENT_KIND_START || expect_kind == E_UI_ELEMENT_KIND_END) { + guint ii; + + for (ii = 0; ii < e_ui_element_get_n_children (ui_elem); ii++) { + EUIElement *child = e_ui_element_get_child (ui_elem, ii); + + if (child && e_ui_element_item_get_order (child) != 0) + break; + } + + /* when one element has non-zero order */ + if (ii < e_ui_element_get_n_children (ui_elem)) + g_ptr_array_sort (ui_elem->children, ui_parser_sort_by_order_cmp); + } + } + } +} + +/** + * e_ui_parser_merge_data: + * @self: an #EUIParser + * @data: a data to merge + * @data_len: length of the @data, or -1, when NUL-terminated + * @error: an output location to store a #GError at, or %NULL + * + * Adds content of the @data into the UI definition. Items with + * the same identifier are reused, allowing to add new items into + * existing hierarchy. + * + * Returns: whether could successfully parse the file content. On failure, + * the @error is set. + * + * Since: 3.56 + **/ +gboolean +e_ui_parser_merge_data (EUIParser *self, + const gchar *data, + gssize data_len, + GError **error) +{ + static GMarkupParser xml_parser = { + ui_parser_xml_start_element, + ui_parser_xml_end_element, + NULL, /* text */ + NULL, /* passthrough */ + NULL /* error */ + }; + GMarkupParseContext *context; + ParseData pd = { NULL, }; + gboolean success; + + g_return_val_if_fail (E_IS_UI_PARSER (self), FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + pd.self = self; + pd.elems_stack = NULL; + pd.changed = FALSE; + + context = g_markup_parse_context_new (&xml_parser, 0, &pd, NULL); + + success = g_markup_parse_context_parse (context, data, data_len, error) && + g_markup_parse_context_end_parse (context, error); + + g_markup_parse_context_free (context); + + if (pd.changed) + g_signal_emit (self, signals[SIGNAL_CHANGED], 0, NULL); + + return success; +} + +/** + * e_ui_parser_clear: + * @self: an #EUIParser + * + * Removes all content of the @self. + * + * Since: 3.56 + **/ +void +e_ui_parser_clear (EUIParser *self) +{ + g_return_if_fail (E_IS_UI_PARSER (self)); + + if (self->root) { + g_clear_pointer (&self->root, e_ui_element_free); + g_signal_emit (self, signals[SIGNAL_CHANGED], 0, NULL); + } +} + +/** + * e_ui_parser_get_root: + * @self: an #EUIParser + * + * Gets the root element of the @self. + * + * Returns: (nullable) (transfer none): a root #EUIElement, or %NULL, when nothing was parsed yet + * + * Since: 3.56 + **/ +EUIElement * +e_ui_parser_get_root (EUIParser *self) +{ + g_return_val_if_fail (E_IS_UI_PARSER (self), NULL); + + return self->root; +} + +/** + * e_ui_parser_export: + * @self: an #EUIParser + * @flags: a bit-or of #EUIParserExportFlags flags + * + * Exports the content of the @self in a format suitable for e_ui_parser_merge_file() + * and e_ui_parser_merge_data(). + * + * Free the returned string with g_free(), when no longer needed. + * + * Returns: (transfer full) (nullable): a string representation of the @self content, + * or %NULL, when the @self is empty. + * + * Since: 3.56 + **/ +gchar * +e_ui_parser_export (EUIParser *self, + EUIParserExportFlags flags) +{ + GString *str; + + g_return_val_if_fail (E_IS_UI_PARSER (self), NULL); + + if (!self->root) + return NULL; + + str = g_string_new (""); + + e_ui_element_export (self->root, str, (flags & E_UI_PARSER_EXPORT_FLAG_INDENT) ? 0 : -1); + + if (!(flags & E_UI_PARSER_EXPORT_FLAG_INDENT)) + g_string_append_c (str, '\n'); + + return g_string_free (str, FALSE); +} diff --git a/src/e-util/e-ui-parser.h b/src/e-util/e-ui-parser.h new file mode 100644 index 0000000000..1024e28cf0 --- /dev/null +++ b/src/e-util/e-ui-parser.h @@ -0,0 +1,75 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * SPDX-FileCopyrightText: (C) 2024 Red Hat (www.redhat.com> + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#if !defined (__E_UTIL_H_INSIDE__) && !defined (LIBEUTIL_COMPILATION) +#error "Only should be included directly." +#endif + +#ifndef E_UI_PARSER_H +#define E_UI_PARSER_H + +#include + +#include + +G_BEGIN_DECLS + +#define E_TYPE_UI_PARSER e_ui_parser_get_type () + +G_DECLARE_FINAL_TYPE (EUIParser, e_ui_parser, E, UI_PARSER, GObject) + +typedef struct _EUIElement EUIElement; + +/* generic EUIElement functions, usable for any element */ +EUIElementKind e_ui_element_get_kind (const EUIElement *self); +const gchar * e_ui_element_get_id (const EUIElement *self); +guint e_ui_element_get_n_children (const EUIElement *self); +EUIElement * e_ui_element_get_child (EUIElement *self, + guint index); +EUIElement * e_ui_element_get_child_by_id (EUIElement *self, + const gchar *id); +/* menu element functions */ +gboolean e_ui_element_menu_get_is_popup (const EUIElement *self); +/* submenu element functions */ +const gchar * e_ui_element_submenu_get_action (const EUIElement *self); +/* headerbar element functions */ +gboolean e_ui_element_headerbar_get_use_gtk_type + (const EUIElement *self); +/* toolbar element functions */ +gboolean e_ui_element_toolbar_get_primary(const EUIElement *self); +/* item element functions */ +guint e_ui_element_item_get_label_priority + (const EUIElement *self); +gint e_ui_element_item_get_order (const EUIElement *self); +gboolean e_ui_element_item_get_icon_only_is_set + (const EUIElement *self); +gboolean e_ui_element_item_get_icon_only (const EUIElement *self); +gboolean e_ui_element_item_get_text_only_is_set + (const EUIElement *self); +gboolean e_ui_element_item_get_text_only (const EUIElement *self); +gboolean e_ui_element_item_get_important (const EUIElement *self); +const gchar * e_ui_element_item_get_css_classes + (const EUIElement *self); +const gchar * e_ui_element_item_get_action (const EUIElement *self); +const gchar * e_ui_element_item_get_group (const EUIElement *self); + +/* parser functions */ +EUIParser * e_ui_parser_new (void); +gboolean e_ui_parser_merge_file (EUIParser *self, + const gchar *filename, + GError **error); +gboolean e_ui_parser_merge_data (EUIParser *self, + const gchar *data, + gssize data_len, + GError **error); +void e_ui_parser_clear (EUIParser *self); +EUIElement * e_ui_parser_get_root (EUIParser *self); +gchar * e_ui_parser_export (EUIParser *self, + EUIParserExportFlags flags); + +G_END_DECLS + +#endif /* E_UI_PARSER_H */ diff --git a/src/e-util/e-util-enums.h b/src/e-util/e-util-enums.h index 180d062db8..87531e35c7 100644 --- a/src/e-util/e-util-enums.h +++ b/src/e-util/e-util-enums.h @@ -720,6 +720,53 @@ typedef enum { E_HTML_LINK_TO_TEXT_REFERENCE_WITHOUT_LABEL = 3 } EHTMLLinkToText; +/** + * EUIElementKind: + * @E_UI_ELEMENT_KIND_UNKNOWN: the kind is not known; used to indicate an error + * @E_UI_ELEMENT_KIND_ROOT: a root, aka toplevel, element; it contains elements for headerbar, toolbar and menu usually + * @E_UI_ELEMENT_KIND_HEADERBAR: a headerbar element + * @E_UI_ELEMENT_KIND_TOOLBAR: a toolbar element + * @E_UI_ELEMENT_KIND_MENU: a menu element + * @E_UI_ELEMENT_KIND_SUBMENU: a submenu of a menu element + * @E_UI_ELEMENT_KIND_PLACEHOLDER: a placeholder, into which can be added other elements + * @E_UI_ELEMENT_KIND_SEPARATOR: a separator element + * @E_UI_ELEMENT_KIND_START: a list of items to be packed at the start of a headerbar + * @E_UI_ELEMENT_KIND_END: a list of items to be packed at the end of a headerbar + * @E_UI_ELEMENT_KIND_ITEM: an item + * + * The UI element kinds. Depending on the kind, only respective functions can be + * called for the element. + * + * Since: 3.56 + **/ +typedef enum _EUIElementKind { + E_UI_ELEMENT_KIND_UNKNOWN, + E_UI_ELEMENT_KIND_ROOT, + E_UI_ELEMENT_KIND_HEADERBAR, + E_UI_ELEMENT_KIND_TOOLBAR, + E_UI_ELEMENT_KIND_MENU, + E_UI_ELEMENT_KIND_SUBMENU, + E_UI_ELEMENT_KIND_PLACEHOLDER, + E_UI_ELEMENT_KIND_SEPARATOR, + E_UI_ELEMENT_KIND_START, + E_UI_ELEMENT_KIND_END, + E_UI_ELEMENT_KIND_ITEM +} EUIElementKind; + +/** + * EUIParserExportFlags: + * @E_UI_PARSER_EXPORT_FLAG_NONE: no flag set + * @E_UI_PARSER_EXPORT_FLAG_INDENT: indent the output; when not set a single line of text is exported + * + * Set of flags to influence output of the e_ui_parser_export(). + * + * Since: 3.56 + **/ +typedef enum _EUIParserExportFlags { /*< flags >*/ + E_UI_PARSER_EXPORT_FLAG_NONE = 0, + E_UI_PARSER_EXPORT_FLAG_INDENT = 1 << 0 +} EUIParserExportFlags; + G_END_DECLS #endif /* E_UTIL_ENUMS_H */ diff --git a/src/e-util/e-util.h b/src/e-util/e-util.h index abf7c1db3d..7b577ede71 100644 --- a/src/e-util/e-util.h +++ b/src/e-util/e-util.h @@ -100,10 +100,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -158,7 +156,6 @@ #include #include #include -#include #include #include #include @@ -177,7 +174,6 @@ #include #include #include -#include #include #include #include @@ -267,6 +263,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include diff --git a/src/e-util/e-web-view.c b/src/e-util/e-web-view.c index 421760de62..8b1f73f3b0 100644 --- a/src/e-util/e-web-view.c +++ b/src/e-util/e-web-view.c @@ -35,9 +35,11 @@ #include "e-file-request.h" #include "e-misc-utils.h" #include "e-plugin-ui.h" -#include "e-popup-action.h" #include "e-selectable.h" #include "e-stock-request.h" +#include "e-ui-action.h" +#include "e-ui-action-group.h" +#include "e-ui-manager.h" #include "e-web-view-jsc-utils.h" #include "e-web-view.h" @@ -50,16 +52,16 @@ typedef struct _ElementClickedData { } ElementClickedData; struct _EWebViewPrivate { - GtkUIManager *ui_manager; + EUIManager *ui_manager; gchar *selected_uri; gchar *cursor_image_src; GQueue highlights; gboolean highlights_enabled; - GtkAction *open_proxy; - GtkAction *print_proxy; - GtkAction *save_as_proxy; + EUIAction *open_proxy; + EUIAction *print_proxy; + EUIAction *save_as_proxy; /* Lockdown Options */ gboolean disable_printing; @@ -138,33 +140,6 @@ enum { static guint signals[LAST_SIGNAL]; -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; - /* Forward Declarations */ static void e_web_view_alert_sink_init (EAlertSinkInterface *iface); static void e_web_view_selectable_init (ESelectableInterface *iface); @@ -227,9 +202,12 @@ e_web_view_spell_settings_changed_cb (GSettings *settings, } static void -action_copy_clipboard_cb (GtkAction *action, - EWebView *web_view) +action_copy_clipboard_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; + e_web_view_copy_clipboard (web_view); } @@ -284,17 +262,22 @@ e_web_view_search_web_get_selection_cb (GObject *source, } static void -action_search_web_cb (GtkAction *action, - EWebView *web_view) +action_search_web_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; + e_web_view_jsc_get_selection (WEBKIT_WEB_VIEW (web_view), E_TEXT_FORMAT_PLAIN, web_view->priv->cancellable, e_web_view_search_web_get_selection_cb, NULL); } static void -action_http_open_cb (GtkAction *action, - EWebView *web_view) +action_http_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; const gchar *uri; gpointer parent; @@ -351,30 +334,41 @@ webview_mailto_copy (EWebView *web_view, } static void -action_mailto_copy_cb (GtkAction *action, - EWebView *web_view) +action_mailto_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; + webview_mailto_copy (web_view, FALSE); } static void -action_mailto_copy_raw_cb (GtkAction *action, - EWebView *web_view) +action_mailto_copy_raw_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; + webview_mailto_copy (web_view, TRUE); } static void -action_select_all_cb (GtkAction *action, - EWebView *web_view) +action_select_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; + e_web_view_select_all (web_view); } static void -action_send_message_cb (GtkAction *action, - EWebView *web_view) +action_send_message_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; const gchar *uri; gpointer parent; gboolean handled; @@ -393,9 +387,11 @@ action_send_message_cb (GtkAction *action, } static void -action_uri_copy_cb (GtkAction *action, - EWebView *web_view) +action_uri_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; GtkClipboard *clipboard; const gchar *uri; @@ -412,123 +408,56 @@ action_uri_copy_cb (GtkAction *action, } static void -action_image_copy_cb (GtkAction *action, - EWebView *web_view) +action_image_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; + e_web_view_cursor_image_copy (web_view); } static void -action_image_save_cb (GtkAction *action, - EWebView *web_view) +action_image_save_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EWebView *web_view = user_data; + e_web_view_cursor_image_save (web_view); } -static GtkActionEntry uri_entries[] = { +static void +action_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EWebView *web_view = user_data; - { "uri-copy", - "edit-copy", - N_("_Copy Link Location"), - "c", - N_("Copy the link to the clipboard"), - G_CALLBACK (action_uri_copy_cb) } -}; - -static GtkActionEntry http_entries[] = { - - { "http-open", - "emblem-web", - N_("_Open Link in Browser"), - NULL, - N_("Open the link in a web browser"), - G_CALLBACK (action_http_open_cb) } -}; - -static GtkActionEntry mailto_entries[] = { - - { "mailto-copy", - "edit-copy", - N_("_Copy Name and Email Address"), - "c", - N_("Copy the email address with the name to the clipboard"), - G_CALLBACK (action_mailto_copy_cb) }, - - { "mailto-copy-raw", - "edit-copy", - N_("Copy Only Email Add_ress"), - NULL, - N_("Copy only the email address without the name to the clipboard"), - G_CALLBACK (action_mailto_copy_raw_cb) }, - - { "send-message", - "mail-message-new", - N_("_Send New Message To…"), - NULL, - N_("Send a mail message to this address"), - G_CALLBACK (action_send_message_cb) } -}; - -static GtkActionEntry image_entries[] = { - - { "image-copy", - "edit-copy", - N_("_Copy Image"), - "c", - N_("Copy the image to the clipboard"), - G_CALLBACK (action_image_copy_cb) }, - - { "image-save", - "document-save", - N_("Save _Image…"), - "s", - N_("Save the image to a file"), - G_CALLBACK (action_image_save_cb) } -}; - -static GtkActionEntry selection_entries[] = { - - { "copy-clipboard", - "edit-copy", - N_("_Copy"), - "c", - N_("Copy the selection"), - G_CALLBACK (action_copy_clipboard_cb) }, - - { "search-web", - NULL, - N_("Search _Web…"), - NULL, - N_("Search the Web with the selected text"), - G_CALLBACK (action_search_web_cb) } -}; - -static GtkActionEntry standard_entries[] = { - - { "select-all", - "edit-select-all", - N_("Select _All"), - NULL, - N_("Select all text and images"), - G_CALLBACK (action_select_all_cb) } -}; + if (web_view->priv->open_proxy) + g_action_activate (G_ACTION (web_view->priv->open_proxy), NULL); +} static void -web_view_menu_item_select_cb (EWebView *web_view, - GtkWidget *widget) +action_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - GtkAction *action; - GtkActivatable *activatable; - const gchar *tooltip; + EWebView *web_view = user_data; - activatable = GTK_ACTIVATABLE (widget); - action = gtk_activatable_get_related_action (activatable); - tooltip = gtk_action_get_tooltip (action); + if (web_view->priv->print_proxy) + g_action_activate (G_ACTION (web_view->priv->print_proxy), NULL); +} - if (tooltip == NULL) - return; +static void +action_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EWebView *web_view = user_data; - e_web_view_status_message (web_view, tooltip); + if (web_view->priv->save_as_proxy) + g_action_activate (G_ACTION (web_view->priv->save_as_proxy), NULL); } static void @@ -581,29 +510,6 @@ web_view_update_document_highlights (EWebView *web_view) } } -static void -web_view_menu_item_deselect_cb (EWebView *web_view) -{ - e_web_view_status_message (web_view, NULL); -} - -static void -web_view_connect_proxy_cb (EWebView *web_view, - GtkAction *action, - GtkWidget *proxy) -{ - if (!GTK_IS_MENU_ITEM (proxy)) - return; - - g_signal_connect_swapped ( - proxy, "select", - G_CALLBACK (web_view_menu_item_select_cb), web_view); - - g_signal_connect_swapped ( - proxy, "deselect", - G_CALLBACK (web_view_menu_item_deselect_cb), web_view); -} - static void web_view_got_elem_from_point_for_popup_event_cb (GObject *source_object, GAsyncResult *result, @@ -1931,17 +1837,32 @@ web_view_stop_loading (EWebView *web_view) webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (web_view)); } +static void +e_web_view_update_action_from_proxy (EUIAction *action, + EUIAction *proxy) +{ + e_ui_action_set_visible (action, proxy && e_ui_action_is_visible (proxy)); + + if (!e_ui_action_get_visible (action)) + return; + + e_ui_action_set_label (action, e_ui_action_get_label (proxy)); + e_ui_action_set_icon_name (action, e_ui_action_get_icon_name (proxy)); + e_ui_action_set_tooltip (action, e_ui_action_get_tooltip (proxy)); + e_ui_action_set_sensitive (action, g_action_get_enabled (G_ACTION (proxy))); +} + static void web_view_update_actions (EWebView *web_view) { - GtkActionGroup *action_group; + EUIActionGroup *action_group; + EUIAction *action; gboolean can_copy; gboolean scheme_is_http = FALSE; gboolean scheme_is_mailto = FALSE; gboolean uri_is_valid = FALSE; gboolean visible; const gchar *cursor_image_src; - const gchar *group_name; const gchar *uri; g_return_if_fail (E_IS_WEB_VIEW (web_view)); @@ -1967,20 +1888,17 @@ web_view_update_actions (EWebView *web_view) } /* Allow copying the URI even if it's malformed. */ - group_name = "uri"; visible = (uri != NULL) && !scheme_is_mailto; - action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + action_group = e_web_view_get_action_group (web_view, "uri"); + e_ui_action_group_set_visible (action_group, visible); - group_name = "http"; visible = uri_is_valid && scheme_is_http; - action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + action_group = e_web_view_get_action_group (web_view, "http"); + e_ui_action_group_set_visible (action_group, visible); - group_name = "mailto"; visible = uri_is_valid && scheme_is_mailto; - action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + action_group = e_web_view_get_action_group (web_view, "mailto"); + e_ui_action_group_set_visible (action_group, visible); if (visible) { CamelURL *curl; @@ -1989,13 +1907,12 @@ web_view_update_actions (EWebView *web_view) if (curl) { CamelInternetAddress *inet_addr; const gchar *name = NULL, *email = NULL; - GtkAction *action; inet_addr = camel_internet_address_new (); camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path); - action = gtk_action_group_get_action (action_group, "mailto-copy-raw"); - gtk_action_set_visible (action, + action = e_ui_action_group_get_action (action_group, "mailto-copy-raw"); + e_ui_action_set_visible (action, camel_internet_address_get (inet_addr, 0, &name, &email) && name && *name && email && *email); @@ -2004,30 +1921,29 @@ web_view_update_actions (EWebView *web_view) } } - group_name = "image"; visible = (cursor_image_src != NULL); - action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + action_group = e_web_view_get_action_group (web_view, "image"); + e_ui_action_group_set_visible (action_group, visible); - group_name = "selection"; visible = can_copy; - action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + action_group = e_web_view_get_action_group (web_view, "selection"); + e_ui_action_group_set_visible (action_group, visible); - group_name = "standard"; visible = (uri == NULL); - action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + action_group = e_web_view_get_action_group (web_view, "standard"); + e_ui_action_group_set_visible (action_group, visible); - group_name = "lockdown-printing"; visible = (uri == NULL) && !web_view->priv->disable_printing; - action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + action_group = e_web_view_get_action_group (web_view, "lockdown-printing"); + e_ui_action_group_set_visible (action_group, visible); - group_name = "lockdown-save-to-disk"; visible = (uri == NULL) && !web_view->priv->disable_save_to_disk; - action_group = e_web_view_get_action_group (web_view, group_name); - gtk_action_group_set_visible (action_group, visible); + action_group = e_web_view_get_action_group (web_view, "lockdown-save-to-disk"); + e_ui_action_group_set_visible (action_group, visible); + + e_web_view_update_action_from_proxy (e_web_view_get_action (web_view, "open"), web_view->priv->open_proxy); + e_web_view_update_action_from_proxy (e_web_view_get_action (web_view, "print"), web_view->priv->print_proxy); + e_web_view_update_action_from_proxy (e_web_view_get_action (web_view, "save-as"), web_view->priv->save_as_proxy); } static void @@ -2137,14 +2053,14 @@ web_view_submit_alert (EAlertSink *alert_sink, static void web_view_can_execute_editing_command_cb (WebKitWebView *webkit_web_view, GAsyncResult *result, - GtkAction *action) + EUIAction *action) { gboolean can_do_command; can_do_command = webkit_web_view_can_execute_editing_command_finish ( webkit_web_view, result, NULL); - gtk_action_set_sensitive (action, can_do_command); + e_ui_action_set_sensitive (action, can_do_command); g_object_unref (action); } @@ -2155,7 +2071,7 @@ web_view_selectable_update_actions (ESelectable *selectable, gint n_clipboard_targets) { EWebView *web_view; - GtkAction *action; + EUIAction *action; gboolean can_copy = FALSE; web_view = E_WEB_VIEW (selectable); @@ -2163,8 +2079,8 @@ web_view_selectable_update_actions (ESelectable *selectable, can_copy = e_web_view_has_selection (web_view); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); - gtk_action_set_sensitive (action, can_copy); - gtk_action_set_tooltip (action, _("Copy the selection")); + e_ui_action_set_sensitive (action, can_copy); + e_ui_action_set_tooltip (action, _("Copy the selection")); action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); webkit_web_view_can_execute_editing_command ( @@ -2173,7 +2089,7 @@ web_view_selectable_update_actions (ESelectable *selectable, NULL, /* cancellable */ (GAsyncReadyCallback) web_view_can_execute_editing_command_cb, g_object_ref (action)); - gtk_action_set_tooltip (action, _("Cut the selection")); + e_ui_action_set_tooltip (action, _("Cut the selection")); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); webkit_web_view_can_execute_editing_command ( @@ -2182,11 +2098,11 @@ web_view_selectable_update_actions (ESelectable *selectable, NULL, /* cancellable */ (GAsyncReadyCallback) web_view_can_execute_editing_command_cb, g_object_ref (action)); - gtk_action_set_tooltip (action, _("Paste the clipboard")); + e_ui_action_set_tooltip (action, _("Paste the clipboard")); action = e_focus_tracker_get_select_all_action (focus_tracker); - gtk_action_set_sensitive (action, TRUE); - gtk_action_set_tooltip (action, _("Select all text and images")); + e_ui_action_set_sensitive (action, TRUE); + e_ui_action_set_tooltip (action, _("Select all text and images")); } static void @@ -2399,7 +2315,7 @@ e_web_view_class_init (EWebViewClass *class) "open-proxy", "Open Proxy", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -2409,7 +2325,7 @@ e_web_view_class_init (EWebViewClass *class) "print-proxy", "Print Proxy", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -2419,7 +2335,7 @@ e_web_view_class_init (EWebViewClass *class) "save-as-proxy", "Save As Proxy", NULL, - GTK_TYPE_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -2553,14 +2469,151 @@ e_web_view_selectable_init (ESelectableInterface *iface) static void e_web_view_init (EWebView *web_view) { - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - EPopupAction *popup_action; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry uri_entries[] = { + + { "uri-copy", + "edit-copy", + N_("_Copy Link Location"), + "c", + N_("Copy the link to the clipboard"), + action_uri_copy_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry http_entries[] = { + + { "http-open", + "emblem-web", + N_("_Open Link in Browser"), + NULL, + N_("Open the link in a web browser"), + action_http_open_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry mailto_entries[] = { + + { "mailto-copy", + "edit-copy", + N_("_Copy Name and Email Address"), + "c", + N_("Copy the email address with the name to the clipboard"), + action_mailto_copy_cb, NULL, NULL, NULL }, + + { "mailto-copy-raw", + "edit-copy", + N_("Copy Only Email Add_ress"), + NULL, + N_("Copy only the email address without the name to the clipboard"), + action_mailto_copy_raw_cb, NULL, NULL, NULL }, + + { "send-message", + "mail-message-new", + N_("_Send New Message To…"), + NULL, + N_("Send a mail message to this address"), + action_send_message_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry image_entries[] = { + + { "image-copy", + "edit-copy", + N_("_Copy Image"), + "c", + N_("Copy the image to the clipboard"), + action_image_copy_cb, NULL, NULL, NULL }, + + { "image-save", + "document-save", + N_("Save _Image…"), + "s", + N_("Save the image to a file"), + action_image_save_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry selection_entries[] = { + + { "copy-clipboard", + "edit-copy", + N_("_Copy"), + "c", + N_("Copy the selection"), + action_copy_clipboard_cb, NULL, NULL, NULL }, + + { "search-web", + NULL, + N_("Search _Web…"), + NULL, + N_("Search the Web with the selected text"), + action_search_web_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry standard_entries[] = { + + { "open", + NULL, + N_("_Open"), + NULL, + NULL, + action_open_cb, NULL, NULL, NULL }, + + { "select-all", + "edit-select-all", + N_("Select _All"), + NULL, + N_("Select all text and images"), + action_select_all_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry lockdown_printing_entries[] = { + + { "print", + "document-print", + N_("_Print"), + NULL, + NULL, + action_print_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry lockdown_save_to_disk_entries[] = { + + { "save-as", + "document-save-as", + N_("Save _as…"), + NULL, + NULL, + action_save_as_cb, NULL, NULL, NULL } + }; + + EUIManager *ui_manager; GSettings *settings; - const gchar *domain = GETTEXT_PACKAGE; - const gchar *id; gulong handler_id; - GError *error = NULL; web_view->priv = e_web_view_get_instance_private (web_view); @@ -2593,13 +2646,9 @@ e_web_view_init (EWebView *web_view) web_view, "state-flags-changed", G_CALLBACK (style_updated_cb), NULL); - ui_manager = gtk_ui_manager_new (); + ui_manager = e_ui_manager_new (); web_view->priv->ui_manager = ui_manager; - g_signal_connect_swapped ( - ui_manager, "connect-proxy", - G_CALLBACK (web_view_connect_proxy_cb), web_view); - settings = e_util_ref_settings ("org.gnome.desktop.interface"); web_view->priv->font_settings = g_object_ref (settings); handler_id = g_signal_connect_swapped ( @@ -2612,116 +2661,30 @@ e_web_view_init (EWebView *web_view) web_view->priv->monospace_font_name_changed_handler_id = handler_id; g_object_unref (settings); - action_group = gtk_action_group_new ("uri"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - gtk_action_group_add_actions ( - action_group, uri_entries, - G_N_ELEMENTS (uri_entries), web_view); - - action_group = gtk_action_group_new ("http"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - gtk_action_group_add_actions ( - action_group, http_entries, - G_N_ELEMENTS (http_entries), web_view); - - action_group = gtk_action_group_new ("mailto"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - gtk_action_group_add_actions ( - action_group, mailto_entries, - G_N_ELEMENTS (mailto_entries), web_view); - - action_group = gtk_action_group_new ("image"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - gtk_action_group_add_actions ( - action_group, image_entries, - G_N_ELEMENTS (image_entries), web_view); - - action_group = gtk_action_group_new ("selection"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - gtk_action_group_add_actions ( - action_group, selection_entries, - G_N_ELEMENTS (selection_entries), web_view); - - action_group = gtk_action_group_new ("standard"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - gtk_action_group_add_actions ( - action_group, standard_entries, - G_N_ELEMENTS (standard_entries), web_view); - - popup_action = e_popup_action_new ("open"); - gtk_action_group_add_action (action_group, GTK_ACTION (popup_action)); - g_object_unref (popup_action); - - e_binding_bind_property ( - web_view, "open-proxy", - popup_action, "related-action", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - + e_ui_manager_add_actions (ui_manager, "uri", NULL, + uri_entries, G_N_ELEMENTS (uri_entries), web_view); + e_ui_manager_add_actions (ui_manager, "http", NULL, + http_entries, G_N_ELEMENTS (http_entries), web_view); + e_ui_manager_add_actions (ui_manager, "mailto", NULL, + mailto_entries, G_N_ELEMENTS (mailto_entries), web_view); + e_ui_manager_add_actions (ui_manager, "image", NULL, + image_entries, G_N_ELEMENTS (image_entries), web_view); + e_ui_manager_add_actions (ui_manager, "selection", NULL, + selection_entries, G_N_ELEMENTS (selection_entries), web_view); /* Support lockdown. */ - - action_group = gtk_action_group_new ("lockdown-printing"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - popup_action = e_popup_action_new ("print"); - gtk_action_group_add_action (action_group, GTK_ACTION (popup_action)); - g_object_unref (popup_action); - - e_binding_bind_property ( - web_view, "print-proxy", - popup_action, "related-action", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - action_group = gtk_action_group_new ("lockdown-save-to-disk"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - popup_action = e_popup_action_new ("save-as"); - gtk_action_group_add_action (action_group, GTK_ACTION (popup_action)); - g_object_unref (popup_action); - - e_binding_bind_property ( - web_view, "save-as-proxy", - popup_action, "related-action", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - /* Because we are loading from a hard-coded string, there is - * no chance of I/O errors. Failure here implies a malformed - * UI definition. Full stop. */ - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) - g_error ("%s", error->message); - - id = "org.gnome.evolution.webview"; - e_plugin_ui_register_manager (ui_manager, id, web_view); - e_plugin_ui_enable_manager (ui_manager, id); + e_ui_manager_add_actions (ui_manager, "lockdown-printing", NULL, + lockdown_printing_entries, G_N_ELEMENTS (lockdown_printing_entries), web_view); + e_ui_manager_add_actions (ui_manager, "lockdown-save-to-disk", NULL, + lockdown_save_to_disk_entries, G_N_ELEMENTS (lockdown_save_to_disk_entries), web_view); + /* finally add actions with the .eui data */ + e_ui_manager_add_actions_with_eui_data (ui_manager, "standard", NULL, + standard_entries, G_N_ELEMENTS (standard_entries), web_view, eui); web_view->priv->element_clicked_cbs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); web_view->priv->cancellable = NULL; + + e_ui_manager_set_action_groups_widget (ui_manager, GTK_WIDGET (web_view)); } GtkWidget * @@ -2982,7 +2945,7 @@ e_web_view_set_cursor_image_src (EWebView *web_view, g_object_notify (G_OBJECT (web_view), "cursor-image-src"); } -GtkAction * +EUIAction * e_web_view_get_open_proxy (EWebView *web_view) { g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); @@ -2992,7 +2955,7 @@ e_web_view_get_open_proxy (EWebView *web_view) void e_web_view_set_open_proxy (EWebView *web_view, - GtkAction *open_proxy) + EUIAction *open_proxy) { g_return_if_fail (E_IS_WEB_VIEW (web_view)); @@ -3000,7 +2963,7 @@ e_web_view_set_open_proxy (EWebView *web_view, return; if (open_proxy != NULL) { - g_return_if_fail (GTK_IS_ACTION (open_proxy)); + g_return_if_fail (E_IS_UI_ACTION (open_proxy)); g_object_ref (open_proxy); } @@ -3023,7 +2986,7 @@ e_web_view_get_paste_target_list (EWebView *web_view) return NULL; } -GtkAction * +EUIAction * e_web_view_get_print_proxy (EWebView *web_view) { g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); @@ -3033,7 +2996,7 @@ e_web_view_get_print_proxy (EWebView *web_view) void e_web_view_set_print_proxy (EWebView *web_view, - GtkAction *print_proxy) + EUIAction *print_proxy) { g_return_if_fail (E_IS_WEB_VIEW (web_view)); @@ -3041,7 +3004,7 @@ e_web_view_set_print_proxy (EWebView *web_view, return; if (print_proxy != NULL) { - g_return_if_fail (GTK_IS_ACTION (print_proxy)); + g_return_if_fail (E_IS_UI_ACTION (print_proxy)); g_object_ref (print_proxy); } @@ -3053,7 +3016,7 @@ e_web_view_set_print_proxy (EWebView *web_view, g_object_notify (G_OBJECT (web_view), "print-proxy"); } -GtkAction * +EUIAction * e_web_view_get_save_as_proxy (EWebView *web_view) { g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); @@ -3063,7 +3026,7 @@ e_web_view_get_save_as_proxy (EWebView *web_view) void e_web_view_set_save_as_proxy (EWebView *web_view, - GtkAction *save_as_proxy) + EUIAction *save_as_proxy) { g_return_if_fail (E_IS_WEB_VIEW (web_view)); @@ -3071,7 +3034,7 @@ e_web_view_set_save_as_proxy (EWebView *web_view, return; if (save_as_proxy != NULL) { - g_return_if_fail (GTK_IS_ACTION (save_as_proxy)); + g_return_if_fail (E_IS_UI_ACTION (save_as_proxy)); g_object_ref (save_as_proxy); } @@ -3151,32 +3114,32 @@ e_web_view_disable_highlights (EWebView *web_view) web_view->priv->highlights_enabled = FALSE; } -GtkAction * +EUIAction * e_web_view_get_action (EWebView *web_view, const gchar *action_name) { - GtkUIManager *ui_manager; + EUIManager *ui_manager; g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); g_return_val_if_fail (action_name != NULL, NULL); ui_manager = e_web_view_get_ui_manager (web_view); - return e_lookup_action (ui_manager, action_name); + return e_ui_manager_get_action (ui_manager, action_name); } -GtkActionGroup * +EUIActionGroup * e_web_view_get_action_group (EWebView *web_view, const gchar *group_name) { - GtkUIManager *ui_manager; + EUIManager *ui_manager; g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); g_return_val_if_fail (group_name != NULL, NULL); ui_manager = e_web_view_get_ui_manager (web_view); - return e_lookup_action_group (ui_manager, group_name); + return e_ui_manager_get_action_group (ui_manager, group_name); } void @@ -3291,7 +3254,7 @@ e_web_view_zoom_out (EWebView *web_view) webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (web_view), zoom_level); } -GtkUIManager * +EUIManager * e_web_view_get_ui_manager (EWebView *web_view) { g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); @@ -3299,54 +3262,28 @@ e_web_view_get_ui_manager (EWebView *web_view) return web_view->priv->ui_manager; } -static void -e_web_view_popup_menu_deactivate_cb (GtkMenu *popup_menu, - GtkWidget *web_view) -{ - g_return_if_fail (GTK_IS_MENU (popup_menu)); - - g_signal_handlers_disconnect_by_func (popup_menu, e_web_view_popup_menu_deactivate_cb, web_view); - gtk_menu_detach (popup_menu); -} - -GtkWidget * -e_web_view_get_popup_menu (EWebView *web_view) -{ - GtkUIManager *ui_manager; - GtkWidget *menu; - - g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); - - ui_manager = e_web_view_get_ui_manager (web_view); - menu = gtk_ui_manager_get_widget (ui_manager, "/context"); - g_return_val_if_fail (GTK_IS_MENU (menu), NULL); - - g_warn_if_fail (!gtk_menu_get_attach_widget (GTK_MENU (menu))); - - gtk_menu_attach_to_widget (GTK_MENU (menu), - GTK_WIDGET (web_view), - NULL); - - g_signal_connect ( - menu, "deactivate", - G_CALLBACK (e_web_view_popup_menu_deactivate_cb), web_view); - - return menu; -} - void e_web_view_show_popup_menu (EWebView *web_view, GdkEvent *event) { - GtkWidget *menu; + EUIManager *ui_manager; + GtkMenu *menu; + GObject *ui_item; g_return_if_fail (E_IS_WEB_VIEW (web_view)); e_web_view_update_actions (web_view); - menu = e_web_view_get_popup_menu (web_view); + ui_manager = e_web_view_get_ui_manager (web_view); + ui_item = e_ui_manager_create_item (ui_manager, "context"); + menu = GTK_MENU (gtk_menu_new_from_model (G_MENU_MODEL (ui_item))); + g_clear_object (&ui_item); - gtk_menu_popup_at_pointer (GTK_MENU (menu), event); + gtk_menu_attach_to_widget (menu, GTK_WIDGET (web_view), NULL); + + e_util_connect_menu_detach_after_deactivate (menu); + + gtk_menu_popup_at_pointer (menu, event); } /** diff --git a/src/e-util/e-web-view.h b/src/e-util/e-web-view.h index ef238d8f68..5f2461d159 100644 --- a/src/e-util/e-web-view.h +++ b/src/e-util/e-web-view.h @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include /* Standard GObject macros */ #define E_TYPE_WEB_VIEW \ @@ -181,17 +184,17 @@ void e_web_view_set_selected_uri (EWebView *web_view, const gchar * e_web_view_get_cursor_image_src (EWebView *web_view); void e_web_view_set_cursor_image_src (EWebView *web_view, const gchar *src_uri); -GtkAction * e_web_view_get_open_proxy (EWebView *web_view); +EUIAction * e_web_view_get_open_proxy (EWebView *web_view); void e_web_view_set_open_proxy (EWebView *web_view, - GtkAction *open_proxy); + EUIAction *open_proxy); GtkTargetList * e_web_view_get_paste_target_list (EWebView *web_view); -GtkAction * e_web_view_get_print_proxy (EWebView *web_view); +EUIAction * e_web_view_get_print_proxy (EWebView *web_view); void e_web_view_set_print_proxy (EWebView *web_view, - GtkAction *print_proxy); -GtkAction * e_web_view_get_save_as_proxy (EWebView *web_view); + EUIAction *print_proxy); +EUIAction * e_web_view_get_save_as_proxy (EWebView *web_view); void e_web_view_set_save_as_proxy (EWebView *web_view, - GtkAction *save_as_proxy); + EUIAction *save_as_proxy); void e_web_view_get_last_popup_place (EWebView *web_view, gchar **out_iframe_src, gchar **out_iframe_id, @@ -202,9 +205,9 @@ void e_web_view_add_highlight (EWebView *web_view, void e_web_view_clear_highlights (EWebView *web_view); void e_web_view_update_highlights (EWebView *web_view); void e_web_view_disable_highlights (EWebView *web_view); -GtkAction * e_web_view_get_action (EWebView *web_view, +EUIAction * e_web_view_get_action (EWebView *web_view, const gchar *action_name); -GtkActionGroup *e_web_view_get_action_group (EWebView *web_view, +EUIActionGroup *e_web_view_get_action_group (EWebView *web_view, const gchar *group_name); void e_web_view_copy_clipboard (EWebView *web_view); void e_web_view_cut_clipboard (EWebView *web_view); @@ -217,8 +220,7 @@ void e_web_view_unselect_all (EWebView *web_view); void e_web_view_zoom_100 (EWebView *web_view); void e_web_view_zoom_in (EWebView *web_view); void e_web_view_zoom_out (EWebView *web_view); -GtkUIManager * e_web_view_get_ui_manager (EWebView *web_view); -GtkWidget * e_web_view_get_popup_menu (EWebView *web_view); +EUIManager * e_web_view_get_ui_manager (EWebView *web_view); void e_web_view_show_popup_menu (EWebView *web_view, GdkEvent *event); EActivity * e_web_view_new_activity (EWebView *web_view); diff --git a/src/e-util/test-html-editor-units-utils.c b/src/e-util/test-html-editor-units-utils.c index 0ed746be93..edab71dd5c 100644 --- a/src/e-util/test-html-editor-units-utils.c +++ b/src/e-util/test-html-editor-units-utils.c @@ -741,11 +741,15 @@ test_utils_html_equal (TestFixture *fixture, script = e_web_view_jsc_printf_script ( "var EvoEditorTest = {};\n" - "EvoEditorTest.fixupBlockquotes = function(parent) {\n" + "EvoEditorTest.fixupElems = function(parent) {\n" " var ii, elems = parent.getElementsByTagName(\"BLOCKQUOTE\");\n" " for (ii = 0; ii < elems.length; ii++) {\n" " elems[ii].removeAttribute(\"spellcheck\");\n" " }\n" + " elems = parent.getElementsByTagName(\"STYLE\");\n" + " for (ii = elems.length; ii--;) {\n" + " elems[ii].remove();\n" + " }\n" "}\n" "EvoEditorTest.isHTMLEqual = function(html1, html2) {\n" " var elem1, elem2;\n" @@ -753,8 +757,8 @@ test_utils_html_equal (TestFixture *fixture, " elem2 = document.createElement(\"testHtmlEqual\");\n" " elem1.innerHTML = html1.replace(/ /g, \" \").replace(/ /g, \" \");\n" " elem2.innerHTML = html2.replace(/ /g, \" \").replace(/ /g, \" \");\n" - " EvoEditorTest.fixupBlockquotes(elem1);\n" - " EvoEditorTest.fixupBlockquotes(elem2);\n" + " EvoEditorTest.fixupElems(elem1);\n" + " EvoEditorTest.fixupElems(elem2);\n" " elem1.normalize();\n" " elem2.normalize();\n" " return elem1.isEqualNode(elem2);\n" @@ -929,7 +933,7 @@ static gboolean test_utils_execute_action (TestFixture *fixture, const gchar *action_name) { - GtkAction *action; + EUIAction *action; g_return_val_if_fail (fixture != NULL, FALSE); g_return_val_if_fail (E_IS_HTML_EDITOR (fixture->editor), FALSE); @@ -937,7 +941,11 @@ test_utils_execute_action (TestFixture *fixture, action = e_html_editor_get_action (fixture->editor, action_name); if (action) { - gtk_action_activate (action); + GVariant *target; + + target = e_ui_action_ref_target (action); + g_action_activate (G_ACTION (action), target); + g_clear_pointer (&target, g_variant_unref); } else { g_warning ("%s: Failed to find action '%s'", G_STRFUNC, action_name); return FALSE; diff --git a/src/e-util/test-html-editor-units.c b/src/e-util/test-html-editor-units.c index cb31f7bb88..7739677fc9 100644 --- a/src/e-util/test-html-editor-units.c +++ b/src/e-util/test-html-editor-units.c @@ -3522,7 +3522,9 @@ test_link_insert_dialog (TestFixture *fixture) "type:a link example: \n" "action:insert-link\n" "type:http://www.gnome.org\n" - "seq:n\n", + "seq:A\n" /* Alt+A to press the "Add" button in the popover */ + "type:a\n" + "seq:a\n", HTML_PREFIX "
a link example: http://www.gnome.org
" HTML_SUFFIX, "a link example: http://www.gnome.org\n")) g_test_fail (); @@ -3531,13 +3533,17 @@ test_link_insert_dialog (TestFixture *fixture) static void test_link_insert_dialog_selection (TestFixture *fixture) { + test_utils_fixture_change_setting_string (fixture, "org.gnome.evolution.mail", "html-link-to-text", "none"); + if (!test_utils_run_simple_test (fixture, "mode:html\n" "type:a link example: GNOME\n" "seq:CSlsc\n" "action:insert-link\n" "type:http://www.gnome.org\n" - "seq:n\n", + "seq:A\n" /* Alt+A to press the "Add" button in the popover */ + "type:a\n" + "seq:a\n", HTML_PREFIX "
a link example: GNOME
" HTML_SUFFIX, "a link example: GNOME\n")) g_test_fail (); @@ -3557,6 +3563,8 @@ test_link_insert_typed (TestFixture *fixture) static void test_link_insert_typed_change_description (TestFixture *fixture) { + test_utils_fixture_change_setting_string (fixture, "org.gnome.evolution.mail", "html-link-to-text", "none"); + if (!test_utils_run_simple_test (fixture, "mode:html\n" "type:www.gnome.org \n" @@ -3566,7 +3574,9 @@ test_link_insert_typed_change_description (TestFixture *fixture) "type:D\n" "seq:a\n" "type:GNOME\n" - "seq:n\n", + "seq:A\n" /* Alt+A to press the "Update" button in the popover */ + "type:a\n" + "seq:a\n", HTML_PREFIX "" HTML_SUFFIX, "GNOME \n")) g_test_fail (); @@ -3591,6 +3601,8 @@ test_link_insert_dialog_remove_link (TestFixture *fixture) static void test_link_insert_typed_append (TestFixture *fixture) { + test_utils_fixture_change_setting_string (fixture, "org.gnome.evolution.mail", "html-link-to-text", "none"); + if (!test_utils_run_simple_test (fixture, "mode:html\n" "type:www.gnome.org \n" @@ -3604,6 +3616,8 @@ test_link_insert_typed_append (TestFixture *fixture) static void test_link_insert_typed_remove (TestFixture *fixture) { + test_utils_fixture_change_setting_string (fixture, "org.gnome.evolution.mail", "html-link-to-text", "none"); + if (!test_utils_run_simple_test (fixture, "mode:html\n" "type:www.gnome.org \n" diff --git a/src/e-util/test-html-editor.c b/src/e-util/test-html-editor.c index f8a9bb8cf6..6f103e9907 100644 --- a/src/e-util/test-html-editor.c +++ b/src/e-util/test-html-editor.c @@ -31,41 +31,6 @@ which prints a constructed message, like within the message preview. */ /* #define ENABLE_PRINT */ -static const gchar *file_ui = -"\n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -#ifdef ENABLE_PRINT -" \n" -" \n" -" \n" -#endif /* ENABLE_PRINT */ -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -""; - -static const gchar *view_ui = -"\n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -""; - enum { GET_CONTENT_PLAIN, GET_CONTENT_HTML, @@ -291,32 +256,52 @@ view_source_dialog (EHTMLEditor *editor, } static void -action_new_editor_cb (GtkAction *action, - EHTMLEditor *editor) +action_new_editor_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + create_new_editor (); } #ifdef ENABLE_PRINT static void -action_print_cb (GtkAction *action, - EHTMLEditor *editor) +action_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + print (editor, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG); } static void -action_print_preview_cb (GtkAction *action, - EHTMLEditor *editor) +action_print_preview_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + print (editor, GTK_PRINT_OPERATION_ACTION_PREVIEW); } #endif /* ENABLE_PRINT */ static void -action_quit_cb (GtkAction *action, - EHTMLEditor *editor) +action_quit_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + gtk_main_quit (); } @@ -333,12 +318,16 @@ html_editor_save_done_cb (GObject *source_object, } static void -action_save_cb (GtkAction *action, - EHTMLEditor *editor) +action_save_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; const gchar *filename; gboolean as_html; + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + if (e_html_editor_get_filename (editor) == NULL) if (save_dialog (editor) == GTK_RESPONSE_CANCEL) return; @@ -350,12 +339,16 @@ action_save_cb (GtkAction *action, } static void -action_save_as_cb (GtkAction *action, - EHTMLEditor *editor) +action_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; const gchar *filename; gboolean as_html; + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + if (save_dialog (editor) == GTK_RESPONSE_CANCEL) return; @@ -366,49 +359,77 @@ action_save_as_cb (GtkAction *action, } static void -action_toggle_editor (GtkAction *action, - EHTMLEditor *editor) +action_toggle_editor (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + cnt_editor = e_html_editor_get_content_editor (editor); e_content_editor_set_editable (cnt_editor, !e_content_editor_is_editable (cnt_editor)); } static void -action_view_html_output (GtkAction *action, - EHTMLEditor *editor) +action_view_html_output (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + view_source_dialog (editor, _("HTML Output"), GET_CONTENT_HTML, FALSE); } static void -action_view_html_source (GtkAction *action, - EHTMLEditor *editor) +action_view_html_source (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + view_source_dialog (editor, _("HTML Source"), GET_CONTENT_HTML, TRUE); } static void -action_view_plain_source (GtkAction *action, - EHTMLEditor *editor) +action_view_plain_source (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + view_source_dialog (editor, _("Plain Source"), GET_CONTENT_PLAIN, FALSE); } static void -action_view_draft_source (GtkAction *action, - EHTMLEditor *editor) +action_view_draft_source (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EHTMLEditor *editor = user_data; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); + view_source_dialog (editor, _("Draft"), GET_CONTENT_DRAFT, TRUE); } static void -action_view_inspector (GtkAction *action, - EHTMLEditor *editor) +action_view_inspector (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - WebKitWebInspector *inspector; + EHTMLEditor *editor = user_data; EContentEditor *cnt_editor; + WebKitWebInspector *inspector; + + g_return_if_fail (E_IS_HTML_EDITOR (editor)); cnt_editor = e_html_editor_get_content_editor (editor); if (WEBKIT_IS_WEB_VIEW (cnt_editor)) { @@ -419,111 +440,6 @@ action_view_inspector (GtkAction *action, } } -static GtkActionEntry file_entries[] = { - { "new-editor", - "document-new", - N_("_New editor"), - "N", - NULL, - G_CALLBACK (action_new_editor_cb) }, - -#ifdef ENABLE_PRINT - { "print", - "document-print", - N_("_Print…"), - "p", - NULL, - G_CALLBACK (action_print_cb) }, - - { "print-preview", - "document-print-preview", - N_("Print Pre_view"), - "p", - NULL, - G_CALLBACK (action_print_preview_cb) }, -#endif /* ENABLE_PRINT */ - - { "quit", - "application-exit", - N_("_Quit"), - NULL, - NULL, - G_CALLBACK (action_quit_cb) }, - - { "save", - "document-save", - N_("_Save"), - NULL, - NULL, - G_CALLBACK (action_save_cb) }, - - { "save-as", - "document-save-as", - N_("Save _As…"), - NULL, - NULL, - G_CALLBACK (action_save_as_cb) }, - - { "disable-editor", - NULL, - N_("Disable/Enable Editor"), - NULL, - NULL, - G_CALLBACK (action_toggle_editor) }, - - { "file-menu", - NULL, - N_("_File"), - NULL, - NULL, - NULL } -}; - -static GtkActionEntry view_entries[] = { - - { "view-html-output", - NULL, - N_("HTML _Output"), - NULL, - NULL, - G_CALLBACK (action_view_html_output) }, - - { "view-html-source", - NULL, - N_("_HTML Source"), - NULL, - NULL, - G_CALLBACK (action_view_html_source) }, - - { "view-plain-source", - NULL, - N_("_Plain Source"), - NULL, - NULL, - G_CALLBACK (action_view_plain_source) }, - - { "view-draft-source", - NULL, - N_("_Draft Source"), - NULL, - NULL, - G_CALLBACK (action_view_draft_source) }, - - { "view-webkit-inspector", - NULL, - N_("Inspector"), - NULL, - "I", - G_CALLBACK (action_view_inspector) }, - - { "view-menu", - NULL, - N_("_View"), - NULL, - NULL, - NULL } -}; - static guint glob_editors = 0; static const gchar *glob_prefill_body = NULL; @@ -543,10 +459,144 @@ create_new_editor_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { - GtkActionGroup *action_group; - GtkUIManager *manager; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + #ifdef ENABLE_PRINT + "" + "" + "" + #endif /* ENABLE_PRINT */ + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry file_entries[] = { + { "new-editor", + "document-new", + N_("_New editor"), + "n", + NULL, + action_new_editor_cb, NULL, NULL, NULL }, + + #ifdef ENABLE_PRINT + { "print", + "document-print", + N_("_Print…"), + "p", + NULL, + action_print_cb, NULL, NULL, NULL }, + + { "print-preview", + "document-print-preview", + N_("Print Pre_view"), + "p", + NULL, + action_print_preview_cb, NULL, NULL, NULL }, + #endif /* ENABLE_PRINT */ + + { "quit", + "application-exit", + N_("_Quit"), + NULL, + NULL, + action_quit_cb, NULL, NULL, NULL }, + + { "save", + "document-save", + N_("_Save"), + NULL, + NULL, + action_save_cb, NULL, NULL, NULL }, + + { "save-as", + "document-save-as", + N_("Save _As…"), + NULL, + NULL, + action_save_as_cb, NULL, NULL, NULL }, + + { "disable-editor", + NULL, + N_("Disable/Enable Editor"), + NULL, + NULL, + action_toggle_editor, NULL, NULL, NULL }, + + { "file-menu", + NULL, + N_("_File"), + NULL, + NULL, + NULL } + }; + + static const EUIActionEntry view_entries[] = { + + { "view-html-output", + NULL, + N_("HTML _Output"), + NULL, + NULL, + action_view_html_output, NULL, NULL, NULL }, + + { "view-html-source", + NULL, + N_("_HTML Source"), + NULL, + NULL, + action_view_html_source, NULL, NULL, NULL }, + + { "view-plain-source", + NULL, + N_("_Plain Source"), + NULL, + NULL, + action_view_plain_source, NULL, NULL, NULL }, + + { "view-draft-source", + NULL, + N_("_Draft Source"), + NULL, + NULL, + action_view_draft_source, NULL, NULL, NULL }, + + { "view-webkit-inspector", + NULL, + N_("Inspector"), + NULL, + "I", + action_view_inspector, NULL, NULL, NULL }, + + { "view-menu", + NULL, + N_("_View"), + NULL, + NULL, + NULL, NULL, NULL, NULL } + }; + + EUIManager *ui_manager; GtkWidget *container; GtkWidget *widget; + GObject *ui_object; EHTMLEditor *editor; EContentEditor *cnt_editor; EFocusTracker *focus_tracker; @@ -562,6 +612,14 @@ create_new_editor_cb (GObject *source_object, editor = E_HTML_EDITOR (widget); cnt_editor = e_html_editor_get_content_editor (editor); + ui_manager = e_html_editor_get_ui_manager (editor); + + e_ui_manager_freeze (ui_manager); + + e_ui_manager_add_actions (ui_manager, "file", GETTEXT_PACKAGE, file_entries, G_N_ELEMENTS (file_entries), editor); + e_ui_manager_add_actions_with_eui_data (ui_manager, "view", GETTEXT_PACKAGE, view_entries, G_N_ELEMENTS (view_entries), editor, eui); + + e_ui_manager_thaw (ui_manager); g_object_set (G_OBJECT (editor), "halign", GTK_ALIGN_FILL, @@ -609,11 +667,13 @@ create_new_editor_cb (GObject *source_object, container = widget; - widget = e_html_editor_get_managed_widget (editor, "/main-menu"); + ui_object = e_html_editor_get_ui_object (editor, E_HTML_EDITOR_UI_OBJECT_MAIN_MENU); + widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (ui_object)); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); gtk_widget_show (widget); - widget = e_html_editor_get_managed_widget (editor, "/main-toolbar"); + ui_object = e_html_editor_get_ui_object (editor, E_HTML_EDITOR_UI_OBJECT_MAIN_TOOLBAR); + widget = GTK_WIDGET (ui_object); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); gtk_widget_show (widget); @@ -623,39 +683,13 @@ create_new_editor_cb (GObject *source_object, gtk_widget_grab_focus (GTK_WIDGET (cnt_editor)); - manager = e_html_editor_get_ui_manager (editor); - - gtk_ui_manager_add_ui_from_string (manager, file_ui, -1, &error); - handle_error (&error); - - gtk_ui_manager_add_ui_from_string (manager, view_ui, -1, &error); - handle_error (&error); - - action_group = gtk_action_group_new ("file"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, file_entries, - G_N_ELEMENTS (file_entries), editor); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - - action_group = gtk_action_group_new ("view"); - gtk_action_group_set_translation_domain ( - action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions ( - action_group, view_entries, - G_N_ELEMENTS (view_entries), editor); - gtk_ui_manager_insert_action_group (manager, action_group, 0); - if (!WEBKIT_IS_WEB_VIEW (cnt_editor)) { - GtkAction *action; + EUIAction *action; action = e_html_editor_get_action (editor, "view-webkit-inspector"); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); } - gtk_ui_manager_ensure_update (manager); - if (glob_prefill_body) { e_content_editor_insert_content (cnt_editor, glob_prefill_body, E_CONTENT_EDITOR_INSERT_REPLACE_ALL | (*glob_prefill_body == '<' ? E_CONTENT_EDITOR_INSERT_TEXT_HTML : E_CONTENT_EDITOR_INSERT_TEXT_PLAIN)); diff --git a/src/e-util/test-tree-view-frame.c b/src/e-util/test-tree-view-frame.c index fafbc2ffe2..3fbebda7b7 100644 --- a/src/e-util/test-tree-view-frame.c +++ b/src/e-util/test-tree-view-frame.c @@ -18,7 +18,7 @@ delete_event_cb (GtkWidget *widget, static void action_add_cb (ETreeViewFrame *tree_view_frame, - GtkAction *action) + EUIAction *action) { GtkTreeView *tree_view; GtkTreeModel *tree_model; @@ -49,7 +49,7 @@ action_add_cb (ETreeViewFrame *tree_view_frame, static void action_remove_cb (ETreeViewFrame *tree_view_frame, - GtkAction *action) + EUIAction *action) { GtkTreeView *tree_view; GtkTreeModel *tree_model; @@ -81,7 +81,7 @@ action_remove_cb (ETreeViewFrame *tree_view_frame, static void update_toolbar_actions_cb (ETreeViewFrame *tree_view_frame) { - GtkAction *action; + EUIAction *action; GtkTreeView *tree_view; GtkTreeSelection *selection; gint n_selected_rows; @@ -93,7 +93,7 @@ update_toolbar_actions_cb (ETreeViewFrame *tree_view_frame) action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_REMOVE); - gtk_action_set_sensitive (action, n_selected_rows > 0); + e_ui_action_set_sensitive (action, n_selected_rows > 0); } static void diff --git a/src/mail/CMakeLists.txt b/src/mail/CMakeLists.txt index af3660c12c..4b46265dbb 100644 --- a/src/mail/CMakeLists.txt +++ b/src/mail/CMakeLists.txt @@ -70,7 +70,6 @@ set(SOURCES e-mail-folder-tweaks.c e-mail-free-form-exp.c e-mail-junk-options.c - e-mail-label-action.c e-mail-label-dialog.c e-mail-label-list-store.c e-mail-label-manager.c @@ -163,7 +162,6 @@ set(HEADERS e-mail-folder-tweaks.h e-mail-free-form-exp.h e-mail-junk-options.h - e-mail-label-action.h e-mail-label-dialog.h e-mail-label-list-store.h e-mail-label-manager.h diff --git a/src/mail/e-mail-browser.c b/src/mail/e-mail-browser.c index 7100971148..930fae34d5 100644 --- a/src/mail/e-mail-browser.c +++ b/src/mail/e-mail-browser.c @@ -41,13 +41,14 @@ struct _EMailBrowserPrivate { EMailBackend *backend; - GtkUIManager *ui_manager; + EUIManager *ui_manager; EFocusTracker *focus_tracker; EMailFormatterMode display_mode; EAutomaticActionPolicy close_on_reply_policy; EMenuBar *menu_bar; + GtkWidget *menu_button; /* owned by menu_bar */ GtkWidget *main_toolbar; GtkWidget *message_list; GtkWidget *preview_pane; @@ -73,33 +74,10 @@ enum { PROP_MARK_SEEN_ALWAYS, PROP_SHOW_DELETED, PROP_SHOW_JUNK, - PROP_UI_MANAGER, PROP_DELETE_SELECTS_PREVIOUS, PROP_CLOSE_ON_DELETE_OR_JUNK }; -/* This is too trivial to put in a file. - * It gets merged with the EMailReader UI. */ -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; static void e_mail_browser_reader_init (EMailReaderInterface *iface); @@ -110,29 +88,36 @@ G_DEFINE_TYPE_WITH_CODE (EMailBrowser, e_mail_browser, GTK_TYPE_WINDOW, G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)) static void -action_close_cb (GtkAction *action, - EMailBrowser *browser) +action_close_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailBrowser *browser = user_data; + e_mail_browser_close (browser); } static void -action_search_web_cb (GtkAction *action, - EMailReader *reader) +action_search_web_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *display; - GtkAction *wv_action; + EUIAction *wv_action; display = e_mail_reader_get_mail_display (reader); wv_action = e_web_view_get_action (E_WEB_VIEW (display), "search-web"); - gtk_action_activate (wv_action); + g_action_activate (G_ACTION (wv_action), NULL); } static void -action_mail_smart_backward_cb (GtkAction *action, - EMailReader *reader) +action_mail_smart_backward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *mail_display; mail_display = e_mail_reader_get_mail_display (reader); @@ -141,9 +126,11 @@ action_mail_smart_backward_cb (GtkAction *action, } static void -action_mail_smart_forward_cb (GtkAction *action, - EMailReader *reader) +action_mail_smart_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *mail_display; mail_display = e_mail_reader_get_mail_display (reader); @@ -151,169 +138,6 @@ action_mail_smart_forward_cb (GtkAction *action, e_mail_display_process_magic_spacebar (mail_display, TRUE); } -static GtkActionEntry mail_browser_entries[] = { - - { "close", - "window-close", - N_("_Close"), - "w", - N_("Close this window"), - G_CALLBACK (action_close_cb) }, - - { "copy-clipboard", - "edit-copy", - N_("_Copy"), - "c", - N_("Copy the selection"), - NULL }, /* Handled by EFocusTracker */ - - { "cut-clipboard", - "edit-cut", - N_("Cu_t"), - "x", - N_("Cut the selection"), - NULL }, /* Handled by EFocusTracker */ - - { "paste-clipboard", - "edit-paste", - N_("_Paste"), - "v", - N_("Paste the clipboard"), - NULL }, /* Handled by EFocusTracker */ - - { "select-all", - "edit-select-all", - N_("Select _All"), - NULL, - N_("Select all text"), - NULL }, /* Handled by EFocusTracker */ - - { "search-web", - NULL, - N_("Search _Web…"), - NULL, - N_("Search the Web with the selected text"), - G_CALLBACK (action_search_web_cb) }, - - /*** Menus ***/ - - { "file-menu", - NULL, - N_("_File"), - NULL, - NULL, - NULL }, - - { "edit-menu", - NULL, - N_("_Edit"), - NULL, - NULL, - NULL }, - - { "view-menu", - NULL, - N_("_View"), - NULL, - NULL, - NULL } -}; - -static GtkActionEntry mail_entries[] = { - - { "mail-smart-backward", - NULL, - NULL, - NULL, - NULL, - G_CALLBACK (action_mail_smart_backward_cb) }, - - { "mail-smart-forward", - NULL, - NULL, - NULL, - NULL, - G_CALLBACK (action_mail_smart_forward_cb) }, -}; - -static EPopupActionEntry mail_browser_popup_entries[] = { - - { "popup-copy-clipboard", - NULL, - "copy-clipboard" }, - - { "popup-search-web", - NULL, - "search-web" } -}; - -static void -mail_browser_menu_item_select_cb (EMailBrowser *browser, - GtkWidget *widget) -{ - GtkAction *action; - GtkActivatable *activatable; - GtkStatusbar *statusbar; - const gchar *tooltip; - guint context_id; - gpointer data; - - activatable = GTK_ACTIVATABLE (widget); - action = gtk_activatable_get_related_action (activatable); - tooltip = gtk_action_get_tooltip (action); - - data = g_object_get_data (G_OBJECT (widget), "context-id"); - context_id = GPOINTER_TO_UINT (data); - - if (tooltip == NULL) - return; - - statusbar = GTK_STATUSBAR (browser->priv->statusbar); - gtk_statusbar_push (statusbar, context_id, tooltip); -} - -static void -mail_browser_menu_item_deselect_cb (EMailBrowser *browser, - GtkWidget *menu_item) -{ - GtkStatusbar *statusbar; - guint context_id; - gpointer data; - - data = g_object_get_data (G_OBJECT (menu_item), "context-id"); - context_id = GPOINTER_TO_UINT (data); - - statusbar = GTK_STATUSBAR (browser->priv->statusbar); - gtk_statusbar_pop (statusbar, context_id); -} - -static void -mail_browser_connect_proxy_cb (EMailBrowser *browser, - GtkAction *action, - GtkWidget *proxy) -{ - GtkStatusbar *statusbar; - guint context_id; - - if (!GTK_IS_MENU_ITEM (proxy)) - return; - - statusbar = GTK_STATUSBAR (browser->priv->statusbar); - context_id = gtk_statusbar_get_context_id (statusbar, G_STRFUNC); - - g_object_set_data ( - G_OBJECT (proxy), "context-id", - GUINT_TO_POINTER (context_id)); - - g_signal_connect_swapped ( - proxy, "select", - G_CALLBACK (mail_browser_menu_item_select_cb), browser); - - g_signal_connect_swapped ( - proxy, "deselect", - G_CALLBACK (mail_browser_menu_item_deselect_cb), browser); -} - static void mail_browser_message_selected_cb (EMailBrowser *browser, const gchar *uid) @@ -398,11 +222,10 @@ mail_browser_popup_event_cb (EMailBrowser *browser, if (e_web_view_get_cursor_image_src (web_view) != NULL) return FALSE; - menu = e_mail_reader_get_popup_menu (reader); - state = e_mail_reader_check_state (reader); e_mail_reader_update_actions (reader, state); + menu = e_mail_reader_get_popup_menu (reader); gtk_menu_popup_at_pointer (menu, event); return TRUE; @@ -450,44 +273,27 @@ mail_browser_close_on_reply_response_cb (EAlert *alert, } static gboolean -mail_browser_key_press_event_cb (GtkWindow *mail_browser, - GdkEventKey *event) +mail_browser_ui_manager_create_item_cb (EUIManager *manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) { - GtkWidget *focused; - EMailDisplay *mail_display; + EMailBrowser *self = user_data; - mail_display = e_mail_reader_get_mail_display (E_MAIL_READER (mail_browser)); + g_return_val_if_fail (E_IS_MAIL_BROWSER (self), FALSE); - if (!event || (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0 || - event->keyval == GDK_KEY_Tab || - event->keyval == GDK_KEY_Return || - event->keyval == GDK_KEY_KP_Tab || - event->keyval == GDK_KEY_KP_Enter) - return event && e_mail_display_need_key_event (mail_display, event); + if (for_kind != E_UI_ELEMENT_KIND_HEADERBAR || + g_strcmp0 (g_action_get_name (G_ACTION (action)), "menu-button") != 0) + return FALSE; - focused = gtk_window_get_focus (mail_browser); + if (self->priv->menu_button) + *out_item = G_OBJECT (g_object_ref (self->priv->menu_button)); + else + *out_item = NULL; - if (focused && (GTK_IS_ENTRY (focused) || GTK_IS_EDITABLE (focused) || - (GTK_IS_TREE_VIEW (focused) && gtk_tree_view_get_search_column (GTK_TREE_VIEW (focused)) >= 0))) { - gtk_widget_event (focused, (GdkEvent *) event); - return event->keyval != GDK_KEY_Escape; - } - - if (e_web_view_get_need_input (E_WEB_VIEW (mail_display)) && - gtk_widget_has_focus (GTK_WIDGET (mail_display))) { - gtk_widget_event (GTK_WIDGET (mail_display), (GdkEvent *) event); - return TRUE; - } - - if (e_mail_display_need_key_event (mail_display, event)) - return TRUE; - - if (event->keyval == GDK_KEY_Escape) { - e_mail_browser_close (E_MAIL_BROWSER (mail_browser)); - return TRUE; - } - - return FALSE; + return TRUE; } static void @@ -507,56 +313,6 @@ mail_browser_set_display_mode (EMailBrowser *browser, browser->priv->display_mode = display_mode; } -static GtkWidget * -mail_browser_construct_header_bar (EMailReader *reader, - GtkWidget *menu_button) -{ - GtkWidget *widget; - GtkAction *action; - GtkHeaderBar *header_bar; - const gchar *action_name; - - widget = e_header_bar_new (); - gtk_widget_show (widget); - header_bar = GTK_HEADER_BAR (widget); - - if (menu_button) - e_header_bar_pack_end (E_HEADER_BAR (header_bar), menu_button, G_MAXUINT); - - action_name = "mail-forward"; - action = e_mail_reader_get_action (reader, action_name); - widget = e_header_bar_button_new (_("Forward"), action); - gtk_widget_set_name (widget, "e-mail-shell-view-forward"); - e_header_bar_button_take_menu ( - E_HEADER_BAR_BUTTON (widget), - e_mail_reader_create_forward_menu (reader)); - gtk_widget_show (widget); - - e_header_bar_pack_end (E_HEADER_BAR (header_bar), widget, 2); - - action_name = "mail-reply-group"; - action = e_mail_reader_get_action (reader, action_name); - widget = e_header_bar_button_new (_("Group Reply"), action); - gtk_widget_set_name (widget, "e-mail-shell-view-reply-group"); - gtk_widget_show (widget); - - e_header_bar_button_take_menu ( - E_HEADER_BAR_BUTTON (widget), - e_mail_reader_create_reply_menu (reader)); - - e_header_bar_pack_end (E_HEADER_BAR (header_bar), widget, 1); - - action_name = "mail-reply-sender"; - action = e_mail_reader_get_action (reader, action_name); - widget = e_header_bar_button_new (_("Reply"), action); - gtk_widget_set_name (widget, "e-mail-shell-view-reply-sender"); - gtk_widget_show (widget); - - e_header_bar_pack_end (E_HEADER_BAR (header_bar), widget, 1); - - return GTK_WIDGET (header_bar); -} - static void mail_browser_set_property (GObject *object, guint property_id, @@ -704,13 +460,6 @@ mail_browser_get_property (GObject *object, E_MAIL_BROWSER (object))); return; - case PROP_UI_MANAGER: - g_value_set_object ( - value, - e_mail_browser_get_ui_manager ( - E_MAIL_BROWSER (object))); - return; - case PROP_MARK_SEEN_ALWAYS: g_value_set_boolean ( value, @@ -772,6 +521,104 @@ mail_browser_dispose (GObject *object) static void mail_browser_constructed (GObject *object) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry mail_browser_entries[] = { + + { "close", + "window-close", + N_("_Close"), + "w", + N_("Close this window"), + action_close_cb, NULL, NULL, NULL }, + + { "copy-clipboard", + "edit-copy", + N_("_Copy"), + "c", + N_("Copy the selection"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "cut-clipboard", + "edit-cut", + N_("Cu_t"), + "x", + N_("Cut the selection"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "paste-clipboard", + "edit-paste", + N_("_Paste"), + "v", + N_("Paste the clipboard"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "select-all", + "edit-select-all", + N_("Select _All"), + NULL, + N_("Select all text"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "search-web", + NULL, + N_("Search _Web…"), + NULL, + N_("Search the Web with the selected text"), + action_search_web_cb, NULL, NULL, NULL }, + + /*** Menus ***/ + + { "file-menu", NULL, N_("_File"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "edit-menu", NULL, N_("_Edit"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "view-menu", NULL, N_("_View"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "menu-button", NULL, N_("Menu"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + + static const EUIActionEntry mail_entries[] = { + + { "mail-smart-backward", + "go-up", + "mail smart backward", + "BackSpace", + NULL, + action_mail_smart_backward_cb, NULL, NULL, NULL }, + + { "mail-smart-forward", + "go-down", + "mail smart forward", + "space", + NULL, + action_mail_smart_forward_cb, NULL, NULL, NULL }, + }; + EMailBrowser *browser; EMailReader *reader; EMailBackend *backend; @@ -780,17 +627,11 @@ mail_browser_constructed (GObject *object) EShell *shell; EFocusTracker *focus_tracker; EAttachmentStore *attachment_store; - GtkAccelGroup *accel_group; - GtkActionGroup *action_group; - GtkAction *action, *mail_action; - GtkUIManager *ui_manager; + EUIAction *action, *mail_action; GtkWidget *container; GtkWidget *display; GtkWidget *widget; - GtkWidget *menu_button = NULL; - const gchar *domain; - const gchar *id; - guint merge_id; + GObject *ui_item; /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_browser_parent_class)->constructed (object); @@ -803,11 +644,6 @@ mail_browser_constructed (GObject *object) shell_backend = E_SHELL_BACKEND (backend); shell = e_shell_backend_get_shell (shell_backend); - ui_manager = gtk_ui_manager_new (); - - browser->priv->ui_manager = ui_manager; - domain = GETTEXT_PACKAGE; - gtk_application_add_window ( GTK_APPLICATION (shell), GTK_WINDOW (object)); @@ -825,7 +661,7 @@ mail_browser_constructed (GObject *object) browser->priv->message_list, "message-list-built", G_CALLBACK (mail_browser_message_list_built_cb), object); - display = e_mail_display_new (e_mail_backend_get_remote_content (backend)); + display = e_mail_display_new (e_mail_backend_get_remote_content (backend), E_MAIL_READER (browser)); e_mail_display_set_mode ( E_MAIL_DISPLAY (display), @@ -843,77 +679,42 @@ mail_browser_constructed (GObject *object) browser->priv->preview_pane = g_object_ref (widget); gtk_widget_show (widget); - action_group = gtk_action_group_new ("mail"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, mail_entries, - G_N_ELEMENTS (mail_entries), object); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + gtk_window_add_accel_group (GTK_WINDOW (browser), e_ui_manager_get_accel_group (e_web_view_get_ui_manager (E_WEB_VIEW (display)))); - action_group = gtk_action_group_new (ACTION_GROUP_STANDARD); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, mail_browser_entries, - G_N_ELEMENTS (mail_browser_entries), object); - e_action_group_add_popup_actions ( - action_group, mail_browser_popup_entries, - G_N_ELEMENTS (mail_browser_popup_entries)); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + browser->priv->ui_manager = e_ui_manager_new (); + + g_signal_connect (browser->priv->ui_manager, "create-item", + G_CALLBACK (mail_browser_ui_manager_create_item_cb), browser); + g_signal_connect_swapped (browser->priv->ui_manager, "ignore-accel", + G_CALLBACK (e_mail_reader_ignore_accel), browser); + + e_mail_reader_init (reader); + e_mail_reader_init_ui_data (reader); + + e_ui_manager_add_actions (browser->priv->ui_manager, "mail", NULL, + mail_entries, G_N_ELEMENTS (mail_entries), object); + + e_ui_manager_add_actions_with_eui_data (browser->priv->ui_manager, ACTION_GROUP_STANDARD, NULL, + mail_browser_entries, G_N_ELEMENTS (mail_browser_entries), object, eui); + + action = e_ui_manager_get_action (browser->priv->ui_manager, "close"); + e_ui_action_add_secondary_accel (action, "Escape"); mail_action = e_web_view_get_action (E_WEB_VIEW (display), "search-web"); - action = gtk_action_group_get_action (action_group, "search-web"); + action = e_ui_manager_get_action (browser->priv->ui_manager, "search-web"); e_binding_bind_property ( mail_action, "sensitive", action, "sensitive", G_BINDING_SYNC_CREATE); - /* For easy access. Takes ownership of the reference. */ - g_object_set_data_full ( - object, ACTION_GROUP_STANDARD, - action_group, (GDestroyNotify) g_object_unref); - - action_group = gtk_action_group_new (ACTION_GROUP_SEARCH_FOLDERS); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - - /* For easy access. Takes ownership of the reference. */ - g_object_set_data_full ( - object, ACTION_GROUP_SEARCH_FOLDERS, - action_group, (GDestroyNotify) g_object_unref); - - action_group = gtk_action_group_new (ACTION_GROUP_LABELS); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - - /* For easy access. Takes ownership of the reference. */ - g_object_set_data_full ( - object, ACTION_GROUP_LABELS, - action_group, (GDestroyNotify) g_object_unref); - - e_binding_bind_property ( - display, "need-input", - action_group, "sensitive", - G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); - - e_mail_reader_init (reader, TRUE, TRUE); - - e_load_ui_manager_definition (ui_manager, E_MAIL_READER_UI_DEFINITION); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL); - - merge_id = gtk_ui_manager_new_merge_id (ui_manager); - e_mail_reader_create_charset_menu (reader, ui_manager, merge_id); - - accel_group = gtk_ui_manager_get_accel_group (ui_manager); - gtk_window_add_accel_group (GTK_WINDOW (object), accel_group); - - g_signal_connect_swapped ( - ui_manager, "connect-proxy", - G_CALLBACK (mail_browser_connect_proxy_cb), object); + e_ui_manager_set_action_groups_widget (browser->priv->ui_manager, GTK_WIDGET (browser)); + gtk_window_add_accel_group (GTK_WINDOW (browser), e_ui_manager_get_accel_group (browser->priv->ui_manager)); /* Configure an EFocusTracker to manage selection actions. */ focus_tracker = e_focus_tracker_new (GTK_WINDOW (object)); + action = e_mail_reader_get_action (reader, "cut-clipboard"); e_focus_tracker_set_cut_clipboard_action (focus_tracker, action); action = e_mail_reader_get_action (reader, "copy-clipboard"); @@ -922,6 +723,7 @@ mail_browser_constructed (GObject *object) e_focus_tracker_set_paste_clipboard_action (focus_tracker, action); action = e_mail_reader_get_action (reader, "select-all"); e_focus_tracker_set_select_all_action (focus_tracker, action); + browser->priv->focus_tracker = focus_tracker; /* Construct window widgets. */ @@ -937,33 +739,28 @@ mail_browser_constructed (GObject *object) browser->priv->statusbar = g_object_ref (widget); gtk_widget_show (widget); - widget = gtk_ui_manager_get_widget (ui_manager, "/main-menu"); + ui_item = e_ui_manager_create_item (browser->priv->ui_manager, "main-menu"); + widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (ui_item)); + g_clear_object (&ui_item); + + browser->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (browser), &browser->priv->menu_button); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - browser->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (browser), &menu_button); if (e_util_get_use_header_bar ()) { - widget = mail_browser_construct_header_bar (reader, menu_button); - gtk_window_set_titlebar (GTK_WINDOW (object), widget); + ui_item = e_ui_manager_create_item (browser->priv->ui_manager, "main-headerbar"); + widget = GTK_WIDGET (ui_item); + gtk_window_set_titlebar (GTK_WINDOW (browser), widget); - widget = gtk_ui_manager_get_widget (ui_manager, "/main-toolbar/mail-toolbar-common/mail-reply-sender"); - if (widget) - gtk_widget_destroy (widget); - } else if (menu_button) { - g_object_ref_sink (menu_button); - gtk_widget_destroy (menu_button); + ui_item = e_ui_manager_create_item (browser->priv->ui_manager, "main-toolbar-with-headerbar"); + } else { + ui_item = e_ui_manager_create_item (browser->priv->ui_manager, "main-toolbar-without-headerbar"); } - widget = gtk_ui_manager_get_widget (ui_manager, "/main-toolbar"); + widget = GTK_WIDGET (ui_item); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); browser->priv->main_toolbar = g_object_ref (widget); gtk_widget_show (widget); - gtk_style_context_add_class ( - gtk_widget_get_style_context (widget), - GTK_STYLE_CLASS_PRIMARY_TOOLBAR); - - e_util_setup_toolbar_icon_size (GTK_TOOLBAR (widget), GTK_ICON_SIZE_BUTTON); - attachment_store = e_mail_display_get_attachment_store (E_MAIL_DISPLAY (display)); widget = GTK_WIDGET (e_mail_display_get_attachment_view (E_MAIL_DISPLAY (display))); gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); @@ -980,9 +777,7 @@ mail_browser_constructed (GObject *object) e_attachment_store_transform_num_attachments_to_visible_boolean, NULL, NULL, NULL); - id = "org.gnome.evolution.mail.browser"; - e_plugin_ui_register_manager (ui_manager, id, object); - e_plugin_ui_enable_manager (ui_manager, id); + e_plugin_ui_register_manager (browser->priv->ui_manager, "org.gnome.evolution.mail.browser", object); action = e_mail_reader_get_action (reader, "mail-label-none"); e_binding_bind_property ( @@ -990,41 +785,14 @@ mail_browser_constructed (GObject *object) action, "sensitive", G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); - g_signal_connect ( - browser, "key-press-event", - G_CALLBACK (mail_browser_key_press_event_cb), NULL); - /* WebKitGTK does not support print preview, thus hide the option from the menu; maybe it'll be supported in the future */ action = e_mail_reader_get_action (reader, "mail-print-preview"); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); e_extensible_load_extensions (E_EXTENSIBLE (object)); } -static GtkActionGroup * -mail_browser_get_action_group (EMailReader *reader, - EMailReaderActionGroup group) -{ - const gchar *group_name; - - switch (group) { - case E_MAIL_READER_ACTION_GROUP_STANDARD: - group_name = ACTION_GROUP_STANDARD; - break; - case E_MAIL_READER_ACTION_GROUP_SEARCH_FOLDERS: - group_name = ACTION_GROUP_SEARCH_FOLDERS; - break; - case E_MAIL_READER_ACTION_GROUP_LABELS: - group_name = ACTION_GROUP_LABELS; - break; - default: - g_return_val_if_reached (NULL); - } - - return g_object_get_data (G_OBJECT (reader), group_name); -} - static EMailBackend * mail_browser_get_backend (EMailReader *reader) { @@ -1068,21 +836,12 @@ mail_browser_get_message_list (EMailReader *reader) return self->priv->message_list; } -static GtkMenu * -mail_browser_get_popup_menu (EMailReader *reader) +static EUIManager * +mail_browser_get_ui_manager (EMailReader *reader) { - EMailBrowser *browser; - GtkUIManager *ui_manager; - GtkWidget *widget; + EMailBrowser *self = E_MAIL_BROWSER (reader); - browser = E_MAIL_BROWSER (reader); - ui_manager = e_mail_browser_get_ui_manager (browser); - if (!ui_manager) - return NULL; - - widget = gtk_ui_manager_get_widget (ui_manager, "/mail-preview-popup"); - - return GTK_MENU (widget); + return self->priv->ui_manager; } static EPreviewPane * @@ -1297,17 +1056,6 @@ e_mail_browser_class_init (EMailBrowserClass *class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property ( - object_class, - PROP_UI_MANAGER, - g_param_spec_object ( - "ui-manager", - "UI Manager", - NULL, - GTK_TYPE_UI_MANAGER, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property ( object_class, PROP_CLOSE_ON_DELETE_OR_JUNK, @@ -1324,12 +1072,11 @@ e_mail_browser_class_init (EMailBrowserClass *class) static void e_mail_browser_reader_init (EMailReaderInterface *iface) { - iface->get_action_group = mail_browser_get_action_group; iface->get_backend = mail_browser_get_backend; iface->get_mail_display = mail_browser_get_mail_display; iface->get_hide_deleted = mail_browser_get_hide_deleted; iface->get_message_list = mail_browser_get_message_list; - iface->get_popup_menu = mail_browser_get_popup_menu; + iface->get_ui_manager = mail_browser_get_ui_manager; iface->get_preview_pane = mail_browser_get_preview_pane; iface->get_window = mail_browser_get_window; iface->set_message = mail_browser_set_message; @@ -1489,14 +1236,6 @@ e_mail_browser_set_show_junk (EMailBrowser *browser, g_object_notify (G_OBJECT (browser), "show-junk"); } -GtkUIManager * -e_mail_browser_get_ui_manager (EMailBrowser *browser) -{ - g_return_val_if_fail (E_IS_MAIL_BROWSER (browser), NULL); - - return browser->priv->ui_manager; -} - gboolean e_mail_browser_get_close_on_delete_or_junk (EMailBrowser *browser) { diff --git a/src/mail/e-mail-browser.h b/src/mail/e-mail-browser.h index a03be100cc..6de074fc9c 100644 --- a/src/mail/e-mail-browser.h +++ b/src/mail/e-mail-browser.h @@ -81,7 +81,6 @@ void e_mail_browser_set_show_deleted (EMailBrowser *browser, gboolean e_mail_browser_get_show_junk (EMailBrowser *browser); void e_mail_browser_set_show_junk (EMailBrowser *browser, gboolean show_junk); -GtkUIManager * e_mail_browser_get_ui_manager (EMailBrowser *browser); gboolean e_mail_browser_get_close_on_delete_or_junk (EMailBrowser *browser); void e_mail_browser_set_close_on_delete_or_junk diff --git a/src/mail/e-mail-display.c b/src/mail/e-mail-display.c index 900807ddc8..3d4e682c4c 100644 --- a/src/mail/e-mail-display.c +++ b/src/mail/e-mail-display.c @@ -40,6 +40,7 @@ #include "e-http-request.h" #include "e-mail-display-popup-extension.h" #include "e-mail-notes.h" +#include "e-mail-reader.h" #include "e-mail-request.h" #include "e-mail-ui-session.h" #include "em-composer-utils.h" @@ -64,12 +65,13 @@ struct _EMailDisplayPrivate { EAttachmentView *attachment_view; GHashTable *attachment_flags; /* EAttachment * ~> guint bit-or of EAttachmentFlags */ GHashTable *cid_attachments; /* gchar *cid ~> EAttachemnt *; these are not part of the attachment store */ - guint attachment_inline_ui_id; - guint open_with_ui_id; - GtkActionGroup *attachment_inline_group; - GtkActionGroup *attachment_accel_action_group; - GtkAccelGroup *attachment_accel_group; + GWeakRef mail_reader_weakref; + + EUIActionGroup *attachment_inline_group; + EUIActionGroup *attachment_accel_action_group; + GMenu *open_with_apps_menu; + GHashTable *open_with_apps_hash; /* gchar *action_parameter ~> OpenWithData * */ EMailPartList *part_list; EMailFormatterMode mode; @@ -107,7 +109,8 @@ enum { PROP_HEADERS_COLLAPSED, PROP_MODE, PROP_PART_LIST, - PROP_REMOTE_CONTENT + PROP_REMOTE_CONTENT, + PROP_MAIL_READER }; enum { @@ -125,80 +128,35 @@ G_DEFINE_TYPE_WITH_CODE (EMailDisplay, e_mail_display, E_TYPE_WEB_VIEW, G_ADD_PRIVATE (EMailDisplay) G_IMPLEMENT_INTERFACE (E_TYPE_CID_RESOLVER, e_mail_display_cid_resolver_init)) -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; +typedef struct _OpenWithData { + GAppInfo *app_info; + EAttachment *attachment; +} OpenWithData; -static GtkActionEntry mailto_entries[] = { +static OpenWithData * +open_with_data_new (GAppInfo *app_info, + EAttachment *attachment) +{ + OpenWithData *data; - { "add-to-address-book", - "contact-new", - N_("_Add to Address Book…"), - NULL, - NULL, /* XXX Add a tooltip! */ - NULL /* Handled by EMailReader */ }, + data = g_new0 (OpenWithData, 1); + data->app_info = app_info ? g_object_ref (app_info) : NULL; + data->attachment = g_object_ref (attachment); - { "search-folder-recipient", - NULL, - N_("_To This Address"), - NULL, - NULL, /* XXX Add a tooltip! */ - NULL /* Handled by EMailReader */ }, + return data; +} - { "search-folder-sender", - NULL, - N_("_From This Address"), - NULL, - NULL, /* XXX Add a tooltip! */ - NULL /* Handled by EMailReader */ }, +static void +open_with_data_free (gpointer ptr) +{ + OpenWithData *data = ptr; - { "send-reply", - NULL, - N_("Send _Reply To…"), - NULL, - N_("Send a reply message to this address"), - NULL /* Handled by EMailReader */ }, - - /*** Menus ***/ - - { "search-folder-menu", - "folder-saved-search", - N_("Create Search _Folder"), - NULL, - NULL, - NULL } -}; - -static const gchar *attachment_popup_ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; + if (data) { + g_clear_object (&data->app_info); + g_clear_object (&data->attachment); + g_free (data); + } +} static void e_mail_display_claim_skipped_uri (EMailDisplay *mail_display, @@ -721,108 +679,83 @@ mail_attachment_change_zoom (EMailDisplay *display, } static void -action_attachment_show_cb (GtkAction *action, - EMailDisplay *display) +action_attachment_show_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); mail_display_change_attachment_visibility (display, FALSE, TRUE); } static void -action_attachment_show_all_cb (GtkAction *action, - EMailDisplay *display) +action_attachment_show_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); mail_display_change_attachment_visibility (display, TRUE, TRUE); } static void -action_attachment_hide_cb (GtkAction *action, - EMailDisplay *display) +action_attachment_hide_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); mail_display_change_attachment_visibility (display, FALSE, FALSE); } static void -action_attachment_hide_all_cb (GtkAction *action, - EMailDisplay *display) +action_attachment_hide_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); mail_display_change_attachment_visibility (display, TRUE, FALSE); } static void -action_attachment_zoom_to_100_cb (GtkAction *action, - EMailDisplay *display) +action_attachment_zoom_to_100_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); mail_attachment_change_zoom (display, TRUE); } static void -action_attachment_zoom_to_window_cb (GtkAction *action, - EMailDisplay *display) +action_attachment_zoom_to_window_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; + g_return_if_fail (E_IS_MAIL_DISPLAY (display)); mail_attachment_change_zoom (display, FALSE); } -static GtkActionEntry attachment_inline_entries[] = { - - { "hide", - NULL, - N_("_Hide"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_attachment_hide_cb) }, - - { "hide-all", - NULL, - N_("Hid_e All"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_attachment_hide_all_cb) }, - - { "show", - NULL, - N_("_View Inline"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_attachment_show_cb) }, - - { "show-all", - NULL, - N_("Vie_w All Inline"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_attachment_show_all_cb) }, - - { "zoom-to-100", - NULL, - N_("_Zoom to 100%"), - NULL, - N_("Zoom the image to its natural size"), - G_CALLBACK (action_attachment_zoom_to_100_cb) }, - - { "zoom-to-window", - NULL, - N_("_Zoom to window"), - NULL, - N_("Zoom large images to not be wider than the window width"), - G_CALLBACK (action_attachment_zoom_to_window_cb) } -}; - static void -mail_display_allow_remote_content_site_cb (GtkAction *action, - EMailDisplay *display) +mail_display_allow_remote_content_site_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; EMailRemoteContent *remote_content; GUri *img_uri; const gchar *cursor_image_source; @@ -848,9 +781,11 @@ mail_display_allow_remote_content_site_cb (GtkAction *action, } static void -mail_display_load_remote_content_site_cb (GtkAction *action, - EMailDisplay *display) +mail_display_load_remote_content_site_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; GUri *img_uri; const gchar *cursor_image_source; @@ -873,9 +808,11 @@ mail_display_load_remote_content_site_cb (GtkAction *action, } static void -mail_display_load_remote_content_this_cb (GtkAction *action, - EMailDisplay *display) +mail_display_load_remote_content_this_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; const gchar *cursor_image_source; g_return_if_fail (E_IS_MAIL_DISPLAY (display)); @@ -890,30 +827,6 @@ mail_display_load_remote_content_this_cb (GtkAction *action, } } -static GtkActionEntry image_entries[] = { - - { "allow-remote-content-site", - NULL, - "Allow remote content from...", /* placeholder text, do not localize */ - NULL, - NULL, - G_CALLBACK (mail_display_allow_remote_content_site_cb) }, - - { "load-remote-content-site", - NULL, - "Load remote content from...", /* placeholder text, do not localize */ - NULL, - NULL, - G_CALLBACK (mail_display_load_remote_content_site_cb) }, - - { "load-remote-content-this", - NULL, - N_("Load this image"), - NULL, - NULL, - G_CALLBACK (mail_display_load_remote_content_this_cb) } -}; - static void call_attachment_save_handle_error (GObject *source_object, GAsyncResult *result, @@ -970,16 +883,21 @@ mail_display_open_attachment (EMailDisplay *display, } static void -action_attachment_toggle_cb (GtkAction *action, - EMailDisplay *display) +action_attachment_toggle_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplay *display = user_data; EAttachmentStore *store; GList *attachments, *link; const gchar *name; guint index = ~0; guint len, ii; - name = gtk_action_get_name (action); + if (!gtk_widget_is_visible (GTK_WIDGET (display))) + return; + + name = g_action_get_name (G_ACTION (action)); g_return_if_fail (name != NULL); len = strlen (name); @@ -1034,79 +952,6 @@ action_attachment_toggle_cb (GtkAction *action, g_list_free_full (attachments, g_object_unref); } -static GtkActionEntry accel_entries[] = { - - { "attachment-toggle-all", - NULL, - NULL, - "0", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-1", - NULL, - NULL, - "1", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-2", - NULL, - NULL, - "2", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-3", - NULL, - NULL, - "3", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-4", - NULL, - NULL, - "4", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-5", - NULL, - NULL, - "5", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-6", - NULL, - NULL, - "6", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-7", - NULL, - NULL, - "7", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-8", - NULL, - NULL, - "8", - NULL, - G_CALLBACK (action_attachment_toggle_cb) }, - - { "attachment-toggle-9", - NULL, - NULL, - "9", - NULL, - G_CALLBACK (action_attachment_toggle_cb) } -}; - static EAttachment * mail_display_ref_attachment_from_element (EMailDisplay *display, const gchar *element_value) @@ -1185,8 +1030,8 @@ mail_display_attachment_expander_clicked_cb (EWebView *web_view, static void mail_display_attachment_inline_update_actions (EMailDisplay *display) { - GtkActionGroup *action_group; - GtkAction *action; + EUIActionGroup *action_group; + EUIAction *action; GList *attachments, *link; EAttachmentView *view; guint n_shown = 0; @@ -1245,43 +1090,42 @@ mail_display_attachment_inline_update_actions (EMailDisplay *display) } g_list_free_full (attachments, g_object_unref); - action = gtk_action_group_get_action (action_group, "show"); - gtk_action_set_visible (action, can_show && !shown); + action = e_ui_action_group_get_action (action_group, "show"); + e_ui_action_set_visible (action, can_show && !shown); /* Show this action if there are multiple viewable * attachments, and at least one of them is hidden. */ visible = (n_shown + n_hidden > 1) && (n_hidden > 0); - action = gtk_action_group_get_action (action_group, "show-all"); - gtk_action_set_visible (action, visible); + action = e_ui_action_group_get_action (action_group, "show-all"); + e_ui_action_set_visible (action, visible); - action = gtk_action_group_get_action (action_group, "hide"); - gtk_action_set_visible (action, can_show && shown); + action = e_ui_action_group_get_action (action_group, "hide"); + e_ui_action_set_visible (action, can_show && shown); /* Show this action if there are multiple viewable * attachments, and at least one of them is shown. */ visible = (n_shown + n_hidden > 1) && (n_shown > 0); - action = gtk_action_group_get_action (action_group, "hide-all"); - gtk_action_set_visible (action, visible); + action = e_ui_action_group_get_action (action_group, "hide-all"); + e_ui_action_set_visible (action, visible); - action = gtk_action_group_get_action (action_group, "zoom-to-100"); - gtk_action_set_visible (action, can_show && shown && is_image && !zoomed_to_100); + action = e_ui_action_group_get_action (action_group, "zoom-to-100"); + e_ui_action_set_visible (action, can_show && shown && is_image && !zoomed_to_100); - action = gtk_action_group_get_action (action_group, "zoom-to-window"); - gtk_action_set_visible (action, can_show && shown && is_image && zoomed_to_100); + action = e_ui_action_group_get_action (action_group, "zoom-to-window"); + e_ui_action_set_visible (action, can_show && shown && is_image && zoomed_to_100); } static void -mail_display_attachment_menu_deactivate_cb (GtkMenuShell *menu, - gpointer user_data) +mail_display_attachment_menu_freed_cb (gpointer user_data, + GObject *freed_menu) { - EMailDisplay *display = user_data; + EUIActionGroup *group = user_data; - g_return_if_fail (E_IS_MAIL_DISPLAY (display)); + g_return_if_fail (E_IS_UI_ACTION_GROUP (group)); - gtk_action_group_set_visible (display->priv->attachment_inline_group, FALSE); + e_ui_action_group_set_visible (group, FALSE); - g_signal_handlers_disconnect_by_func (menu, - G_CALLBACK (mail_display_attachment_menu_deactivate_cb), display); + g_clear_object (&group); } static void @@ -1331,19 +1175,20 @@ mail_display_attachment_menu_clicked_cb (EWebView *web_view, if (view && attachment) { GtkWidget *popup_menu; - popup_menu = e_attachment_view_get_popup_menu (view); - - g_signal_connect ( - popup_menu, "deactivate", - G_CALLBACK (mail_display_attachment_menu_deactivate_cb), display); - mail_display_attachment_select_path (view, attachment); mail_display_attachment_inline_update_actions (display); - gtk_action_group_set_visible (display->priv->attachment_inline_group, TRUE); + e_ui_action_group_set_visible (display->priv->attachment_inline_group, TRUE); e_attachment_view_update_actions (view); + popup_menu = e_attachment_view_get_popup_menu (view); + e_ui_manager_add_action_groups_to_widget (e_web_view_get_ui_manager (web_view), popup_menu); + e_ui_manager_add_action_groups_to_widget (e_attachment_view_get_ui_manager (view), popup_menu); + + g_object_weak_ref (G_OBJECT (popup_menu), mail_display_attachment_menu_freed_cb, + g_object_ref (display->priv->attachment_inline_group)); + g_object_set (GTK_MENU (popup_menu), "anchor-hints", (GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE | @@ -1630,6 +1475,53 @@ mail_display_content_loaded_cb (EWebView *web_view, mail_display_schedule_iframes_height_update (mail_display); } +static void +action_open_with_app_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EMailDisplay *self = user_data; + GAppInfo *app_info; + OpenWithData *data; + gpointer parent; + + data = g_hash_table_lookup (self->priv->open_with_apps_hash, GINT_TO_POINTER (g_variant_get_int32 (parameter))); + g_return_if_fail (data != NULL); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (self)); + parent = gtk_widget_is_toplevel (parent) ? parent : NULL; + + app_info = data->app_info; + + if (!app_info && !e_util_is_running_flatpak ()) { + GtkWidget *dialog; + GFileInfo *file_info; + const gchar *content_type; + + file_info = e_attachment_ref_file_info (data->attachment); + g_return_if_fail (file_info != NULL); + + content_type = g_file_info_get_content_type (file_info); + + dialog = gtk_app_chooser_dialog_new_for_content_type (parent, 0, content_type); + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { + GtkAppChooser *app_chooser = GTK_APP_CHOOSER (dialog); + app_info = gtk_app_chooser_get_app_info (app_chooser); + } + + gtk_widget_destroy (dialog); + g_object_unref (file_info); + } else if (app_info) { + g_object_ref (app_info); + } + + if (app_info) { + e_attachment_open_async (data->attachment, app_info, + (GAsyncReadyCallback) e_attachment_open_handle_error, parent); + g_object_unref (app_info); + } +} + static void mail_display_set_property (GObject *object, guint property_id, @@ -1666,6 +1558,10 @@ mail_display_set_property (GObject *object, E_MAIL_DISPLAY (object), g_value_get_object (value)); return; + + case PROP_MAIL_READER: + g_weak_ref_set (&(E_MAIL_DISPLAY (object)->priv->mail_reader_weakref), g_value_get_object (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -1733,6 +1629,11 @@ mail_display_get_property (GObject *object, e_mail_display_ref_remote_content ( E_MAIL_DISPLAY (object))); return; + + case PROP_MAIL_READER: + g_value_take_object (value, + e_mail_display_ref_mail_reader (E_MAIL_DISPLAY (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -1777,7 +1678,6 @@ mail_display_dispose (GObject *object) g_clear_object (&self->priv->attachment_view); g_clear_object (&self->priv->attachment_inline_group); g_clear_object (&self->priv->attachment_accel_action_group); - g_clear_object (&self->priv->attachment_accel_group); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_mail_display_parent_class)->dispose (object); @@ -1793,12 +1693,15 @@ mail_display_finalize (GObject *object) g_mutex_lock (&self->priv->remote_content_lock); g_clear_pointer (&self->priv->skipped_remote_content_sites, g_hash_table_destroy); g_clear_pointer (&self->priv->temporary_allow_remote_content, g_hash_table_destroy); + g_clear_object (&self->priv->open_with_apps_menu); + g_clear_pointer (&self->priv->open_with_apps_hash, g_hash_table_unref); g_slist_free_full (self->priv->insecure_part_ids, g_free); g_hash_table_destroy (self->priv->attachment_flags); g_hash_table_destroy (self->priv->cid_attachments); g_clear_object (&self->priv->remote_content); g_mutex_unlock (&self->priv->remote_content_lock); g_mutex_clear (&self->priv->remote_content_lock); + g_weak_ref_clear (&self->priv->mail_reader_weakref); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_mail_display_parent_class)->finalize (object); @@ -1891,6 +1794,30 @@ mail_display_schedule_iframes_height_update_cb (WebKitUserContentManager *manage mail_display_schedule_iframes_height_update (mail_display); } +static gboolean +e_mail_display_ui_manager_create_item_cb (EUIManager *manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EMailDisplay *self = user_data; + + g_return_val_if_fail (E_IS_MAIL_DISPLAY (self), FALSE); + + if (for_kind != E_UI_ELEMENT_KIND_MENU || + g_strcmp0 (g_action_get_name (G_ACTION (action)), "EMailDisplay::open-with-app") != 0) + return FALSE; + + if (self->priv->open_with_apps_menu) + *out_item = G_OBJECT (g_menu_item_new_section (NULL, G_MENU_MODEL (self->priv->open_with_apps_menu))); + else + *out_item = NULL; + + return TRUE; +} + static void mail_display_constructed (GObject *object) { @@ -1898,7 +1825,7 @@ mail_display_constructed (GObject *object) WebKitUserContentManager *manager; EWebView *web_view; EMailDisplay *display; - GtkUIManager *ui_manager; + EUIManager *ui_manager; /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_display_parent_class)->constructed (object); @@ -1934,17 +1861,256 @@ mail_display_constructed (GObject *object) ui_manager = e_attachment_view_get_ui_manager (display->priv->attachment_view); if (ui_manager) { - GError *error = NULL; + static const gchar *attachment_popup_eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - gtk_ui_manager_insert_action_group (ui_manager, display->priv->attachment_inline_group, -1); + static const EUIActionEntry attachment_inline_entries[] = { - display->priv->attachment_inline_ui_id = gtk_ui_manager_add_ui_from_string (ui_manager, - attachment_popup_ui, -1, &error); + { "hide", + NULL, + N_("_Hide"), + NULL, + NULL, + action_attachment_hide_cb, NULL, NULL, NULL }, - if (error) { - g_warning ("%s: Failed to read attachment_popup_ui: %s", G_STRFUNC, error->message); - g_clear_error (&error); - } + { "hide-all", + NULL, + N_("Hid_e All"), + NULL, + NULL, + action_attachment_hide_all_cb, NULL, NULL, NULL }, + + { "show", + NULL, + N_("_View Inline"), + NULL, + NULL, + action_attachment_show_cb, NULL, NULL, NULL }, + + { "show-all", + NULL, + N_("Vie_w All Inline"), + NULL, + NULL, + action_attachment_show_all_cb, NULL, NULL, NULL }, + + { "zoom-to-100", + NULL, + N_("_Zoom to 100%"), + NULL, + N_("Zoom the image to its natural size"), + action_attachment_zoom_to_100_cb, NULL, NULL, NULL }, + + { "zoom-to-window", + NULL, + N_("_Zoom to window"), + NULL, + N_("Zoom large images to not be wider than the window width"), + action_attachment_zoom_to_window_cb, NULL, NULL, NULL } + }; + + e_ui_manager_add_actions_with_eui_data (ui_manager, "e-mail-display-attachment-inline", NULL, + attachment_inline_entries, G_N_ELEMENTS (attachment_inline_entries), display, attachment_popup_eui); + + display->priv->attachment_inline_group = g_object_ref (e_ui_manager_get_action_group (ui_manager, "e-mail-display-attachment-inline")); + e_ui_action_group_set_visible (display->priv->attachment_inline_group, FALSE); + + gtk_widget_insert_action_group (GTK_WIDGET (display), e_ui_action_group_get_name (display->priv->attachment_inline_group), + G_ACTION_GROUP (display->priv->attachment_inline_group)); + } + + ui_manager = e_web_view_get_ui_manager (web_view); + if (ui_manager) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry accel_entries[] = { + + { "attachment-toggle-all", + NULL, + "Toggle Attachment All", + "0", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-1", + NULL, + "Toggle Attachment 1", + "1", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-2", + NULL, + "Toggle Attachment 2", + "2", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-3", + NULL, + "Toggle Attachment 3", + "3", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-4", + NULL, + "Toggle Attachment 4", + "4", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-5", + NULL, + "Toggle Attachment 5", + "5", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-6", + NULL, + "Toggle Attachment 6", + "6", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-7", + NULL, + "Toggle Attachment 7", + "7", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-8", + NULL, + "Toggle Attachment 8", + "8", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL }, + + { "attachment-toggle-9", + NULL, + "Toggle Attachment 9", + "9", + NULL, + action_attachment_toggle_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry image_entries[] = { + + { "allow-remote-content-site", + NULL, + "Allow remote content from...", /* placeholder text, do not localize */ + NULL, + NULL, + mail_display_allow_remote_content_site_cb, NULL, NULL, NULL }, + + { "load-remote-content-site", + NULL, + "Load remote content from...", /* placeholder text, do not localize */ + NULL, + NULL, + mail_display_load_remote_content_site_cb, NULL, NULL, NULL }, + + { "load-remote-content-this", + NULL, + N_("Load this image"), + NULL, + NULL, + mail_display_load_remote_content_this_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry mailto_entries[] = { + + { "add-to-address-book", + "contact-new", + N_("_Add to Address Book…"), + NULL, + NULL, + NULL /* Handled by EMailReader */, NULL, NULL, NULL }, + + { "search-folder-recipient", + NULL, + N_("_To This Address"), + NULL, + NULL, + NULL /* Handled by EMailReader */, NULL, NULL, NULL }, + + { "search-folder-sender", + NULL, + N_("_From This Address"), + NULL, + NULL, + NULL /* Handled by EMailReader */, NULL, NULL, NULL }, + + { "send-reply", + NULL, + N_("Send _Reply To…"), + NULL, + N_("Send a reply message to this address"), + NULL /* Handled by EMailReader */, NULL, NULL, NULL }, + + /*** Menus ***/ + + { "search-folder-menu", + "folder-saved-search", + N_("Create Search _Folder"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, + + { "EMailDisplay::open-with-app", + NULL, + N_("Open with…"), + NULL, + NULL, + action_open_with_app_cb, "i", NULL, NULL } + }; + + g_signal_connect (ui_manager, "create-item", + G_CALLBACK (e_mail_display_ui_manager_create_item_cb), display); + + e_ui_manager_add_actions (ui_manager, "e-mail-display-attachment-accel", NULL, + accel_entries, G_N_ELEMENTS (accel_entries), display); + e_ui_manager_add_actions (ui_manager, "image", NULL, + image_entries, G_N_ELEMENTS (image_entries), display); + e_ui_manager_add_actions_with_eui_data (ui_manager, "mailto", NULL, + mailto_entries, G_N_ELEMENTS (mailto_entries), display, eui); + + display->priv->attachment_accel_action_group = g_object_ref (e_ui_manager_get_action_group (ui_manager, "e-mail-display-attachment-accel")); + + gtk_widget_insert_action_group (GTK_WIDGET (display), e_ui_action_group_get_name (display->priv->attachment_accel_action_group), + G_ACTION_GROUP (display->priv->attachment_accel_action_group)); } manager = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (object)); @@ -1982,8 +2148,7 @@ mail_display_style_updated (GtkWidget *widget) mail_display_update_formatter_colors (display); /* Chain up to parent's style_updated() method. */ - GTK_WIDGET_CLASS (e_mail_display_parent_class)-> - style_updated (widget); + GTK_WIDGET_CLASS (e_mail_display_parent_class)->style_updated (widget); } static gboolean @@ -2027,61 +2192,14 @@ mail_display_image_exists_in_cache (const gchar *uri, return exists; } -static void -mail_display_action_open_with_app_info_cb (GtkAction *action, - EMailDisplay *mail_display) -{ - EAttachment *attachment; - GAppInfo *app_info; - gpointer parent; - - parent = gtk_widget_get_toplevel (GTK_WIDGET (mail_display)); - parent = gtk_widget_is_toplevel (parent) ? parent : NULL; - - attachment = g_object_get_data (G_OBJECT (action), "attachment"); - app_info = g_object_get_data (G_OBJECT (action), "app-info"); - - if (!app_info && !e_util_is_running_flatpak ()) { - GtkWidget *dialog; - GFileInfo *file_info; - const gchar *content_type; - - file_info = e_attachment_ref_file_info (attachment); - g_return_if_fail (file_info != NULL); - - content_type = g_file_info_get_content_type (file_info); - - dialog = gtk_app_chooser_dialog_new_for_content_type (parent, 0, content_type); - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { - GtkAppChooser *app_chooser = GTK_APP_CHOOSER (dialog); - app_info = gtk_app_chooser_get_app_info (app_chooser); - } - - gtk_widget_destroy (dialog); - g_object_unref (file_info); - } else if (app_info) { - g_object_ref (app_info); - } - - if (app_info) { - e_attachment_open_async ( - attachment, app_info, (GAsyncReadyCallback) - e_attachment_open_handle_error, parent); - g_object_unref (app_info); - } -} - static void mai_display_fill_open_with (EWebView *web_view, const gchar *attachment_id) { EMailDisplay *mail_display = E_MAIL_DISPLAY (web_view); EAttachment *attachment; - GtkActionGroup *action_group; - GtkUIManager *ui_manager; GList *apps, *link; - - g_warn_if_fail (mail_display->priv->open_with_ui_id == 0); + gint op_id = 0; attachment = g_hash_table_lookup (mail_display->priv->cid_attachments, attachment_id); if (attachment) { @@ -2113,22 +2231,21 @@ mai_display_fill_open_with (EWebView *web_view, g_hash_table_insert (mail_display->priv->cid_attachments, g_strdup (attachment_id), g_object_ref (attachment)); } - ui_manager = e_web_view_get_ui_manager (web_view); - action_group = e_web_view_get_action_group (web_view, "image"); apps = e_attachment_list_apps (attachment); + g_menu_remove_all (mail_display->priv->open_with_apps_menu); + g_hash_table_remove_all (mail_display->priv->open_with_apps_hash); + if (!apps && e_util_is_running_flatpak ()) apps = g_list_prepend (apps, NULL); for (link = apps; link; link = g_list_next (link)) { GAppInfo *app_info = link->data; - GtkAction *action; + GMenuItem *menu_item; GIcon *app_icon; const gchar *app_id; const gchar *app_name; - gchar *action_tooltip; - gchar *action_label; - gchar *action_name; + gchar *label; if (app_info) { app_id = g_app_info_get_id (app_info); @@ -2147,44 +2264,22 @@ mai_display_fill_open_with (EWebView *web_view, if (g_str_equal (app_id, "org.gnome.Evolution.desktop")) continue; - action_name = g_strdup_printf ("mail-display-open-with-%s", app_id); + if (app_info) + label = g_strdup_printf (_("Open With “%s”"), app_name); + else + label = g_strdup (_("Open With Default Application")); - if (app_info) { - action_label = g_strdup_printf (_("Open With “%s”"), app_name); - action_tooltip = g_strdup_printf (_("Open this attachment in %s"), app_name); - } else { - action_label = g_strdup (_("Open With Default Application")); - action_tooltip = g_strdup (_("Open this attachment in default application")); - } + menu_item = g_menu_item_new (label, NULL); + g_menu_item_set_action_and_target_value (menu_item, "e-mail-display-attachment-inline.EMailDisplay::open-with-app", g_variant_new_int32 (op_id)); + g_menu_item_set_icon (menu_item, app_icon); + g_menu_append_item (mail_display->priv->open_with_apps_menu, menu_item); + g_clear_object (&menu_item); - action = gtk_action_new (action_name, action_label, action_tooltip, NULL); + g_hash_table_insert (mail_display->priv->open_with_apps_hash, GINT_TO_POINTER (op_id), open_with_data_new (app_info, attachment)); - gtk_action_set_gicon (action, app_icon); + op_id++; - if (app_info) { - g_object_set_data_full (G_OBJECT (action), "app-info", - g_object_ref (app_info), g_object_unref); - } - - g_object_set_data_full (G_OBJECT (action), "attachment", - g_object_ref (attachment), g_object_unref); - - g_signal_connect (action, "activate", - G_CALLBACK (mail_display_action_open_with_app_info_cb), mail_display); - - gtk_action_group_add_action (action_group, action); - - if (!mail_display->priv->open_with_ui_id) - mail_display->priv->open_with_ui_id = gtk_ui_manager_new_merge_id (ui_manager); - - gtk_ui_manager_add_ui ( - ui_manager, mail_display->priv->open_with_ui_id, - "/context/custom-actions-3/open-actions", action_name, - action_name, GTK_UI_MANAGER_AUTO, FALSE); - - g_free (action_name); - g_free (action_label); - g_free (action_tooltip); + g_free (label); if (!app_info) { apps = g_list_remove (apps, app_info); @@ -2193,72 +2288,35 @@ mai_display_fill_open_with (EWebView *web_view, } if (link != apps && !e_util_is_running_flatpak ()) { - GtkAction *action; - const gchar *action_name = "mail-display-open-with-other"; + GMenuItem *menu_item; - action = gtk_action_new (action_name, _("Open With Other Application…"), NULL, NULL); + menu_item = g_menu_item_new (_("Open With Other Application…"), NULL); + g_menu_item_set_action_and_target_value (menu_item, "e-mail-display-attachment-inline.EMailDisplay::open-with-app", g_variant_new_int32 (op_id)); + g_menu_append_item (mail_display->priv->open_with_apps_menu, menu_item); + g_clear_object (&menu_item); - g_object_set_data_full (G_OBJECT (action), "attachment", - g_object_ref (attachment), g_object_unref); + g_hash_table_insert (mail_display->priv->open_with_apps_hash, GINT_TO_POINTER (op_id), open_with_data_new (NULL, attachment)); - g_signal_connect (action, "activate", - G_CALLBACK (mail_display_action_open_with_app_info_cb), mail_display); - - gtk_action_group_add_action (action_group, action); - - if (!mail_display->priv->open_with_ui_id) - mail_display->priv->open_with_ui_id = gtk_ui_manager_new_merge_id (ui_manager); - - gtk_ui_manager_add_ui ( - ui_manager, mail_display->priv->open_with_ui_id, - "/context/custom-actions-3/open-actions", action_name, - action_name, GTK_UI_MANAGER_AUTO, FALSE); + op_id++; } g_list_free_full (apps, g_object_unref); g_object_unref (attachment); } -static void -mail_display_cleanup_open_with (EWebView *web_view) -{ - EMailDisplay *mail_display = E_MAIL_DISPLAY (web_view); - GtkActionGroup *action_group; - GList *actions, *link; - - if (mail_display->priv->open_with_ui_id) { - GtkUIManager *ui_manager; - - ui_manager = e_web_view_get_ui_manager (web_view); - - gtk_ui_manager_remove_ui (ui_manager, mail_display->priv->open_with_ui_id); - mail_display->priv->open_with_ui_id = 0; - } - - action_group = e_web_view_get_action_group (web_view, "image"); - actions = gtk_action_group_list_actions (action_group); - - for (link = actions; link; link = g_list_next (link)) { - GtkAction *action = link->data; - const gchar *name = gtk_action_get_name (action); - if (name && g_str_has_prefix (name, "mail-display-open-with-")) - gtk_action_group_remove_action (action_group, action); - } - - g_list_free (actions); -} - static void mail_display_before_popup_event (EWebView *web_view, const gchar *uri) { + EMailDisplay *self = E_MAIL_DISPLAY (web_view); const gchar *cursor_image_source; gchar *popup_iframe_src = NULL, *popup_iframe_id = NULL; GList *list, *link; e_web_view_get_last_popup_place (web_view, &popup_iframe_src, &popup_iframe_id, NULL, NULL); - mail_display_cleanup_open_with (web_view); + g_menu_remove_all (self->priv->open_with_apps_menu); + g_hash_table_remove_all (self->priv->open_with_apps_hash); list = e_extensible_list_extensions (E_EXTENSIBLE (web_view), E_TYPE_EXTENSION); @@ -2273,7 +2331,7 @@ mail_display_before_popup_event (EWebView *web_view, cursor_image_source = e_web_view_get_cursor_image_src (web_view); if (cursor_image_source) { - GtkAction *action; + EUIAction *action; GUri *img_uri; gboolean img_is_available; gboolean can_show; @@ -2291,32 +2349,32 @@ mail_display_before_popup_event (EWebView *web_view, g_ascii_strcasecmp (g_uri_get_scheme (img_uri), "evo-https") == 0); action = e_web_view_get_action (web_view, "allow-remote-content-site"); - gtk_action_set_sensitive (action, can_show); - gtk_action_set_visible (action, can_show); + e_ui_action_set_sensitive (action, can_show); + e_ui_action_set_visible (action, can_show); if (can_show) { gchar *label; label = g_strdup_printf (_("Allow remote content from %s"), g_uri_get_host (img_uri)); - gtk_action_set_label (action, label); + e_ui_action_set_label (action, label); g_free (label); } action = e_web_view_get_action (web_view, "load-remote-content-site"); - gtk_action_set_sensitive (action, can_show); - gtk_action_set_visible (action, can_show); + e_ui_action_set_sensitive (action, can_show); + e_ui_action_set_visible (action, can_show); if (can_show) { gchar *label; label = g_strdup_printf (_("Load remote content from %s"), g_uri_get_host (img_uri)); - gtk_action_set_label (action, label); + e_ui_action_set_label (action, label); g_free (label); } action = e_web_view_get_action (web_view, "load-remote-content-this"); - gtk_action_set_sensitive (action, can_show); - gtk_action_set_visible (action, can_show); + e_ui_action_set_sensitive (action, can_show); + e_ui_action_set_visible (action, can_show); g_clear_pointer (&img_uri, g_uri_unref); } @@ -2924,6 +2982,18 @@ e_mail_display_class_init (EMailDisplayClass *class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property ( + object_class, + PROP_MAIL_READER, + g_param_spec_object ( + "mail-reader", + "a mail reader this instance is part of", + NULL, + E_TYPE_MAIL_READER, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + signals[REMOTE_CONTENT_CLICKED] = g_signal_new ( "remote-content-clicked", G_TYPE_FROM_CLASS (class), @@ -2948,46 +3018,22 @@ e_mail_display_class_init (EMailDisplayClass *class) static void e_mail_display_init (EMailDisplay *display) { - GtkUIManager *ui_manager; - GtkActionGroup *actions; - GList *acts_list, *link; GSettings *settings; display->priv = e_mail_display_get_instance_private (display); + g_weak_ref_init (&display->priv->mail_reader_weakref, NULL); + display->priv->attachment_store = E_ATTACHMENT_STORE (e_attachment_store_new ()); display->priv->attachment_flags = g_hash_table_new (g_direct_hash, g_direct_equal); display->priv->cid_attachments = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - display->priv->attachment_inline_group = gtk_action_group_new ("e-mail-display-attachment-inline"); - display->priv->attachment_accel_action_group = gtk_action_group_new ("e-mail-display-attachment-accel"); - display->priv->attachment_accel_group = gtk_accel_group_new (); + display->priv->open_with_apps_menu = g_menu_new (); + display->priv->open_with_apps_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, open_with_data_free); settings = e_util_ref_settings ("org.gnome.evolution.mail"); display->priv->skip_insecure_parts = !g_settings_get_boolean (settings, "show-insecure-parts"); g_object_unref (settings); - gtk_action_group_add_actions ( - display->priv->attachment_inline_group, attachment_inline_entries, - G_N_ELEMENTS (attachment_inline_entries), display); - gtk_action_group_set_visible (display->priv->attachment_inline_group, FALSE); - - gtk_action_group_set_accel_group (display->priv->attachment_accel_action_group, - display->priv->attachment_accel_group); - - gtk_action_group_add_actions ( - display->priv->attachment_accel_action_group, accel_entries, - G_N_ELEMENTS (accel_entries), display); - - acts_list = gtk_action_group_list_actions (display->priv->attachment_accel_action_group); - - for (link = acts_list; link; link = g_list_next (link)) { - GtkAction *action = link->data; - - gtk_action_connect_accelerator (action); - } - - g_list_free (acts_list); - g_signal_connect (display->priv->attachment_store, "attachment-added", G_CALLBACK (mail_display_attachment_added_cb), display); g_signal_connect (display->priv->attachment_store, "attachment-removed", @@ -3044,19 +3090,6 @@ e_mail_display_init (EMailDisplay *display) display, "content-loaded", G_CALLBACK (mail_display_content_loaded_cb), NULL); - actions = e_web_view_get_action_group (E_WEB_VIEW (display), "mailto"); - gtk_action_group_add_actions ( - actions, mailto_entries, - G_N_ELEMENTS (mailto_entries), display); - - actions = e_web_view_get_action_group (E_WEB_VIEW (display), "image"); - gtk_action_group_add_actions ( - actions, image_entries, - G_N_ELEMENTS (image_entries), display); - - ui_manager = e_web_view_get_ui_manager (E_WEB_VIEW (display)); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL); - g_mutex_init (&display->priv->remote_content_lock); display->priv->remote_content = NULL; display->priv->skipped_remote_content_sites = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, NULL); @@ -3152,13 +3185,23 @@ e_mail_display_claim_attachment (EMailFormatter *formatter, } GtkWidget * -e_mail_display_new (EMailRemoteContent *remote_content) +e_mail_display_new (EMailRemoteContent *remote_content, + EMailReader *mail_reader) { return g_object_new (E_TYPE_MAIL_DISPLAY, "remote-content", remote_content, + "mail-reader", mail_reader, NULL); } +EMailReader * +e_mail_display_ref_mail_reader (EMailDisplay *display) +{ + g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); + + return g_weak_ref_get (&display->priv->mail_reader_weakref); +} + EAttachmentStore * e_mail_display_get_attachment_store (EMailDisplay *display) { @@ -3535,11 +3578,11 @@ e_mail_display_reload (EMailDisplay *display) (GSourceFunc) do_reload_display, display, NULL); } -GtkAction * +EUIAction * e_mail_display_get_action (EMailDisplay *display, const gchar *action_name) { - GtkAction *action; + EUIAction *action; g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); g_return_val_if_fail (action_name != NULL, NULL); @@ -3697,34 +3740,6 @@ e_mail_display_process_magic_spacebar (EMailDisplay *display, return TRUE; } -gboolean -e_mail_display_need_key_event (EMailDisplay *mail_display, - const GdkEventKey *event) -{ - GtkAccelGroup *accel_group; - GdkModifierType accel_mods; - GQuark accel_quark; - gchar *accel_name; - - if (!event) - return FALSE; - - g_return_val_if_fail (E_IS_MAIL_DISPLAY (mail_display), FALSE); - - accel_group = gtk_action_group_get_accel_group (mail_display->priv->attachment_accel_action_group); - - if (!accel_group) - return FALSE; - - accel_mods = event->state & gtk_accelerator_get_default_mod_mask (); - accel_name = gtk_accelerator_name (event->keyval, accel_mods); - accel_quark = g_quark_from_string (accel_name); - g_free (accel_name); - - return gtk_accel_group_activate (accel_group, accel_quark, G_OBJECT (mail_display), - event->keyval, accel_mods); -} - gboolean e_mail_display_get_skip_insecure_parts (EMailDisplay *mail_display) { diff --git a/src/mail/e-mail-display.h b/src/mail/e-mail-display.h index 8c0651bd13..3052bd6cf6 100644 --- a/src/mail/e-mail-display.h +++ b/src/mail/e-mail-display.h @@ -47,6 +47,8 @@ G_BEGIN_DECLS +struct _EMailReader; + typedef struct _EMailDisplay EMailDisplay; typedef struct _EMailDisplayClass EMailDisplayClass; typedef struct _EMailDisplayPrivate EMailDisplayPrivate; @@ -61,7 +63,10 @@ struct _EMailDisplayClass { }; GType e_mail_display_get_type (void) G_GNUC_CONST; -GtkWidget * e_mail_display_new (EMailRemoteContent *remote_content); +GtkWidget * e_mail_display_new (EMailRemoteContent *remote_content, + struct _EMailReader *mail_reader); +struct _EMailReader * + e_mail_display_ref_mail_reader (EMailDisplay *display); EAttachmentStore * e_mail_display_get_attachment_store (EMailDisplay *display); @@ -90,7 +95,7 @@ void e_mail_display_set_headers_collapsed void e_mail_display_load (EMailDisplay *display, const gchar *msg_uri); void e_mail_display_reload (EMailDisplay *display); -GtkAction * e_mail_display_get_action (EMailDisplay *display, +EUIAction * e_mail_display_get_action (EMailDisplay *display, const gchar *action_name); void e_mail_display_set_status (EMailDisplay *display, const gchar *status); @@ -111,8 +116,6 @@ void e_mail_display_set_remote_content gboolean e_mail_display_process_magic_spacebar (EMailDisplay *display, gboolean towards_bottom); -gboolean e_mail_display_need_key_event (EMailDisplay *mail_display, - const GdkEventKey *event); gboolean e_mail_display_get_skip_insecure_parts (EMailDisplay *mail_display); diff --git a/src/mail/e-mail-folder-sort-order-dialog.c b/src/mail/e-mail-folder-sort-order-dialog.c index aa0053bb7e..85e79c1713 100644 --- a/src/mail/e-mail-folder-sort-order-dialog.c +++ b/src/mail/e-mail-folder-sort-order-dialog.c @@ -36,7 +36,7 @@ struct _EMailFolderSortOrderDialogPrivate { gboolean drag_changed; GHashTable *drag_state; /* gchar *folder_uri ~> guint sort_order */ - GtkAction *reset_current_level_action; + EUIAction *reset_current_level_action; }; enum { @@ -79,11 +79,12 @@ sort_order_dialog_selection_changed_cb (GtkTreeSelection *selection, } while (!can && gtk_tree_model_iter_next (model, &iter)); } - gtk_action_set_sensitive (dialog->priv->reset_current_level_action, can); + e_ui_action_set_sensitive (dialog->priv->reset_current_level_action, can); } static void -sort_order_dialog_reset_current_level_activate_cb (GtkAction *action, +sort_order_dialog_reset_current_level_activate_cb (EUIAction *action, + GVariant *parameter, gpointer user_data) { EMailFolderSortOrderDialog *dialog = user_data; @@ -129,7 +130,8 @@ sort_order_dialog_reset_current_level_activate_cb (GtkAction *action, } static void -sort_order_dialog_reset_all_levels_activate_cb (GtkAction *action, +sort_order_dialog_reset_all_levels_activate_cb (EUIAction *action, + GVariant *parameter, gpointer user_data) { EMailFolderSortOrderDialog *dialog = user_data; @@ -675,7 +677,7 @@ e_mail_folder_sort_order_dialog_constructed (GObject *object) ETreeViewFrame *tree_view_frame; GtkTreeSelection *selection; CamelSession *session; - GtkAction *action; + EUIAction *action; /* Chain up to parent's method. */ G_OBJECT_CLASS (e_mail_folder_sort_order_dialog_parent_class)->constructed (object); @@ -721,15 +723,15 @@ e_mail_folder_sort_order_dialog_constructed (GObject *object) gtk_widget_grab_focus (folder_tree); action = e_tree_view_frame_lookup_toolbar_action (tree_view_frame, E_TREE_VIEW_FRAME_ACTION_ADD); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); action = e_tree_view_frame_lookup_toolbar_action (tree_view_frame, E_TREE_VIEW_FRAME_ACTION_REMOVE); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); + + action = e_ui_action_new ("FolderSortOrder", "reset-current", NULL); + e_ui_action_set_label (action, _("Reset current level")); + e_ui_action_set_tooltip (action, _("Reset sort order in the current level to the defaults")); - action = gtk_action_new ("FolderSortOrder-reset-current", - _("Reset current level"), - _("Reset sort order in the current level to the defaults"), - NULL); dialog->priv->reset_current_level_action = action; g_signal_connect (action, "activate", @@ -737,10 +739,9 @@ e_mail_folder_sort_order_dialog_constructed (GObject *object) e_tree_view_frame_insert_toolbar_action (tree_view_frame, action, 0); - action = gtk_action_new ("FolderSortOrder-reset-all", - _("Reset all levels"), - _("Reset sort order in all levels to their defaults"), - NULL); + action = e_ui_action_new ("FolderSortOrder", "reset-all", NULL); + e_ui_action_set_label (action, _("Reset all levels")); + e_ui_action_set_tooltip (action, _("Reset sort order in all levels to their defaults")); g_signal_connect (action, "activate", G_CALLBACK (sort_order_dialog_reset_all_levels_activate_cb), dialog); diff --git a/src/mail/e-mail-label-action.c b/src/mail/e-mail-label-action.c deleted file mode 100644 index 3ce6c956af..0000000000 --- a/src/mail/e-mail-label-action.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * e-mail-label-action.c - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include "evolution-config.h" - -#include - -#include "e-mail-label-action.h" - -struct _EMailLabelActionPrivate { - gint placeholder; -}; - -G_DEFINE_TYPE_WITH_PRIVATE (EMailLabelAction, e_mail_label_action, GTK_TYPE_TOGGLE_ACTION) - -static void -mail_label_action_menu_item_realize_cb (GtkWidget *menu_item) -{ - GtkAction *action; - GtkActivatable *activatable; - GtkWidget *container; - GtkWidget *widget; - - activatable = GTK_ACTIVATABLE (menu_item); - action = gtk_activatable_get_related_action (activatable); - g_return_if_fail (E_IS_MAIL_LABEL_ACTION (action)); - - /* Prevent GtkMenuItem's sync_action_properties() method from - * destroying our hack. Instead we use EBindings to keep the - * label and image in sync with the action. */ - gtk_activatable_set_use_action_appearance (activatable, FALSE); - - /* Remove the menu item's child widget. */ - widget = gtk_bin_get_child (GTK_BIN (menu_item)); - gtk_widget_destroy (widget); - - /* Now add our own child widget. */ - - widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); - gtk_container_add (GTK_CONTAINER (menu_item), widget); - gtk_widget_show (widget); - - container = widget; - - widget = gtk_action_create_icon (action, GTK_ICON_SIZE_MENU); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - widget = gtk_label_new (NULL); - gtk_label_set_use_underline (GTK_LABEL (widget), TRUE); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - gtk_widget_show (widget); - - e_binding_bind_property ( - action, "label", - widget, "label", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); -} - -static GtkWidget * -mail_label_action_create_menu_item (GtkAction *action) -{ - GtkWidget *menu_item; - - menu_item = gtk_check_menu_item_new (); - - g_signal_connect ( - menu_item, "realize", - G_CALLBACK (mail_label_action_menu_item_realize_cb), NULL); - - return menu_item; -} - -static void -e_mail_label_action_class_init (EMailLabelActionClass *class) -{ - GtkActionClass *action_class; - - action_class = GTK_ACTION_CLASS (class); - action_class->create_menu_item = mail_label_action_create_menu_item; -} - -static void -e_mail_label_action_init (EMailLabelAction *action) -{ - action->priv = e_mail_label_action_get_instance_private (action); -} - -EMailLabelAction * -e_mail_label_action_new (const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id) -{ - g_return_val_if_fail (name != NULL, NULL); - - return g_object_new ( - E_TYPE_MAIL_LABEL_ACTION, - "name", name, "label", label, - "tooltip", tooltip, "stock-id", stock_id, NULL); -} diff --git a/src/mail/e-mail-label-action.h b/src/mail/e-mail-label-action.h deleted file mode 100644 index f4e3e4c9b8..0000000000 --- a/src/mail/e-mail-label-action.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * e-mail-label-action.h - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* This is a toggle action whose menu item shows a checkbox, icon and - * label. Use of this thing for anything besides the label submenu in - * the message list popup menu is discouraged, which is why this class - * was not given a more generic name. */ - -#ifndef E_MAIL_LABEL_ACTION_H -#define E_MAIL_LABEL_ACTION_H - -#include - -/* Standard GObject macros */ -#define E_TYPE_MAIL_LABEL_ACTION \ - (e_mail_label_action_get_type ()) -#define E_MAIL_LABEL_ACTION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_MAIL_LABEL_ACTION, EMailLabelAction)) -#define E_MAIL_LABEL_ACTION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_MAIL_LABEL_ACTION, EMailLabelActionClass)) -#define E_IS_MAIL_LABEL_ACTION(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_MAIL_LABEL_ACTION)) -#define E_IS_MAIL_LABEL_ACTION_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_MAIL_LABEL_ACTION)) -#define E_MAIL_LABEL_ACTION_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_MAIL_LABEL_ACTION, EMailLabelActionClass)) - -G_BEGIN_DECLS - -typedef struct _EMailLabelAction EMailLabelAction; -typedef struct _EMailLabelActionClass EMailLabelActionClass; -typedef struct _EMailLabelActionPrivate EMailLabelActionPrivate; - -struct _EMailLabelAction { - GtkToggleAction parent; - EMailLabelActionPrivate *priv; -}; - -struct _EMailLabelActionClass { - GtkToggleActionClass parent_class; -}; - -GType e_mail_label_action_get_type (void); -EMailLabelAction * - e_mail_label_action_new (const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id); - -#endif /* E_MAIL_LABEL_ACTION_H */ diff --git a/src/mail/e-mail-label-list-store.c b/src/mail/e-mail-label-list-store.c index b1dfde39eb..ae6f732494 100644 --- a/src/mail/e-mail-label-list-store.c +++ b/src/mail/e-mail-label-list-store.c @@ -149,43 +149,35 @@ mail_label_list_store_ensure_defaults (EMailLabelListStore *store) } static gchar * -mail_label_list_store_get_stock_id (EMailLabelListStore *store, - const gchar *color_spec) +mail_label_list_store_dup_icon_name (EMailLabelListStore *store, + const gchar *color_spec) { - EMailLabelListStoreClass *class; - GtkIconFactory *icon_factory; - GdkColor color; - gchar *stock_id; + GtkIconTheme *icon_theme; + GdkRGBA rgba = { 0, }; + gchar *icon_name; - class = E_MAIL_LABEL_LIST_STORE_GET_CLASS (store); - icon_factory = class->icon_factory; - - if (!gdk_color_parse (color_spec, &color)) + if (!gdk_rgba_parse (&rgba, color_spec)) return NULL; - stock_id = g_strdup_printf ("evolution-label-%s", color_spec); + icon_theme = gtk_icon_theme_get_default (); + icon_name = g_strdup_printf ("evolution-label-%s", color_spec); - /* Themes need not be taken into account here. - * It's just a solid block of a user-chosen color. */ - if (gtk_icon_factory_lookup (icon_factory, stock_id) == NULL) { - GtkIconSet *icon_set; + /* It's just a solid block of a user-chosen color. */ + if (!gtk_icon_theme_has_icon (icon_theme, icon_name)) { GdkPixbuf *pixbuf; guint32 pixel; - pixel = (e_color_to_value (&color) & 0xffffff) << 8; + pixel = (e_rgba_to_value (&rgba) & 0xffffff) << 8; - pixbuf = gdk_pixbuf_new ( - GDK_COLORSPACE_RGB, FALSE, 8, 16, 16); + pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, 16, 16); gdk_pixbuf_fill (pixbuf, pixel); - icon_set = gtk_icon_set_new_from_pixbuf (pixbuf); - gtk_icon_factory_add (icon_factory, stock_id, icon_set); - gtk_icon_set_unref (icon_set); + gtk_icon_theme_add_builtin_icon (icon_name, 16, pixbuf); g_object_unref (pixbuf); } - return stock_id; + return icon_name; } static void @@ -400,9 +392,6 @@ e_mail_label_list_store_class_init (EMailLabelListStoreClass *class) object_class->finalize = mail_label_list_store_finalize; object_class->constructed = mail_label_list_store_constructed; - class->icon_factory = gtk_icon_factory_new (); - gtk_icon_factory_add_default (class->icon_factory); - signals[CHANGED] = g_signal_new ( "changed", G_OBJECT_CLASS_TYPE (class), @@ -506,8 +495,8 @@ e_mail_label_list_store_get_color (EMailLabelListStore *store, } gchar * -e_mail_label_list_store_get_stock_id (EMailLabelListStore *store, - GtkTreeIter *iter) +e_mail_label_list_store_dup_icon_name (EMailLabelListStore *store, + GtkTreeIter *iter) { gchar *encoded; gchar *result; @@ -522,7 +511,7 @@ e_mail_label_list_store_get_stock_id (EMailLabelListStore *store, strv = g_strsplit_set (encoded, ":|", 3); if (g_strv_length (strv) >= 2) - result = mail_label_list_store_get_stock_id (store, strv[1]); + result = mail_label_list_store_dup_icon_name (store, strv[1]); else result = NULL; diff --git a/src/mail/e-mail-label-list-store.h b/src/mail/e-mail-label-list-store.h index 81fc1bef2c..96e9437b7b 100644 --- a/src/mail/e-mail-label-list-store.h +++ b/src/mail/e-mail-label-list-store.h @@ -55,7 +55,6 @@ struct _EMailLabelListStore { struct _EMailLabelListStoreClass { GtkListStoreClass parent_class; - GtkIconFactory *icon_factory; }; GType e_mail_label_list_store_get_type (void); @@ -66,7 +65,7 @@ gchar * e_mail_label_list_store_get_name (EMailLabelListStore *store, gboolean e_mail_label_list_store_get_color (EMailLabelListStore *store, GtkTreeIter *iter, GdkColor *color); -gchar * e_mail_label_list_store_get_stock_id (EMailLabelListStore *store, +gchar * e_mail_label_list_store_dup_icon_name (EMailLabelListStore *store, GtkTreeIter *iter); gchar * e_mail_label_list_store_get_tag (EMailLabelListStore *store, GtkTreeIter *iter); diff --git a/src/mail/e-mail-label-tree-view.c b/src/mail/e-mail-label-tree-view.c index 0d69e3f836..32419f2c2d 100644 --- a/src/mail/e-mail-label-tree-view.c +++ b/src/mail/e-mail-label-tree-view.c @@ -39,12 +39,12 @@ mail_label_tree_view_render_pixbuf (GtkTreeViewColumn *column, EMailLabelTreeView *tree_view) { EMailLabelListStore *store; - gchar *stock_id; + gchar *icon_name; store = E_MAIL_LABEL_LIST_STORE (model); - stock_id = e_mail_label_list_store_get_stock_id (store, iter); - g_object_set (renderer, "stock-id", stock_id, NULL); - g_free (stock_id); + icon_name = e_mail_label_list_store_dup_icon_name (store, iter); + g_object_set (renderer, "icon-name", icon_name, NULL); + g_free (icon_name); } static void diff --git a/src/mail/e-mail-notes.c b/src/mail/e-mail-notes.c index 598ca08637..333b4a30cc 100644 --- a/src/mail/e-mail-notes.c +++ b/src/mail/e-mail-notes.c @@ -50,9 +50,10 @@ struct _EMailNotesEditor { EHTMLEditor *editor; /* not referenced */ EAttachmentPaned *attachment_paned; /* not referenced */ EFocusTracker *focus_tracker; - GtkActionGroup *action_group; + EUIActionGroup *action_group; GBinding *attachment_paned_binding; EMenuBar *menu_bar; + GtkWidget *menu_button; /* owned by menu_bar */ gboolean had_message; CamelMimeMessage *message; @@ -616,10 +617,10 @@ e_mail_notes_retrieve_message_done (gpointer ptr) activity_bar = e_html_editor_get_activity_bar (notes_editor->editor); e_activity_bar_set_activity (activity_bar, NULL); } else { - GtkAction *action; + EUIAction *action; - action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close"); - gtk_action_set_sensitive (action, FALSE); + action = e_ui_action_group_get_action (notes_editor->action_group, "save-and-close"); + e_ui_action_set_sensitive (action, FALSE); } g_object_unref (notes_editor); @@ -629,12 +630,10 @@ static gboolean mail_notes_editor_delete_event_cb (EMailNotesEditor *notes_editor, GdkEvent *event) { - GtkActionGroup *action_group; - GtkAction *action; + EUIAction *action; - action_group = notes_editor->action_group; - action = gtk_action_group_get_action (action_group, "close"); - gtk_action_activate (action); + action = e_ui_action_group_get_action (notes_editor->action_group, "close"); + g_action_activate (G_ACTION (action), NULL); return TRUE; } @@ -646,7 +645,7 @@ notes_editor_update_editable_on_notify_cb (GObject *object, { EActivityBar *activity_bar; EContentEditor *cnt_editor; - GtkAction *action; + EUIAction *action; gboolean can_edit; g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor)); @@ -657,8 +656,8 @@ notes_editor_update_editable_on_notify_cb (GObject *object, g_object_set (cnt_editor, "editable", can_edit, NULL); - action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close"); - gtk_action_set_sensitive (action, can_edit); + action = e_ui_action_group_get_action (notes_editor->action_group, "save-and-close"); + e_ui_action_set_sensitive (action, can_edit); } static gboolean @@ -797,12 +796,16 @@ e_mail_notes_replace_note (CamelMimeMessage *message, } static void -action_close_cb (GtkAction *action, - EMailNotesEditor *notes_editor) +action_close_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailNotesEditor *notes_editor = user_data; EContentEditor *cnt_editor; gboolean something_changed = FALSE; + g_return_if_fail (E_IS_MAIL_NOTES_EDITOR (notes_editor)); + cnt_editor = e_html_editor_get_content_editor (notes_editor->editor); something_changed = e_content_editor_get_changed (cnt_editor); @@ -814,12 +817,8 @@ action_close_cb (GtkAction *action, GTK_WINDOW (notes_editor), "mail:ask-mail-note-changed", NULL); if (response == GTK_RESPONSE_YES) { - GtkActionGroup *action_group; - - action_group = notes_editor->action_group; - action = gtk_action_group_get_action ( - action_group, "save-and-close"); - gtk_action_activate (action); + action = e_ui_action_group_get_action (notes_editor->action_group, "save-and-close"); + g_action_activate (G_ACTION (action), NULL); return; } else if (response == GTK_RESPONSE_CANCEL) return; @@ -949,9 +948,11 @@ mail_notes_get_content_ready_cb (GObject *source_object, } static void -action_save_and_close_cb (GtkAction *action, - EMailNotesEditor *notes_editor) +action_save_and_close_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailNotesEditor *notes_editor = user_data; SaveAndCloseData *scd; EActivity *activity; EContentEditor *cnt_editor; @@ -1079,65 +1080,97 @@ set_preformatted_block_format_on_load_finished_cb (EContentEditor *cnt_editor, G_CALLBACK (set_preformatted_block_format_on_load_finished_cb), NULL); } +static gboolean +e_mail_notes_editor_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EMailNotesEditor *self = user_data; + const gchar *name; + + g_return_val_if_fail (E_IS_MAIL_NOTES_EDITOR (self), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "EMailNotes::")) + return FALSE; + + if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + if (g_str_equal (name, "EMailNotes::menu-button")) + *out_item = G_OBJECT (g_object_ref (self->menu_button)); + else + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + return TRUE; +} + static EMailNotesEditor * e_mail_notes_editor_new_with_editor (EHTMLEditor *html_editor, GtkWindow *parent, CamelFolder *folder, const gchar *uid) { - const gchar *ui = - "\n" - " \n" - " \n" - " \n" - " \n" - " " - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - GtkActionEntry entries[] = { + static const EUIActionEntry entries[] = { { "close", "window-close", N_("_Close"), "w", N_("Close"), - G_CALLBACK (action_close_cb) }, + action_close_cb, NULL, NULL, NULL }, { "save-and-close", "document-save", N_("_Save and Close"), "Return", N_("Save and Close"), - G_CALLBACK (action_save_and_close_cb) }, + action_save_and_close_cb, NULL, NULL, NULL }, - { "file-menu", - NULL, - N_("_File"), - NULL, - NULL, - NULL } + { "file-menu", NULL, N_("_File"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EMailNotes::menu-button", NULL, N_("Menu"), NULL, NULL, NULL, NULL, NULL, NULL } }; EMailNotesEditor *notes_editor; EContentEditor *cnt_editor; EFocusTracker *focus_tracker; EActivityBar *activity_bar; - GtkUIManager *ui_manager; - GtkWidget *widget, *content, *button, *menu_button = NULL; - GtkActionGroup *action_group; - GtkAction *action; - GtkHeaderBar *header_bar; + EUIManager *ui_manager; + EUIAction *action; + GtkWidget *widget, *content; GSettings *settings; - GError *local_error = NULL; + GObject *ui_item; notes_editor = g_object_new (E_TYPE_MAIL_NOTES_EDITOR, NULL); @@ -1159,67 +1192,45 @@ e_mail_notes_editor_new_with_editor (EHTMLEditor *html_editor, cnt_editor = e_html_editor_get_content_editor (notes_editor->editor); ui_manager = e_html_editor_get_ui_manager (notes_editor->editor); - /* Because we are loading from a hard-coded string, there is - * no chance of I/O errors. Failure here implies a malformed - * UI definition. Full stop. */ - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &local_error); - if (local_error != NULL) - g_error ("%s: Failed to load built-in UI definition: %s", G_STRFUNC, local_error->message); + g_signal_connect_object (ui_manager, "create-item", + G_CALLBACK (e_mail_notes_editor_ui_manager_create_item_cb), notes_editor, 0); - action_group = gtk_action_group_new ("notes"); - gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE); - gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), notes_editor); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - notes_editor->action_group = g_object_ref (action_group); + e_ui_manager_add_actions_with_eui_data (ui_manager, "notes", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), notes_editor, eui); + notes_editor->action_group = g_object_ref (e_ui_manager_get_action_group (ui_manager, "notes")); /* Hide page properties because it is not inherited in the mail. */ action = e_html_editor_get_action (notes_editor->editor, "properties-page"); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); action = e_html_editor_get_action (notes_editor->editor, "context-properties-page"); - gtk_action_set_visible (action, FALSE); - - gtk_ui_manager_ensure_update (ui_manager); + e_ui_action_set_visible (action, FALSE); /* Construct the window content. */ - widget = e_html_editor_get_managed_widget (notes_editor->editor, "/main-menu"); - notes_editor->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (notes_editor), &menu_button); + ui_item = e_ui_manager_create_item (ui_manager, "main-menu"); + widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (ui_item)); + g_clear_object (&ui_item); + + notes_editor->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (notes_editor), ¬es_editor->menu_button); gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0); if (e_util_get_use_header_bar ()) { - widget = gtk_header_bar_new (); - gtk_widget_show (widget); - header_bar = GTK_HEADER_BAR (widget); - gtk_header_bar_set_show_close_button (header_bar, TRUE); - gtk_header_bar_set_title (header_bar, _("Edit Message Note")); + ui_item = e_ui_manager_create_item (ui_manager, "main-headerbar"); + widget = GTK_WIDGET (ui_item); + gtk_header_bar_set_title (GTK_HEADER_BAR (widget), _("Edit Message Note")); gtk_window_set_titlebar (GTK_WINDOW (notes_editor), widget); - action = gtk_action_group_get_action (notes_editor->action_group, "save-and-close"); - button = e_header_bar_button_new (_("Save"), action); - e_header_bar_button_css_add_class (E_HEADER_BAR_BUTTON (button), "suggested-action"); - e_header_bar_button_set_show_icon_only (E_HEADER_BAR_BUTTON (button), FALSE); - gtk_widget_show (button); - gtk_header_bar_pack_start (header_bar, button); - - widget = e_html_editor_get_managed_widget (notes_editor->editor, "/main-toolbar/pre-main-toolbar/save-and-close"); - gtk_widget_destroy (widget); - - if (menu_button) - gtk_header_bar_pack_end (header_bar, menu_button); + ui_item = e_ui_manager_create_item (ui_manager, "main-toolbar-with-headerbar"); } else { gtk_window_set_title (GTK_WINDOW (notes_editor), _("Edit Message Note")); - widget = e_html_editor_get_managed_widget (notes_editor->editor, "/main-toolbar"); - gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - if (menu_button) { - g_object_ref_sink (menu_button); - gtk_widget_destroy (menu_button); - } + ui_item = e_ui_manager_create_item (ui_manager, "main-toolbar-without-headerbar"); } + widget = GTK_WIDGET (ui_item); + gtk_box_pack_start (GTK_BOX (content), widget, FALSE, FALSE, 0); + widget = GTK_WIDGET (notes_editor->editor); g_object_set (G_OBJECT (widget), "halign", GTK_ALIGN_FILL, diff --git a/src/mail/e-mail-paned-view.c b/src/mail/e-mail-paned-view.c index c39d4bb723..c612a41350 100644 --- a/src/mail/e-mail-paned-view.c +++ b/src/mail/e-mail-paned-view.c @@ -41,7 +41,7 @@ struct _EMailPanedViewPrivate { GtkWidget *scrolled_window; GtkWidget *message_list; GtkWidget *preview_pane; - GtkWidget *search_bar; + GtkWidget *preview_toolbar_box; EMailDisplay *display; GalViewInstance *view_instance; @@ -57,6 +57,8 @@ struct _EMailPanedViewPrivate { /* TRUE when folder had been just set */ gboolean folder_just_set; gchar *last_selected_uid; + + gboolean preview_toolbar_visible; }; enum { @@ -65,7 +67,8 @@ enum { PROP_GROUP_BY_THREADS, PROP_REPLY_STYLE, PROP_MARK_SEEN_ALWAYS, - PROP_DELETE_SELECTS_PREVIOUS + PROP_DELETE_SELECTS_PREVIOUS, + PROP_PREVIEW_TOOLBAR_VISIBLE }; #define STATE_KEY_GROUP_BY_THREADS "GroupByThreads" @@ -423,6 +426,12 @@ mail_paned_view_set_property (GObject *object, E_MAIL_READER (object), g_value_get_boolean (value)); return; + + case PROP_PREVIEW_TOOLBAR_VISIBLE: + e_mail_paned_view_set_preview_toolbar_visible ( + E_MAIL_PANED_VIEW (object), + g_value_get_boolean (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -469,6 +478,13 @@ mail_paned_view_get_property (GObject *object, e_mail_reader_get_delete_selects_previous ( E_MAIL_READER (object))); return; + + case PROP_PREVIEW_TOOLBAR_VISIBLE: + g_value_set_boolean ( + value, + e_mail_paned_view_get_preview_toolbar_visible ( + E_MAIL_PANED_VIEW (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -497,6 +513,7 @@ mail_paned_view_dispose (GObject *object) } g_clear_object (&self->priv->preview_pane); + g_clear_object (&self->priv->preview_toolbar_box); g_clear_object (&self->priv->view_instance); g_clear_pointer (&self->priv->last_selected_uid, g_free); @@ -507,36 +524,6 @@ mail_paned_view_dispose (GObject *object) G_OBJECT_CLASS (e_mail_paned_view_parent_class)->dispose (object); } -static GtkActionGroup * -mail_paned_view_get_action_group (EMailReader *reader, - EMailReaderActionGroup group) -{ - EMailView *view; - EShellView *shell_view; - EShellWindow *shell_window; - const gchar *group_name; - - view = E_MAIL_VIEW (reader); - shell_view = e_mail_view_get_shell_view (view); - shell_window = e_shell_view_get_shell_window (shell_view); - - switch (group) { - case E_MAIL_READER_ACTION_GROUP_STANDARD: - group_name = "mail"; - break; - case E_MAIL_READER_ACTION_GROUP_SEARCH_FOLDERS: - group_name = "search-folders"; - break; - case E_MAIL_READER_ACTION_GROUP_LABELS: - group_name = "mail-labels"; - break; - default: - g_return_val_if_reached (NULL); - } - - return e_shell_window_get_action_group (shell_window, group_name); -} - static EAlertSink * mail_paned_view_get_alert_sink (EMailReader *reader) { @@ -591,23 +578,14 @@ mail_paned_view_get_message_list (EMailReader *reader) return paned_view->priv->message_list; } -static GtkMenu * -mail_paned_view_get_popup_menu (EMailReader *reader) +static EUIManager * +mail_paned_view_get_ui_manager (EMailReader *reader) { - EMailView *view; EShellView *shell_view; - EShellWindow *shell_window; - GtkUIManager *ui_manager; - GtkWidget *widget; - view = E_MAIL_VIEW (reader); - shell_view = e_mail_view_get_shell_view (view); - shell_window = e_shell_view_get_shell_window (shell_view); + shell_view = e_mail_view_get_shell_view (E_MAIL_VIEW (reader)); - ui_manager = e_shell_window_get_ui_manager (shell_window); - widget = gtk_ui_manager_get_widget (ui_manager, "/mail-preview-popup"); - - return GTK_MENU (widget); + return e_shell_view_get_ui_manager (shell_view); } static EPreviewPane * @@ -799,7 +777,7 @@ mail_paned_view_constructed (GObject *object) EMailView *view; GtkWidget *message_list; GtkWidget *container; - GtkWidget *widget, *toolbar; + GtkWidget *widget; view = E_MAIL_VIEW (object); shell_view = e_mail_view_get_shell_view (view); @@ -812,6 +790,7 @@ mail_paned_view_constructed (GObject *object) self->priv->display = g_object_new (E_TYPE_MAIL_DISPLAY, "headers-collapsable", TRUE, "remote-content", e_mail_backend_get_remote_content (backend), + "mail-reader", E_MAIL_READER (self), NULL); /* FIXME This should be an EMailPanedView property, so @@ -877,12 +856,10 @@ mail_paned_view_constructed (GObject *object) container = e_attachment_bar_get_content_area (E_ATTACHMENT_BAR (widget)); widget = e_preview_pane_new (E_WEB_VIEW (self->priv->display)); - toolbar = e_shell_window_get_managed_widget (shell_window, "/mail-preview-toolbar"); - if (toolbar) { - e_util_setup_toolbar_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_SMALL_TOOLBAR); - gtk_style_context_add_class (gtk_widget_get_style_context (toolbar), GTK_STYLE_CLASS_PRIMARY_TOOLBAR); - gtk_box_pack_start (GTK_BOX (container), toolbar, FALSE, FALSE, 0); - } + /* cannot ask the shell_view for the "mail-preview-toolbar" now, because its EUIManager is not loaded yet; + postpone it to the e_mail_paned_view_take_preview_toolbar() function */ + self->priv->preview_toolbar_box = g_object_ref_sink (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); + gtk_box_pack_start (GTK_BOX (container), GTK_WIDGET (self->priv->preview_toolbar_box), FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); @@ -896,7 +873,7 @@ mail_paned_view_constructed (GObject *object) /* Message list customizations. */ - e_mail_reader_init (E_MAIL_READER (object), FALSE, TRUE); + e_mail_reader_init (E_MAIL_READER (object)); reader = E_MAIL_READER (object); message_list = e_mail_reader_get_message_list (reader); @@ -1277,18 +1254,29 @@ e_mail_paned_view_class_init (EMailPanedViewClass *class) object_class, PROP_DELETE_SELECTS_PREVIOUS, "delete-selects-previous"); + + g_object_class_install_property ( + object_class, + PROP_PREVIEW_TOOLBAR_VISIBLE, + g_param_spec_boolean ( + "preview-toolbar-visible", + NULL, + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_EXPLICIT_NOTIFY | + G_PARAM_STATIC_STRINGS)); } static void e_mail_paned_view_reader_init (EMailReaderInterface *iface) { - iface->get_action_group = mail_paned_view_get_action_group; iface->get_alert_sink = mail_paned_view_get_alert_sink; iface->get_backend = mail_paned_view_get_backend; iface->get_mail_display = mail_paned_view_get_mail_display; iface->get_hide_deleted = mail_paned_view_get_hide_deleted; iface->get_message_list = mail_paned_view_get_message_list; - iface->get_popup_menu = mail_paned_view_get_popup_menu; + iface->get_ui_manager = mail_paned_view_get_ui_manager; iface->get_preview_pane = mail_paned_view_get_preview_pane; iface->get_window = mail_paned_view_get_window; iface->set_folder = mail_paned_view_set_folder; @@ -1336,3 +1324,38 @@ e_mail_paned_view_get_preview (EMailPanedView *view) return GTK_WIDGET (mail_paned_view_get_mail_display (E_MAIL_READER (view))); } +gboolean +e_mail_paned_view_get_preview_toolbar_visible (EMailPanedView *view) +{ + g_return_val_if_fail (E_IS_MAIL_PANED_VIEW (view), FALSE); + + return view->priv->preview_toolbar_visible; +} + +void +e_mail_paned_view_set_preview_toolbar_visible (EMailPanedView *view, + gboolean value) +{ + g_return_if_fail (E_IS_MAIL_PANED_VIEW (view)); + + if (!view->priv->preview_toolbar_visible == !value) + return; + + view->priv->preview_toolbar_visible = value; + + gtk_widget_set_visible (view->priv->preview_toolbar_box, value); + + g_object_notify (G_OBJECT (view), "preview-toolbar-visible"); +} + +void +e_mail_paned_view_take_preview_toolbar (EMailPanedView *self, + GtkWidget *toolbar) +{ + g_return_if_fail (E_IS_MAIL_PANED_VIEW (self)); + g_return_if_fail (GTK_IS_WIDGET (toolbar)); + + gtk_widget_set_visible (toolbar, TRUE); + + gtk_box_pack_start (GTK_BOX (self->priv->preview_toolbar_box), toolbar, FALSE, FALSE, 0); +} diff --git a/src/mail/e-mail-paned-view.h b/src/mail/e-mail-paned-view.h index 09ca1a98b1..bc81f95ca5 100644 --- a/src/mail/e-mail-paned-view.h +++ b/src/mail/e-mail-paned-view.h @@ -69,6 +69,14 @@ void e_mail_paned_view_hide_message_list_pane (EMailPanedView *view, gboolean visible); GtkWidget * e_mail_paned_view_get_preview (EMailPanedView *view); +gboolean e_mail_paned_view_get_preview_toolbar_visible + (EMailPanedView *view); +void e_mail_paned_view_set_preview_toolbar_visible + (EMailPanedView *view, + gboolean value); +void e_mail_paned_view_take_preview_toolbar + (EMailPanedView *self, + GtkWidget *toolbar); G_END_DECLS diff --git a/src/mail/e-mail-print-config-headers.c b/src/mail/e-mail-print-config-headers.c index 7a93e81a03..25676b0e90 100644 --- a/src/mail/e-mail-print-config-headers.c +++ b/src/mail/e-mail-print-config-headers.c @@ -122,7 +122,7 @@ mail_print_config_headers_constructed (GObject *object) { EMailPrintConfigHeaders *config; ETreeViewFrame *tree_view_frame; - GtkAction *action; + EUIAction *action; GtkTreeView *tree_view; GtkTreeSelection *selection; GtkTreeViewColumn *column; @@ -145,36 +145,36 @@ mail_print_config_headers_constructed (GObject *object) action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_ADD); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_REMOVE); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_TOP); tooltip = _("Move selected headers to top"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_UP); tooltip = _("Move selected headers up one row"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_DOWN); tooltip = _("Move selected headers down one row"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_MOVE_BOTTOM); tooltip = _("Move selected headers to bottom"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); action = e_tree_view_frame_lookup_toolbar_action ( tree_view_frame, E_TREE_VIEW_FRAME_ACTION_SELECT_ALL); tooltip = _("Select all headers"); - gtk_action_set_tooltip (action, tooltip); + e_ui_action_set_tooltip (action, tooltip); /* Configure the tree view columns. */ diff --git a/src/mail/e-mail-reader-utils.c b/src/mail/e-mail-reader-utils.c index a4d6a76b0f..cddbbabf2b 100644 --- a/src/mail/e-mail-reader-utils.c +++ b/src/mail/e-mail-reader-utils.c @@ -1490,6 +1490,7 @@ e_mail_reader_open_selected (EMailReader *reader) for (ii = 0; ii < views->len; ii++) { const gchar *uid = views->pdata[ii]; GtkWidget *browser; + EMailReader *browser_reader; MessageList *ml; if (prefer_existing) { @@ -1504,17 +1505,16 @@ e_mail_reader_open_selected (EMailReader *reader) } browser = e_mail_browser_new (backend, E_MAIL_FORMATTER_MODE_NORMAL); + browser_reader = E_MAIL_READER (browser); - ml = MESSAGE_LIST (e_mail_reader_get_message_list ( - E_MAIL_READER (browser))); + ml = MESSAGE_LIST (e_mail_reader_get_message_list (browser_reader)); message_list_freeze (ml); - e_mail_reader_set_folder (E_MAIL_READER (browser), folder); - e_mail_reader_set_message (E_MAIL_READER (browser), uid); + e_mail_reader_set_folder (browser_reader, folder); + e_mail_reader_set_message (browser_reader, uid); - copy_tree_state (reader, E_MAIL_READER (browser)); - e_mail_reader_set_group_by_threads ( - E_MAIL_READER (browser), + copy_tree_state (reader, browser_reader); + e_mail_reader_set_group_by_threads (browser_reader, e_mail_reader_get_group_by_threads (reader)); message_list_thaw (ml); @@ -1524,7 +1524,7 @@ e_mail_reader_open_selected (EMailReader *reader) g_ptr_array_foreach (views, (GFunc) g_free, NULL); g_ptr_array_free (views, TRUE); -exit: + exit: g_clear_object (&folder); g_ptr_array_unref (uids); diff --git a/src/mail/e-mail-reader.c b/src/mail/e-mail-reader.c index 398319a1aa..188b2cf166 100644 --- a/src/mail/e-mail-reader.c +++ b/src/mail/e-mail-reader.c @@ -25,11 +25,6 @@ #include #include -#ifdef HAVE_XFREE -#include -#endif - -#include #include #include @@ -41,7 +36,6 @@ #include "e-mail-backend.h" #include "e-mail-browser.h" #include "e-mail-enumtypes.h" -#include "e-mail-label-action.h" #include "e-mail-label-dialog.h" #include "e-mail-label-list-store.h" #include "e-mail-notes.h" @@ -108,8 +102,9 @@ struct _EMailReaderPrivate { GSList *ongoing_operations; /* GCancellable * */ - guint main_menu_label_merge_id; - guint popup_menu_label_merge_id; + GMenuModel *reply_group_menu; + GMenuModel *forward_as_menu; + GMenu *labels_menu; }; enum { @@ -162,13 +157,19 @@ mail_reader_private_free (EMailReaderPrivate *priv) priv->retrieving_message = NULL; } - g_slice_free (EMailReaderPrivate, priv); + g_clear_object (&priv->reply_group_menu); + g_clear_object (&priv->forward_as_menu); + g_clear_object (&priv->labels_menu); + + g_free (priv); } static void -action_mail_add_sender_cb (GtkAction *action, - EMailReader *reader) +action_mail_add_sender_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EShell *shell; EMailBackend *backend; EMailSession *session; @@ -223,9 +224,11 @@ exit: } static void -action_add_to_address_book_cb (GtkAction *action, - EMailReader *reader) +action_add_to_address_book_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EShell *shell; EMailBackend *backend; EMailDisplay *display; @@ -285,32 +288,11 @@ exit: } static void -action_mail_charset_cb (GtkRadioAction *action, - GtkRadioAction *current, - EMailReader *reader) -{ - EMailDisplay *display; - EMailFormatter *formatter; - - if (action != current) - return; - - display = e_mail_reader_get_mail_display (reader); - formatter = e_mail_display_get_formatter (display); - - if (formatter != NULL) { - const gchar *charset; - - /* Charset for "Default" action will be NULL. */ - charset = g_object_get_data (G_OBJECT (action), "charset"); - e_mail_formatter_set_charset (formatter, charset); - } -} - -static void -action_mail_check_for_junk_cb (GtkAction *action, - EMailReader *reader) +action_mail_check_for_junk_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailBackend *backend; EMailSession *session; CamelFolder *folder; @@ -449,9 +431,11 @@ mail_reader_manage_color_flag_on_selection (EMailReader *reader, } static void -action_mail_color_assign_cb (GtkAction *action, - EMailReader *reader) +action_mail_color_assign_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWidget *dialog; dialog = gtk_color_chooser_dialog_new (NULL, e_mail_reader_get_window (reader)); @@ -478,16 +462,20 @@ action_mail_color_assign_cb (GtkAction *action, } static void -action_mail_color_unset_cb (GtkAction *action, - EMailReader *reader) +action_mail_color_unset_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; mail_reader_manage_color_flag_on_selection (reader, NULL); } static void -action_mail_copy_cb (GtkAction *action, - EMailReader *reader) +action_mail_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; mail_reader_copy_or_move_selected_messages (reader, FALSE); } @@ -528,9 +516,11 @@ mail_reader_replace_vee_folder_with_real (CamelFolder **inout_folder, } static void -action_mail_edit_note_cb (GtkAction *action, - EMailReader *reader) +action_mail_edit_note_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; CamelFolder *folder; GPtrArray *uids; @@ -588,9 +578,11 @@ mail_delete_note_thread (EAlertSinkThreadJobData *job_data, } static void -action_mail_delete_note_cb (GtkAction *action, - EMailReader *reader) +action_mail_delete_note_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; CamelFolder *folder; GPtrArray *uids; @@ -636,9 +628,11 @@ action_mail_delete_note_cb (GtkAction *action, } static void -action_mail_delete_cb (GtkAction *action, - EMailReader *reader) +action_mail_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED; guint32 set = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED; @@ -658,37 +652,51 @@ action_mail_delete_cb (GtkAction *action, } static void -action_mail_filter_on_mailing_list_cb (GtkAction *action, - EMailReader *reader) +action_mail_filter_on_mailing_list_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_create_filter_from_selected (reader, AUTO_MLIST); } static void -action_mail_filter_on_recipients_cb (GtkAction *action, - EMailReader *reader) +action_mail_filter_on_recipients_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_create_filter_from_selected (reader, AUTO_TO); } static void -action_mail_filter_on_sender_cb (GtkAction *action, - EMailReader *reader) +action_mail_filter_on_sender_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_create_filter_from_selected (reader, AUTO_FROM); } static void -action_mail_filter_on_subject_cb (GtkAction *action, - EMailReader *reader) +action_mail_filter_on_subject_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_create_filter_from_selected (reader, AUTO_SUBJECT); } static void -action_mail_filters_apply_cb (GtkAction *action, - EMailReader *reader) +action_mail_filters_apply_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailBackend *backend; EMailSession *session; CamelFolder *folder; @@ -709,30 +717,41 @@ action_mail_filters_apply_cb (GtkAction *action, } static void -action_mail_remove_attachments_cb (GtkAction *action, - EMailReader *reader) +action_mail_remove_attachments_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_remove_attachments (reader); } static void -action_mail_remove_duplicates_cb (GtkAction *action, - EMailReader *reader) +action_mail_remove_duplicates_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_remove_duplicates (reader); } static void -action_mail_find_cb (GtkAction *action, - EMailReader *reader) +action_mail_find_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_show_search_bar (reader); } static void -action_mail_flag_clear_cb (GtkAction *action, - EMailReader *reader) +action_mail_flag_clear_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; CamelFolder *folder; GtkWindow *window; GPtrArray *uids; @@ -750,9 +769,11 @@ action_mail_flag_clear_cb (GtkAction *action, } static void -action_mail_flag_completed_cb (GtkAction *action, - EMailReader *reader) +action_mail_flag_completed_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; CamelFolder *folder; GtkWindow *window; GPtrArray *uids; @@ -770,9 +791,11 @@ action_mail_flag_completed_cb (GtkAction *action, } static void -action_mail_flag_for_followup_cb (GtkAction *action, - EMailReader *reader) +action_mail_flag_for_followup_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; CamelFolder *folder; GPtrArray *uids; @@ -788,9 +811,11 @@ action_mail_flag_for_followup_cb (GtkAction *action, } static void -action_mail_forward_cb (GtkAction *action, - EMailReader *reader) +action_mail_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWindow *window; GPtrArray *uids; @@ -814,9 +839,11 @@ action_mail_forward_cb (GtkAction *action, } static void -action_mail_forward_attached_cb (GtkAction *action, - EMailReader *reader) +action_mail_forward_attached_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWindow *window; GPtrArray *uids; @@ -840,9 +867,11 @@ action_mail_forward_attached_cb (GtkAction *action, } static void -action_mail_forward_inline_cb (GtkAction *action, - EMailReader *reader) +action_mail_forward_inline_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWindow *window; GPtrArray *uids; @@ -866,9 +895,11 @@ action_mail_forward_inline_cb (GtkAction *action, } static void -action_mail_forward_quoted_cb (GtkAction *action, - EMailReader *reader) +action_mail_forward_quoted_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWindow *window; GPtrArray *uids; @@ -892,13 +923,16 @@ action_mail_forward_quoted_cb (GtkAction *action, } static void -action_mail_label_change_more_cb (GtkAction *action, - EMailReader *reader); +action_mail_label_change_more_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data); static void -action_mail_label_new_cb (GtkAction *action, - EMailReader *reader) +action_mail_label_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailLabelDialog *label_dialog; EMailLabelListStore *label_store; EMailBackend *backend; @@ -975,9 +1009,11 @@ action_mail_label_new_cb (GtkAction *action, } static void -action_mail_label_none_cb (GtkAction *action, - EMailReader *reader) +action_mail_label_none_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailBackend *backend; EMailSession *session; EMailLabelListStore *label_store; @@ -1024,9 +1060,11 @@ action_mail_label_none_cb (GtkAction *action, } static void -action_mail_load_images_cb (GtkAction *action, - EMailReader *reader) +action_mail_load_images_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *display; display = e_mail_reader_get_mail_display (reader); @@ -1035,9 +1073,11 @@ action_mail_load_images_cb (GtkAction *action, } static void -action_mail_mark_important_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_important_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; guint32 mask = CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_DELETED; guint32 set = CAMEL_MESSAGE_FLAGGED; @@ -1045,9 +1085,11 @@ action_mail_mark_important_cb (GtkAction *action, } static void -action_mail_mark_junk_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_junk_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_JUNK | @@ -1098,9 +1140,11 @@ action_mail_mark_junk_cb (GtkAction *action, } static void -action_mail_mark_notjunk_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_notjunk_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; guint32 mask = CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_NOTJUNK | @@ -1118,9 +1162,11 @@ action_mail_mark_notjunk_cb (GtkAction *action, } static void -action_mail_mark_read_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_read_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; guint32 mask = CAMEL_MESSAGE_SEEN; guint32 set = CAMEL_MESSAGE_SEEN; @@ -1128,9 +1174,11 @@ action_mail_mark_read_cb (GtkAction *action, } static void -action_mail_mark_unimportant_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_unimportant_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; guint32 mask = CAMEL_MESSAGE_FLAGGED; guint32 set = 0; @@ -1138,37 +1186,51 @@ action_mail_mark_unimportant_cb (GtkAction *action, } static void -action_mail_mark_ignore_thread_sub_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_ignore_thread_sub_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_mark_selected_ignore_thread (reader, E_IGNORE_THREAD_SUBSET_SET); } static void -action_mail_mark_unignore_thread_sub_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_unignore_thread_sub_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_mark_selected_ignore_thread (reader, E_IGNORE_THREAD_SUBSET_UNSET); } static void -action_mail_mark_ignore_thread_whole_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_ignore_thread_whole_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_mark_selected_ignore_thread (reader, E_IGNORE_THREAD_WHOLE_SET); } static void -action_mail_mark_unignore_thread_whole_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_unignore_thread_whole_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_mark_selected_ignore_thread (reader, E_IGNORE_THREAD_WHOLE_UNSET); } static void -action_mail_mark_unread_cb (GtkAction *action, - EMailReader *reader) +action_mail_mark_unread_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWidget *message_list; EMFolderTreeModel *model; CamelFolder *folder; @@ -1196,9 +1258,11 @@ action_mail_mark_unread_cb (GtkAction *action, } static void -action_mail_message_edit_cb (GtkAction *action, - EMailReader *reader) +action_mail_message_edit_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EShell *shell; EMailBackend *backend; ESourceRegistry *registry; @@ -1261,9 +1325,11 @@ mail_reader_new_composer_created_cb (GObject *source_object, } static void -action_mail_message_new_cb (GtkAction *action, - EMailReader *reader) +action_mail_message_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EShell *shell; EMailBackend *backend; EShellBackend *shell_backend; @@ -1303,16 +1369,24 @@ action_mail_message_new_cb (GtkAction *action, } static void -action_mail_message_open_cb (GtkAction *action, - EMailReader *reader) +action_mail_message_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + + if (E_IS_MAIL_BROWSER (reader)) + return; + e_mail_reader_open_selected_mail (reader); } static void -action_mail_archive_cb (GtkAction *action, - EMailReader *reader) +action_mail_archive_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; CamelFolder *folder; EMailBackend *backend; EMailSession *session; @@ -1417,16 +1491,21 @@ action_mail_archive_cb (GtkAction *action, } static void -action_mail_move_cb (GtkAction *action, - EMailReader *reader) +action_mail_move_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + mail_reader_copy_or_move_selected_messages (reader, TRUE); } static void -action_mail_next_cb (GtkAction *action, - EMailReader *reader) +action_mail_next_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWidget *message_list; MessageListSelectDirection direction; guint32 flags, mask; @@ -1442,9 +1521,11 @@ action_mail_next_cb (GtkAction *action, } static void -action_mail_next_important_cb (GtkAction *action, - EMailReader *reader) +action_mail_next_important_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWidget *message_list; MessageListSelectDirection direction; guint32 flags, mask; @@ -1460,9 +1541,11 @@ action_mail_next_important_cb (GtkAction *action, } static void -action_mail_next_thread_cb (GtkAction *action, - EMailReader *reader) +action_mail_next_thread_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWidget *message_list; message_list = e_mail_reader_get_message_list (reader); @@ -1526,16 +1609,21 @@ mail_reader_select_unread (EMailReader *reader, } static void -action_mail_next_unread_cb (GtkAction *action, - EMailReader *reader) +action_mail_next_unread_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + mail_reader_select_unread (reader, TRUE); } static void -action_mail_previous_cb (GtkAction *action, - EMailReader *reader) +action_mail_previous_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWidget *message_list; MessageListSelectDirection direction; guint32 flags, mask; @@ -1551,9 +1639,11 @@ action_mail_previous_cb (GtkAction *action, } static void -action_mail_previous_important_cb (GtkAction *action, - EMailReader *reader) +action_mail_previous_important_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWidget *message_list; MessageListSelectDirection direction; guint32 flags, mask; @@ -1569,9 +1659,11 @@ action_mail_previous_important_cb (GtkAction *action, } static void -action_mail_previous_thread_cb (GtkAction *action, - EMailReader *reader) +action_mail_previous_thread_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkWidget *message_list; message_list = e_mail_reader_get_message_list (reader); @@ -1580,16 +1672,20 @@ action_mail_previous_thread_cb (GtkAction *action, } static void -action_mail_previous_unread_cb (GtkAction *action, - EMailReader *reader) +action_mail_previous_unread_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; mail_reader_select_unread (reader, FALSE); } static void -action_mail_print_cb (GtkAction *action, - EMailReader *reader) +action_mail_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkPrintOperationAction print_action; print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG; @@ -1597,9 +1693,11 @@ action_mail_print_cb (GtkAction *action, } static void -action_mail_print_preview_cb (GtkAction *action, - EMailReader *reader) +action_mail_print_preview_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkPrintOperationAction print_action; print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW; @@ -1655,9 +1753,11 @@ mail_reader_redirect_cb (CamelFolder *folder, } static void -action_mail_redirect_cb (GtkAction *action, - EMailReader *reader) +action_mail_redirect_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EActivity *activity; GCancellable *cancellable; EMailReaderClosure *closure; @@ -1788,9 +1888,11 @@ exit: } static void -action_mail_reply_all_cb (GtkAction *action, - EMailReader *reader) +action_mail_reply_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GSettings *settings; const gchar *key; guint32 state; @@ -1905,9 +2007,11 @@ action_mail_reply_alternative_got_message (GObject *source_object, } static void -action_mail_reply_alternative_cb (GtkAction *action, - EMailReader *reader) +action_mail_reply_alternative_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EActivity *activity; GCancellable *cancellable; EMailReaderClosure *closure; @@ -1930,9 +2034,11 @@ action_mail_reply_alternative_cb (GtkAction *action, } static void -action_mail_reply_group_cb (GtkAction *action, - EMailReader *reader) +action_mail_reply_group_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GSettings *settings; gboolean reply_list; guint32 state; @@ -1951,13 +2057,16 @@ action_mail_reply_group_cb (GtkAction *action, e_mail_reader_reply_to_message ( reader, NULL, E_MAIL_REPLY_TO_LIST); } else - action_mail_reply_all_cb (action, reader); + action_mail_reply_all_cb (action, NULL, reader); } static void -action_mail_reply_list_cb (GtkAction *action, - EMailReader *reader) +action_mail_reply_list_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_reply_to_message (reader, NULL, E_MAIL_REPLY_TO_LIST); } @@ -2263,9 +2372,11 @@ exit: } static void -action_mail_reply_sender_cb (GtkAction *action, - EMailReader *reader) +action_mail_reply_sender_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GSettings *settings; gboolean ask_list_reply_to; gboolean ask_private_list_reply; @@ -2322,54 +2433,76 @@ action_mail_reply_sender_cb (GtkAction *action, } static void -action_mail_reply_recipient_cb (GtkAction *action, - EMailReader *reader) +action_mail_reply_recipient_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_reply_to_message (reader, NULL, E_MAIL_REPLY_TO_RECIPIENT); } static void -action_mail_save_as_cb (GtkAction *action, - EMailReader *reader) +action_mail_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_save_messages (reader); } static void -action_mail_search_folder_from_mailing_list_cb (GtkAction *action, - EMailReader *reader) +action_mail_search_folder_from_mailing_list_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_create_vfolder_from_selected (reader, AUTO_MLIST); } static void -action_mail_search_folder_from_recipients_cb (GtkAction *action, - EMailReader *reader) +action_mail_search_folder_from_recipients_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_create_vfolder_from_selected (reader, AUTO_TO); } static void -action_mail_search_folder_from_sender_cb (GtkAction *action, - EMailReader *reader) +action_mail_search_folder_from_sender_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_create_vfolder_from_selected (reader, AUTO_FROM); } static void -action_mail_search_folder_from_subject_cb (GtkAction *action, - EMailReader *reader) +action_mail_search_folder_from_subject_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; + e_mail_reader_create_vfolder_from_selected (reader, AUTO_SUBJECT); } static void -action_mail_show_all_headers_cb (GtkToggleAction *action, - EMailReader *reader) +action_mail_show_all_headers_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *display; EMailFormatterMode mode; + e_ui_action_set_state (action, parameter); + display = e_mail_reader_get_mail_display (reader); /* Ignore action when viewing message source. */ @@ -2379,7 +2512,7 @@ action_mail_show_all_headers_cb (GtkToggleAction *action, if (mode == E_MAIL_FORMATTER_MODE_RAW) return; - if (gtk_toggle_action_get_active (action)) + if (e_ui_action_get_active (action)) mode = E_MAIL_FORMATTER_MODE_ALL_HEADERS; else mode = E_MAIL_FORMATTER_MODE_NORMAL; @@ -2435,9 +2568,11 @@ mail_source_retrieved (GObject *source_object, } static void -action_mail_show_source_cb (GtkAction *action, - EMailReader *reader) +action_mail_show_source_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *display; EMailBackend *backend; GtkWidget *browser; @@ -2506,9 +2641,11 @@ action_mail_show_source_cb (GtkAction *action, } static void -action_mail_toggle_important_cb (GtkAction *action, - EMailReader *reader) +action_mail_toggle_important_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; CamelFolder *folder; GPtrArray *uids; guint ii; @@ -2542,9 +2679,11 @@ action_mail_toggle_important_cb (GtkAction *action, } static void -action_mail_undelete_cb (GtkAction *action, - EMailReader *reader) +action_mail_undelete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; guint32 mask = CAMEL_MESSAGE_DELETED; guint32 set = 0; @@ -2552,9 +2691,11 @@ action_mail_undelete_cb (GtkAction *action, } static void -action_mail_zoom_100_cb (GtkAction *action, - EMailReader *reader) +action_mail_zoom_100_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *display; display = e_mail_reader_get_mail_display (reader); @@ -2563,9 +2704,11 @@ action_mail_zoom_100_cb (GtkAction *action, } static void -action_mail_zoom_in_cb (GtkAction *action, - EMailReader *reader) +action_mail_zoom_in_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *display; display = e_mail_reader_get_mail_display (reader); @@ -2574,9 +2717,11 @@ action_mail_zoom_in_cb (GtkAction *action, } static void -action_mail_zoom_out_cb (GtkAction *action, - EMailReader *reader) +action_mail_zoom_out_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *display; display = e_mail_reader_get_mail_display (reader); @@ -2585,22 +2730,26 @@ action_mail_zoom_out_cb (GtkAction *action, } static void -action_mail_search_web_cb (GtkAction *action, - EMailReader *reader) +action_mail_search_web_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailDisplay *display; - GtkAction *wv_action; + EUIAction *wv_action; display = e_mail_reader_get_mail_display (reader); wv_action = e_web_view_get_action (E_WEB_VIEW (display), "search-web"); - gtk_action_activate (wv_action); + g_action_activate (G_ACTION (wv_action), NULL); } static void -action_search_folder_recipient_cb (GtkAction *action, - EMailReader *reader) +action_search_folder_recipient_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailBackend *backend; EMailSession *session; EWebView *web_view; @@ -2639,9 +2788,11 @@ action_search_folder_recipient_cb (GtkAction *action, } static void -action_search_folder_sender_cb (GtkAction *action, - EMailReader *reader) +action_search_folder_sender_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; EMailBackend *backend; EMailSession *session; EWebView *web_view; @@ -2679,757 +2830,897 @@ action_search_folder_sender_cb (GtkAction *action, camel_url_free (curl); } -static GtkActionEntry mail_reader_entries[] = { - - { "mail-add-sender", - NULL, - N_("A_dd Sender to Address Book"), - NULL, - N_("Add sender to address book"), - G_CALLBACK (action_mail_add_sender_cb) }, - - { "mail-archive", - "mail-archive", - N_("_Archive"), - "a", - N_("Move selected messages to the Archive folder for the account"), - G_CALLBACK (action_mail_archive_cb) }, - - { "mail-check-for-junk", - "mail-mark-junk", - N_("Check for _Junk"), - "j", - N_("Filter the selected messages for junk status"), - G_CALLBACK (action_mail_check_for_junk_cb) }, - - { "mail-color-assign", - NULL, - N_("Assign C_olor…"), - NULL, - N_("Assign color for the selected messages"), - G_CALLBACK (action_mail_color_assign_cb) }, - - { "mail-color-unset", - NULL, - N_("Unse_t Color"), - NULL, - N_("Unset color for the selected messages"), - G_CALLBACK (action_mail_color_unset_cb) }, - - { "mail-copy", - "mail-copy", - N_("_Copy to Folder…"), - "y", - N_("Copy selected messages to another folder"), - G_CALLBACK (action_mail_copy_cb) }, - - { "mail-delete", - "user-trash", - N_("_Delete Message"), - "d", - N_("Mark the selected messages for deletion"), - G_CALLBACK (action_mail_delete_cb) }, - - { "mail-add-note", - "evolution-memos", - N_("_Add note…"), - NULL, - N_("Add a note for the selected message"), - G_CALLBACK (action_mail_edit_note_cb) }, - - { "mail-delete-note", - NULL, - N_("Delete no_te"), - NULL, - N_("Delete the note for the selected message"), - G_CALLBACK (action_mail_delete_note_cb) }, - - { "mail-edit-note", - "evolution-memos", - N_("_Edit note…"), - NULL, - N_("Edit a note for the selected message"), - G_CALLBACK (action_mail_edit_note_cb) }, - - { "mail-filter-rule-for-mailing-list", - NULL, - N_("Create a Filter Rule for Mailing _List…"), - NULL, - N_("Create a rule to filter messages to this mailing list"), - G_CALLBACK (action_mail_filter_on_mailing_list_cb) }, - - { "mail-filter-rule-for-recipients", - NULL, - N_("Create a Filter Rule for _Recipients…"), - NULL, - N_("Create a rule to filter messages to these recipients"), - G_CALLBACK (action_mail_filter_on_recipients_cb) }, - - { "mail-filter-rule-for-sender", - NULL, - N_("Create a Filter Rule for Se_nder…"), - NULL, - N_("Create a rule to filter messages from this sender"), - G_CALLBACK (action_mail_filter_on_sender_cb) }, - - { "mail-filter-rule-for-subject", - NULL, - N_("Create a Filter Rule for _Subject…"), - NULL, - N_("Create a rule to filter messages with this subject"), - G_CALLBACK (action_mail_filter_on_subject_cb) }, - - { "mail-filters-apply", - "stock_mail-filters-apply", - N_("A_pply Filters"), - "y", - N_("Apply filter rules to the selected messages"), - G_CALLBACK (action_mail_filters_apply_cb) }, - - { "mail-find", - "edit-find", - N_("_Find in Message…"), - "f", - N_("Search for text in the body of the displayed message"), - G_CALLBACK (action_mail_find_cb) }, - - { "mail-flag-clear", - NULL, - N_("_Clear Flag"), - NULL, - N_("Remove the follow-up flag from the selected messages"), - G_CALLBACK (action_mail_flag_clear_cb) }, - - { "mail-flag-completed", - NULL, - N_("_Flag Completed"), - NULL, - N_("Set the follow-up flag to completed on the selected messages"), - G_CALLBACK (action_mail_flag_completed_cb) }, - - { "mail-flag-for-followup", - "stock_mail-flag-for-followup", - N_("Follow _Up…"), - "g", - N_("Flag the selected messages for follow-up"), - G_CALLBACK (action_mail_flag_for_followup_cb) }, - - { "mail-forward", - "mail-forward", - N_("_Forward"), - "f", - N_("Forward the selected message to someone"), - G_CALLBACK (action_mail_forward_cb) }, - - { "mail-forward-attached", - NULL, - N_("_Attached"), - NULL, - N_("Forward the selected message to someone as an attachment"), - G_CALLBACK (action_mail_forward_attached_cb) }, - - { "mail-forward-attached-full", - NULL, - N_("Forward As _Attached"), - NULL, - N_("Forward the selected message to someone as an attachment"), - G_CALLBACK (action_mail_forward_attached_cb) }, - - { "mail-forward-inline", - NULL, - N_("_Inline"), - NULL, - N_("Forward the selected message in the body of a new message"), - G_CALLBACK (action_mail_forward_inline_cb) }, - - { "mail-forward-inline-full", - NULL, - N_("Forward As _Inline"), - NULL, - N_("Forward the selected message in the body of a new message"), - G_CALLBACK (action_mail_forward_inline_cb) }, - - { "mail-forward-quoted", - NULL, - N_("_Quoted"), - NULL, - N_("Forward the selected message quoted like a reply"), - G_CALLBACK (action_mail_forward_quoted_cb) }, - - { "mail-forward-quoted-full", - NULL, - N_("Forward As _Quoted"), - NULL, - N_("Forward the selected message quoted like a reply"), - G_CALLBACK (action_mail_forward_quoted_cb) }, - - { "mail-label-change-more", - NULL, - N_("Change _More Labels…"), - "l", - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mail_label_change_more_cb) }, - - { "mail-label-new", - NULL, - N_("_New Label"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mail_label_new_cb) }, - - { "mail-label-none", - NULL, - /* Translators: "None" is used in the message label context menu. - * It removes all labels from the selected messages. */ - N_("N_one"), - "0", - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mail_label_none_cb) }, - - { "mail-load-images", - "image-x-generic", - N_("_Load Images"), - "i", - N_("Force images in HTML mail to be loaded"), - G_CALLBACK (action_mail_load_images_cb) }, - - { "mail-mark-ignore-thread-sub", - NULL, - N_("_Ignore Subthread"), - NULL, - N_("Mark new mails in a subthread as read automatically"), - G_CALLBACK (action_mail_mark_ignore_thread_sub_cb) }, - - { "mail-mark-ignore-thread-whole", - NULL, - N_("_Ignore Thread"), - NULL, - N_("Mark new mails in this thread as read automatically"), - G_CALLBACK (action_mail_mark_ignore_thread_whole_cb) }, - - { "mail-mark-important", - "mail-mark-important", - N_("_Important"), - NULL, - N_("Mark the selected messages as important"), - G_CALLBACK (action_mail_mark_important_cb) }, - - { "mail-mark-junk", - "mail-mark-junk", - N_("_Junk"), - "j", - N_("Mark the selected messages as junk"), - G_CALLBACK (action_mail_mark_junk_cb) }, - - { "mail-mark-notjunk", - "mail-mark-notjunk", - N_("_Not Junk"), - "j", - N_("Mark the selected messages as not being junk"), - G_CALLBACK (action_mail_mark_notjunk_cb) }, - - { "mail-mark-read", - "mail-mark-read", - N_("_Read"), - "k", - N_("Mark the selected messages as having been read"), - G_CALLBACK (action_mail_mark_read_cb) }, - - { "mail-mark-unignore-thread-sub", - NULL, - N_("Do not _Ignore Subthread"), - NULL, - N_("Do not mark new mails in a subthread as read automatically"), - G_CALLBACK (action_mail_mark_unignore_thread_sub_cb) }, - - { "mail-mark-unignore-thread-whole", - NULL, - N_("Do not _Ignore Thread"), - NULL, - N_("Do not mark new mails in this thread as read automatically"), - G_CALLBACK (action_mail_mark_unignore_thread_whole_cb) }, - - { "mail-mark-unimportant", - NULL, - N_("Uni_mportant"), - NULL, - N_("Mark the selected messages as unimportant"), - G_CALLBACK (action_mail_mark_unimportant_cb) }, - - { "mail-mark-unread", - "mail-mark-unread", - N_("_Unread"), - "k", - N_("Mark the selected messages as not having been read"), - G_CALLBACK (action_mail_mark_unread_cb) }, - - { "mail-message-edit", - NULL, - N_("_Edit as New Message…"), - NULL, - N_("Open the selected messages in the composer for editing"), - G_CALLBACK (action_mail_message_edit_cb) }, - - { "mail-message-new", - "mail-message-new", - N_("Compose _New Message"), - "m", - N_("Open a window for composing a mail message"), - G_CALLBACK (action_mail_message_new_cb) }, - - { "mail-message-open", - NULL, - N_("_Open in New Window"), - "o", - N_("Open the selected messages in a new window"), - G_CALLBACK (action_mail_message_open_cb) }, - - { "mail-move", - "mail-move", - N_("_Move to Folder…"), - "v", - N_("Move selected messages to another folder"), - G_CALLBACK (action_mail_move_cb) }, - - { "mail-next", - "go-next", - N_("_Next Message"), - "Page_Down", - N_("Display the next message"), - G_CALLBACK (action_mail_next_cb) }, - - { "mail-next-important", - NULL, - N_("Next _Important Message"), - NULL, - N_("Display the next important message"), - G_CALLBACK (action_mail_next_important_cb) }, - - { "mail-next-thread", - NULL, - N_("Next _Thread"), - NULL, - N_("Display the next thread"), - G_CALLBACK (action_mail_next_thread_cb) }, - - { "mail-next-unread", - "go-jump", - N_("Next _Unread Message"), - "bracketright", - N_("Display the next unread message"), - G_CALLBACK (action_mail_next_unread_cb) }, - - { "mail-previous", - "go-previous", - N_("_Previous Message"), - "Page_Up", - N_("Display the previous message"), - G_CALLBACK (action_mail_previous_cb) }, - - { "mail-previous-important", - NULL, - N_("Pr_evious Important Message"), - NULL, - N_("Display the previous important message"), - G_CALLBACK (action_mail_previous_important_cb) }, - - { "mail-previous-thread", - NULL, - N_("Previous T_hread"), - NULL, - N_("Display the previous thread"), - G_CALLBACK (action_mail_previous_thread_cb) }, - - { "mail-previous-unread", - NULL, - N_("P_revious Unread Message"), - "bracketleft", - N_("Display the previous unread message"), - G_CALLBACK (action_mail_previous_unread_cb) }, - - { "mail-print", - "document-print", - N_("_Print…"), - "p", - N_("Print this message"), - G_CALLBACK (action_mail_print_cb) }, - - { "mail-print-preview", - "document-print-preview", - N_("Pre_view…"), - NULL, - N_("Preview the message to be printed"), - G_CALLBACK (action_mail_print_preview_cb) }, - - { "mail-redirect", - NULL, - N_("Re_direct"), - NULL, - N_("Redirect (bounce) the selected message to someone"), - G_CALLBACK (action_mail_redirect_cb) }, - - { "mail-remove-attachments", - "edit-delete", - N_("Remo_ve Attachments"), - NULL, - N_("Remove attachments"), - G_CALLBACK (action_mail_remove_attachments_cb) }, - - { "mail-remove-duplicates", - NULL, - N_("Remove Du_plicate Messages"), - NULL, - N_("Checks selected messages for duplicates"), - G_CALLBACK (action_mail_remove_duplicates_cb) }, - - { "mail-reply-all", - NULL, - N_("Reply to _All"), - "r", - N_("Compose a reply to all the recipients of the selected message"), - G_CALLBACK (action_mail_reply_all_cb) }, - - { "mail-reply-alternative", - NULL, - N_("Al_ternative Reply…"), - "r", - N_("Choose reply options for the selected message"), - G_CALLBACK (action_mail_reply_alternative_cb) }, - - { "mail-reply-group", - "mail-reply-all", - N_("Group Reply"), - "g", - N_("Reply to the mailing list, or to all recipients"), - G_CALLBACK (action_mail_reply_group_cb) }, - - { "mail-reply-list", - NULL, - N_("Reply to _List"), - "l", - N_("Compose a reply to the mailing list of the selected message"), - G_CALLBACK (action_mail_reply_list_cb) }, - - { "mail-reply-sender", - "mail-reply-sender", - N_("_Reply to Sender"), - "r", - N_("Compose a reply to the sender of the selected message"), - G_CALLBACK (action_mail_reply_sender_cb) }, - - { "mail-reply-template", - NULL, - N_("Repl_y with Template"), - NULL, - NULL, - NULL }, - - { "mail-save-as", - "document-save-as", - N_("_Save to File…"), - "s", - N_("Save selected messages as an mbox file"), - G_CALLBACK (action_mail_save_as_cb) }, - - { "mail-search-web", - NULL, - N_("Search _Web…"), - NULL, - N_("Search the Web with the selected text"), - G_CALLBACK (action_mail_search_web_cb) }, - - { "mail-show-source", - NULL, - N_("_Message Source"), - "u", - N_("Show the raw email source of the message"), - G_CALLBACK (action_mail_show_source_cb) }, - - { "mail-toggle-important", - NULL, - NULL, /* No menu item; key press only */ - NULL, - NULL, - G_CALLBACK (action_mail_toggle_important_cb) }, - - { "mail-undelete", - NULL, - N_("_Undelete Message"), - "d", - N_("Undelete the selected messages"), - G_CALLBACK (action_mail_undelete_cb) }, - - { "mail-zoom-100", - "zoom-original", - N_("_Normal Size"), - "0", - N_("Reset the text to its original size"), - G_CALLBACK (action_mail_zoom_100_cb) }, - - { "mail-zoom-in", - "zoom-in", - N_("_Zoom In"), - "plus", - N_("Increase the text size"), - G_CALLBACK (action_mail_zoom_in_cb) }, - - { "mail-zoom-out", - "zoom-out", - N_("Zoom _Out"), - "minus", - N_("Decrease the text size"), - G_CALLBACK (action_mail_zoom_out_cb) }, - - /*** Menus ***/ - - { "mail-create-menu", - NULL, - N_("Cre_ate"), - NULL, - NULL, - NULL }, - - { "mail-encoding-menu", - NULL, - N_("Ch_aracter Encoding"), - NULL, - NULL, - NULL }, - - { "mail-forward-as-menu", - NULL, - N_("F_orward As"), - NULL, - NULL, - NULL }, - - { "mail-label-menu", - NULL, - N_("_Label"), - NULL, - NULL, - NULL }, - - { "mail-reply-group-menu", - NULL, - N_("_Group Reply"), - NULL, - NULL, - NULL }, - - { "mail-goto-menu", - NULL, - N_("_Go To"), - NULL, - NULL, - NULL }, - - { "mail-mark-as-menu", - NULL, - N_("Mar_k As"), - NULL, - NULL, - NULL }, - - { "mail-message-menu", - NULL, - N_("_Message"), - NULL, - NULL, - NULL }, - - { "mail-zoom-menu", - NULL, - N_("_Zoom"), - NULL, - NULL, - NULL } -}; - -static GtkActionEntry mail_reader_search_folder_entries[] = { - - { "mail-search-folder-from-mailing-list", - NULL, - N_("Create a Search Folder from Mailing _List…"), - NULL, - N_("Create a search folder for this mailing list"), - G_CALLBACK (action_mail_search_folder_from_mailing_list_cb) }, - - { "mail-search-folder-from-recipients", - NULL, - N_("Create a Search Folder from Recipien_ts…"), - NULL, - N_("Create a search folder for these recipients"), - G_CALLBACK (action_mail_search_folder_from_recipients_cb) }, - - { "mail-search-folder-from-sender", - NULL, - N_("Create a Search Folder from Sen_der…"), - NULL, - N_("Create a search folder for this sender"), - G_CALLBACK (action_mail_search_folder_from_sender_cb) }, - - { "mail-search-folder-from-subject", - NULL, - N_("Create a Search Folder from S_ubject…"), - NULL, - N_("Create a search folder for this subject"), - G_CALLBACK (action_mail_search_folder_from_subject_cb) }, -}; - -static EPopupActionEntry mail_reader_popup_entries[] = { - - { "mail-popup-archive", - NULL, - "mail-archive" }, - - { "mail-popup-color-assign", - NULL, - "mail-color-assign" }, - - { "mail-popup-color-unset", - NULL, - "mail-color-unset" }, - - { "mail-popup-copy", - NULL, - "mail-copy" }, - - { "mail-popup-delete", - NULL, - "mail-delete" }, - - { "mail-popup-add-note", - NULL, - "mail-add-note" }, - - { "mail-popup-delete-note", - NULL, - "mail-delete-note" }, - - { "mail-popup-edit-note", - NULL, - "mail-edit-note" }, - - { "mail-popup-flag-clear", - NULL, - "mail-flag-clear" }, - - { "mail-popup-flag-completed", - NULL, - "mail-flag-completed" }, - - { "mail-popup-flag-for-followup", - N_("Mark for Follo_w Up…"), - "mail-flag-for-followup" }, - - { "mail-popup-forward", - NULL, - "mail-forward" }, - - { "mail-popup-mark-ignore-thread-sub", - N_("_Ignore Subthread"), - "mail-mark-ignore-thread-sub" }, - - { "mail-popup-mark-ignore-thread-whole", - N_("_Ignore Thread"), - "mail-mark-ignore-thread-whole" }, - - { "mail-popup-mark-important", - N_("Mark as _Important"), - "mail-mark-important" }, - - { "mail-popup-mark-junk", - N_("Mark as _Junk"), - "mail-mark-junk" }, - - { "mail-popup-mark-notjunk", - N_("Mark as _Not Junk"), - "mail-mark-notjunk" }, - - { "mail-popup-mark-read", - N_("Mar_k as Read"), - "mail-mark-read" }, - - { "mail-popup-mark-unignore-thread-sub", - N_("Do not _Ignore Subthread"), - "mail-mark-unignore-thread-sub" }, - - { "mail-popup-mark-unignore-thread-whole", - N_("Do not _Ignore Thread"), - "mail-mark-unignore-thread-whole" }, - - { "mail-popup-mark-unimportant", - N_("Mark as Uni_mportant"), - "mail-mark-unimportant" }, - - { "mail-popup-mark-unread", - N_("Mark as _Unread"), - "mail-mark-unread" }, - - { "mail-popup-message-edit", - NULL, - "mail-message-edit" }, - - { "mail-popup-move", - NULL, - "mail-move" }, - - { "mail-popup-print", - NULL, - "mail-print" }, - - { "mail-popup-remove-attachments", - NULL, - "mail-remove-attachments" }, - - { "mail-popup-remove-duplicates", - NULL, - "mail-remove-duplicates" }, - - { "mail-popup-reply-all", - NULL, - "mail-reply-all" }, - - { "mail-popup-reply-sender", - NULL, - "mail-reply-sender" }, - - { "mail-popup-reply-template", - NULL, - "mail-reply-template" }, - - { "mail-popup-save-as", - NULL, - "mail-save-as" }, - - { "mail-popup-search-web", - NULL, - "mail-search-web" }, - - { "mail-popup-undelete", - NULL, - "mail-undelete" } -}; - -static GtkToggleActionEntry mail_reader_toggle_entries[] = { - - { "mail-caret-mode", - NULL, - N_("_Caret Mode"), - "F7", - N_("Show a blinking cursor in the body of displayed messages"), - NULL, /* No callback required */ - FALSE }, - - { "mail-show-all-headers", - NULL, - N_("All Message _Headers"), - NULL, - N_("Show messages with all email headers"), - G_CALLBACK (action_mail_show_all_headers_cb), - FALSE } -}; +static void +charset_menu_change_state_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EMailReader *self = user_data; + EMailFormatter *formatter; + EMailDisplay *mail_display; + + g_return_if_fail (E_IS_MAIL_READER (self)); + + e_ui_action_set_state (action, parameter); + + mail_display = e_mail_reader_get_mail_display (self); + formatter = mail_display ? e_mail_display_get_formatter (mail_display) : NULL; + + if (formatter) { + const gchar *charset; + + charset = g_variant_get_string (parameter, NULL); + + /* Default value is an empty string in the GMenu, but a NULL for the formatter */ + if (charset && !*charset) + charset = NULL; + + e_mail_formatter_set_charset (formatter, charset); + } +} + +static gboolean +e_mail_reader_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EMailReader *self = user_data; + EMailReaderPrivate *priv; + const gchar *name; + + g_return_val_if_fail (E_IS_MAIL_READER (self), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "EMailReader::")) + return FALSE; + + priv = E_MAIL_READER_GET_PRIVATE (self); + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (is_action ("EMailReader::mail-reply-group") || + is_action ("EMailReader::mail-forward-as-group")) { + EUIAction *tool_action; + GMenuModel *menu_model; + + if (is_action ("EMailReader::mail-reply-group")) { + tool_action = e_ui_manager_get_action (ui_manager, "mail-reply-group"); + menu_model = priv->reply_group_menu; + } else { + tool_action = e_ui_manager_get_action (ui_manager, "mail-forward"); + menu_model = priv->forward_as_menu; + } + + *out_item = e_ui_manager_create_item_from_menu_model (ui_manager, elem, tool_action, for_kind, menu_model); + } else if (for_kind == E_UI_ELEMENT_KIND_MENU) { + if (is_action ("EMailReader::charset-menu")) { + GMenu *charset_menu; + GMenuItem *menu_item; + EMailDisplay *mail_display; + + charset_menu = g_menu_new (); + + menu_item = g_menu_item_new (_("_Default"), NULL); + g_menu_item_set_action_and_target (menu_item, "mail.EMailReader::charset-menu", "s", ""); + g_menu_append_item (charset_menu, menu_item); + g_clear_object (&menu_item); + + e_charset_add_to_g_menu (charset_menu, "mail.EMailReader::charset-menu"); + + *out_item = G_OBJECT (g_menu_item_new_submenu (e_ui_action_get_label (action), G_MENU_MODEL (charset_menu))); + + g_clear_object (&charset_menu); + + mail_display = e_mail_reader_get_mail_display (self); + + if (mail_display) { + EMailFormatter *formatter; + + formatter = e_mail_display_get_formatter (mail_display); + if (formatter) { + const gchar *charset; + + charset = e_mail_formatter_get_charset (formatter); + e_ui_action_set_state (action, g_variant_new_string (charset ? charset : "")); + } else { + e_ui_action_set_state (action, g_variant_new_string ("")); + } + } else { + e_ui_action_set_state (action, g_variant_new_string ("")); + } + } else if (is_action ("EMailReader::mail-label-actions")) { + *out_item = G_OBJECT (g_menu_item_new_section (NULL, G_MENU_MODEL (priv->labels_menu))); + } else { + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + #undef is_action + + return TRUE; +} + +void +e_mail_reader_init_ui_data_default (EMailReader *self) +{ + static const EUIActionEntry mail_entries[] = { + + { "mail-add-sender", + NULL, + N_("A_dd Sender to Address Book"), + NULL, + N_("Add sender to address book"), + action_mail_add_sender_cb, NULL, NULL, NULL }, + + { "mail-archive", + "mail-archive", + N_("_Archive"), + "a", + N_("Move selected messages to the Archive folder for the account"), + action_mail_archive_cb, NULL, NULL, NULL }, + + { "mail-check-for-junk", + "mail-mark-junk", + N_("Check for _Junk"), + "j", + N_("Filter the selected messages for junk status"), + action_mail_check_for_junk_cb, NULL, NULL, NULL }, + + { "mail-color-assign", + NULL, + N_("Assign C_olor…"), + NULL, + N_("Assign color for the selected messages"), + action_mail_color_assign_cb, NULL, NULL, NULL }, + + { "mail-color-unset", + NULL, + N_("Unse_t Color"), + NULL, + N_("Unset color for the selected messages"), + action_mail_color_unset_cb, NULL, NULL, NULL }, + + { "mail-copy", + "mail-copy", + N_("_Copy to Folder…"), + "y", + N_("Copy selected messages to another folder"), + action_mail_copy_cb, NULL, NULL, NULL }, + + { "mail-delete", + "user-trash", + N_("_Delete Message"), + "d", + N_("Mark the selected messages for deletion"), + action_mail_delete_cb, NULL, NULL, NULL }, + + { "mail-add-note", + "evolution-memos", + N_("_Add note…"), + NULL, + N_("Add a note for the selected message"), + action_mail_edit_note_cb, NULL, NULL, NULL }, + + { "mail-delete-note", + NULL, + N_("Delete no_te"), + NULL, + N_("Delete the note for the selected message"), + action_mail_delete_note_cb, NULL, NULL, NULL }, + + { "mail-edit-note", + "evolution-memos", + N_("_Edit note…"), + NULL, + N_("Edit a note for the selected message"), + action_mail_edit_note_cb, NULL, NULL, NULL }, + + { "mail-filter-rule-for-mailing-list", + NULL, + N_("Create a Filter Rule for Mailing _List…"), + NULL, + N_("Create a rule to filter messages to this mailing list"), + action_mail_filter_on_mailing_list_cb, NULL, NULL, NULL }, + + { "mail-filter-rule-for-recipients", + NULL, + N_("Create a Filter Rule for _Recipients…"), + NULL, + N_("Create a rule to filter messages to these recipients"), + action_mail_filter_on_recipients_cb, NULL, NULL, NULL }, + + { "mail-filter-rule-for-sender", + NULL, + N_("Create a Filter Rule for Se_nder…"), + NULL, + N_("Create a rule to filter messages from this sender"), + action_mail_filter_on_sender_cb, NULL, NULL, NULL }, + + { "mail-filter-rule-for-subject", + NULL, + N_("Create a Filter Rule for _Subject…"), + NULL, + N_("Create a rule to filter messages with this subject"), + action_mail_filter_on_subject_cb, NULL, NULL, NULL }, + + { "mail-filters-apply", + "stock_mail-filters-apply", + N_("A_pply Filters"), + "y", + N_("Apply filter rules to the selected messages"), + action_mail_filters_apply_cb, NULL, NULL, NULL }, + + { "mail-find", + "edit-find", + N_("_Find in Message…"), + "f", + N_("Search for text in the body of the displayed message"), + action_mail_find_cb, NULL, NULL, NULL }, + + { "mail-flag-clear", + NULL, + N_("_Clear Flag"), + NULL, + N_("Remove the follow-up flag from the selected messages"), + action_mail_flag_clear_cb, NULL, NULL, NULL }, + + { "mail-flag-completed", + NULL, + N_("_Flag Completed"), + NULL, + N_("Set the follow-up flag to completed on the selected messages"), + action_mail_flag_completed_cb, NULL, NULL, NULL }, + + { "mail-flag-for-followup", + "stock_mail-flag-for-followup", + N_("Follow _Up…"), + "g", + N_("Flag the selected messages for follow-up"), + action_mail_flag_for_followup_cb, NULL, NULL, NULL }, + + { "mail-flag-for-followup-full", + "stock_mail-flag-for-followup", + N_("Mark for Follo_w Up…"), + NULL, + N_("Flag the selected messages for follow-up"), + action_mail_flag_for_followup_cb, NULL, NULL, NULL }, + + { "mail-forward", + "mail-forward", + N_("_Forward"), + "f", + N_("Forward the selected message to someone"), + action_mail_forward_cb, NULL, NULL, NULL }, + + { "mail-forward-attached", + NULL, + N_("_Attached"), + NULL, + N_("Forward the selected message to someone as an attachment"), + action_mail_forward_attached_cb, NULL, NULL, NULL }, + + { "mail-forward-attached-full", + NULL, + N_("Forward As _Attached"), + NULL, + N_("Forward the selected message to someone as an attachment"), + action_mail_forward_attached_cb, NULL, NULL, NULL }, + + { "mail-forward-inline", + NULL, + N_("_Inline"), + NULL, + N_("Forward the selected message in the body of a new message"), + action_mail_forward_inline_cb, NULL, NULL, NULL }, + + { "mail-forward-inline-full", + NULL, + N_("Forward As _Inline"), + NULL, + N_("Forward the selected message in the body of a new message"), + action_mail_forward_inline_cb, NULL, NULL, NULL }, + + { "mail-forward-quoted", + NULL, + N_("_Quoted"), + NULL, + N_("Forward the selected message quoted like a reply"), + action_mail_forward_quoted_cb, NULL, NULL, NULL }, + + { "mail-forward-quoted-full", + NULL, + N_("Forward As _Quoted"), + NULL, + N_("Forward the selected message quoted like a reply"), + action_mail_forward_quoted_cb, NULL, NULL, NULL }, + + { "mail-label-change-more", + NULL, + N_("Change _More Labels…"), + "l", + NULL, + action_mail_label_change_more_cb, NULL, NULL, NULL }, + + { "mail-label-new", + NULL, + N_("_New Label"), + NULL, + NULL, + action_mail_label_new_cb, NULL, NULL, NULL }, + + { "mail-label-none", + NULL, + /* Translators: "None" is used in the message label context menu. + * It removes all labels from the selected messages. */ + N_("N_one"), + "0", + NULL, + action_mail_label_none_cb, NULL, NULL, NULL }, + + { "mail-load-images", + "image-x-generic", + N_("_Load Images"), + "i", + N_("Force images in HTML mail to be loaded"), + action_mail_load_images_cb, NULL, NULL, NULL }, + + { "mail-mark-ignore-thread-sub", + NULL, + N_("_Ignore Subthread"), + NULL, + N_("Mark new mails in a subthread as read automatically"), + action_mail_mark_ignore_thread_sub_cb, NULL, NULL, NULL }, + + { "mail-mark-ignore-thread-whole", + NULL, + N_("_Ignore Thread"), + NULL, + N_("Mark new mails in this thread as read automatically"), + action_mail_mark_ignore_thread_whole_cb, NULL, NULL, NULL }, + + { "mail-mark-important", + "mail-mark-important", + N_("_Important"), + NULL, + N_("Mark the selected messages as important"), + action_mail_mark_important_cb, NULL, NULL, NULL }, + + { "mail-mark-important-full", + "mail-mark-important", + N_("Mark as _Important"), + NULL, + N_("Mark the selected messages as important"), + action_mail_mark_important_cb, NULL, NULL, NULL }, + + { "mail-mark-junk", + "mail-mark-junk", + N_("_Junk"), + "j", + N_("Mark the selected messages as junk"), + action_mail_mark_junk_cb, NULL, NULL, NULL }, + + { "mail-mark-junk-full", + "mail-mark-junk", + N_("Mark as _Junk"), + NULL, + N_("Mark the selected messages as junk"), + action_mail_mark_junk_cb, NULL, NULL, NULL }, + + { "mail-mark-notjunk", + "mail-mark-notjunk", + N_("_Not Junk"), + "j", + N_("Mark the selected messages as not being junk"), + action_mail_mark_notjunk_cb, NULL, NULL, NULL }, + + { "mail-mark-notjunk-full", + "mail-mark-notjunk", + N_("Mark as _Not Junk"), + NULL, + N_("Mark the selected messages as not being junk"), + action_mail_mark_notjunk_cb, NULL, NULL, NULL }, + + { "mail-mark-read", + "mail-mark-read", + N_("_Read"), + "k", + N_("Mark the selected messages as having been read"), + action_mail_mark_read_cb, NULL, NULL, NULL }, + + { "mail-mark-read-full", + "mail-mark-read", + N_("Mar_k as Read"), + "k", + N_("Mark the selected messages as having been read"), + action_mail_mark_read_cb, NULL, NULL, NULL }, + + { "mail-mark-unignore-thread-sub", + NULL, + N_("Do not _Ignore Subthread"), + NULL, + N_("Do not mark new mails in a subthread as read automatically"), + action_mail_mark_unignore_thread_sub_cb, NULL, NULL, NULL }, + + { "mail-mark-unignore-thread-whole", + NULL, + N_("Do not _Ignore Thread"), + NULL, + N_("Do not mark new mails in this thread as read automatically"), + action_mail_mark_unignore_thread_whole_cb, NULL, NULL, NULL }, + + { "mail-mark-unimportant", + NULL, + N_("Uni_mportant"), + NULL, + N_("Mark the selected messages as unimportant"), + action_mail_mark_unimportant_cb, NULL, NULL, NULL }, + + { "mail-mark-unimportant-full", + NULL, + N_("Mark as Uni_mportant"), + NULL, + N_("Mark the selected messages as unimportant"), + action_mail_mark_unimportant_cb, NULL, NULL, NULL }, + + { "mail-mark-unread", + "mail-mark-unread", + N_("_Unread"), + "k", + N_("Mark the selected messages as not having been read"), + action_mail_mark_unread_cb, NULL, NULL, NULL }, + + { "mail-mark-unread-full", + "mail-mark-unread", + N_("Mark as _Unread"), + NULL, + N_("Mark the selected messages as not having been read"), + action_mail_mark_unread_cb, NULL, NULL, NULL }, + + { "mail-message-edit", + NULL, + N_("_Edit as New Message…"), + NULL, + N_("Open the selected messages in the composer for editing"), + action_mail_message_edit_cb, NULL, NULL, NULL }, + + { "mail-message-new", + "mail-message-new", + N_("Compose _New Message"), + "m", + N_("Open a window for composing a mail message"), + action_mail_message_new_cb, NULL, NULL, NULL }, + + { "mail-message-open", + NULL, + N_("_Open in New Window"), + "o", + N_("Open the selected messages in a new window"), + action_mail_message_open_cb, NULL, NULL, NULL }, + + { "mail-move", + "mail-move", + N_("_Move to Folder…"), + "v", + N_("Move selected messages to another folder"), + action_mail_move_cb, NULL, NULL, NULL }, + + { "mail-next", + "go-next", + N_("_Next Message"), + "Page_Down", + N_("Display the next message"), + action_mail_next_cb, NULL, NULL, NULL }, + + { "mail-next-important", + NULL, + N_("Next _Important Message"), + NULL, + N_("Display the next important message"), + action_mail_next_important_cb, NULL, NULL, NULL }, + + { "mail-next-thread", + NULL, + N_("Next _Thread"), + NULL, + N_("Display the next thread"), + action_mail_next_thread_cb, NULL, NULL, NULL }, + + { "mail-next-unread", + "go-jump", + N_("Next _Unread Message"), + "bracketright", + N_("Display the next unread message"), + action_mail_next_unread_cb, NULL, NULL, NULL }, + + { "mail-previous", + "go-previous", + N_("_Previous Message"), + "Page_Up", + N_("Display the previous message"), + action_mail_previous_cb, NULL, NULL, NULL }, + + { "mail-previous-important", + NULL, + N_("Pr_evious Important Message"), + NULL, + N_("Display the previous important message"), + action_mail_previous_important_cb, NULL, NULL, NULL }, + + { "mail-previous-thread", + NULL, + N_("Previous T_hread"), + NULL, + N_("Display the previous thread"), + action_mail_previous_thread_cb, NULL, NULL, NULL }, + + { "mail-previous-unread", + NULL, + N_("P_revious Unread Message"), + "bracketleft", + N_("Display the previous unread message"), + action_mail_previous_unread_cb, NULL, NULL, NULL }, + + { "mail-print", + "document-print", + N_("_Print…"), + "p", + N_("Print this message"), + action_mail_print_cb, NULL, NULL, NULL }, + + { "mail-print-preview", + "document-print-preview", + N_("Pre_view…"), + NULL, + N_("Preview the message to be printed"), + action_mail_print_preview_cb, NULL, NULL, NULL }, + + { "mail-redirect", + NULL, + N_("Re_direct"), + NULL, + N_("Redirect (bounce) the selected message to someone"), + action_mail_redirect_cb, NULL, NULL, NULL }, + + { "mail-remove-attachments", + "edit-delete", + N_("Remo_ve Attachments"), + NULL, + N_("Remove attachments"), + action_mail_remove_attachments_cb, NULL, NULL, NULL }, + + { "mail-remove-duplicates", + NULL, + N_("Remove Du_plicate Messages"), + NULL, + N_("Checks selected messages for duplicates"), + action_mail_remove_duplicates_cb, NULL, NULL, NULL }, + + { "mail-reply-all", + NULL, + N_("Reply to _All"), + "r", + N_("Compose a reply to all the recipients of the selected message"), + action_mail_reply_all_cb, NULL, NULL, NULL }, + + { "mail-reply-alternative", + NULL, + N_("Al_ternative Reply…"), + "r", + N_("Choose reply options for the selected message"), + action_mail_reply_alternative_cb, NULL, NULL, NULL }, + + { "mail-reply-group", + "mail-reply-all", + N_("_Group Reply"), + NULL, + N_("Reply to the mailing list, or to all recipients"), + action_mail_reply_group_cb, NULL, NULL, NULL }, + + { "mail-reply-list", + NULL, + N_("Reply to _List"), + "l", + N_("Compose a reply to the mailing list of the selected message"), + action_mail_reply_list_cb, NULL, NULL, NULL }, + + { "mail-reply-sender", + "mail-reply-sender", + N_("_Reply to Sender"), + "r", + N_("Compose a reply to the sender of the selected message"), + action_mail_reply_sender_cb, NULL, NULL, NULL }, + + { "mail-save-as", + "document-save-as", + N_("_Save to File…"), + "s", + N_("Save selected messages as an mbox file"), + action_mail_save_as_cb, NULL, NULL, NULL }, + + { "mail-search-web", + NULL, + N_("Search _Web…"), + NULL, + N_("Search the Web with the selected text"), + action_mail_search_web_cb, NULL, NULL, NULL }, + + { "mail-show-source", + NULL, + N_("_Message Source"), + "u", + N_("Show the raw email source of the message"), + action_mail_show_source_cb, NULL, NULL, NULL }, + + { "mail-toggle-important", + NULL, + "Toggle important", /* No menu item; key press only */ + NULL, + NULL, + action_mail_toggle_important_cb, NULL, NULL, NULL }, + + { "mail-undelete", + NULL, + N_("_Undelete Message"), + "d", + N_("Undelete the selected messages"), + action_mail_undelete_cb, NULL, NULL, NULL }, + + { "mail-zoom-100", + "zoom-original", + N_("_Normal Size"), + "0", + N_("Reset the text to its original size"), + action_mail_zoom_100_cb, NULL, NULL, NULL }, + + { "mail-zoom-in", + "zoom-in", + N_("_Zoom In"), + "plus", + N_("Increase the text size"), + action_mail_zoom_in_cb, NULL, NULL, NULL }, + + { "mail-zoom-out", + "zoom-out", + N_("Zoom _Out"), + "minus", + N_("Decrease the text size"), + action_mail_zoom_out_cb, NULL, NULL, NULL }, + + { "mail-caret-mode", + NULL, + N_("_Caret Mode"), + "F7", + N_("Show a blinking cursor in the body of displayed messages"), + NULL, NULL, "false", NULL }, + + { "mail-show-all-headers", + NULL, + N_("All Message _Headers"), + NULL, + N_("Show messages with all email headers"), + NULL, NULL, "false", action_mail_show_all_headers_cb }, + + /*** Menus ***/ + + { "mail-create-menu", NULL, N_("Cre_ate"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "mail-forward-as-menu", NULL, N_("F_orward As"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "mail-label-menu", NULL, N_("_Label"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "mail-reply-group-menu", NULL, N_("_Group Reply"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "mail-goto-menu", NULL, N_("_Go To"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "mail-mark-as-menu", NULL, N_("Mar_k As"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "mail-message-menu", NULL, N_("_Message"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "mail-zoom-menu", NULL, N_("_Zoom"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EMailReader::charset-menu", NULL, N_("Ch_aracter Encoding"), NULL, NULL, NULL, "s", "''", charset_menu_change_state_cb }, + { "EMailReader::mail-reply-group", NULL, N_("_Group Reply"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EMailReader::mail-forward-as-group", NULL, N_("_Forward"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EMailReader::mail-label-actions", NULL, N_("List of Labels"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + + static const EUIActionEntry search_folder_entries[] = { + + { "mail-search-folder-from-mailing-list", + NULL, + N_("Create a Search Folder from Mailing _List…"), + NULL, + N_("Create a search folder for this mailing list"), + action_mail_search_folder_from_mailing_list_cb, NULL, NULL, NULL }, + + { "mail-search-folder-from-recipients", + NULL, + N_("Create a Search Folder from Recipien_ts…"), + NULL, + N_("Create a search folder for these recipients"), + action_mail_search_folder_from_recipients_cb, NULL, NULL, NULL }, + + { "mail-search-folder-from-sender", + NULL, + N_("Create a Search Folder from Sen_der…"), + NULL, + N_("Create a search folder for this sender"), + action_mail_search_folder_from_sender_cb, NULL, NULL, NULL }, + + { "mail-search-folder-from-subject", + NULL, + N_("Create a Search Folder from S_ubject…"), + NULL, + N_("Create a search folder for this subject"), + action_mail_search_folder_from_subject_cb, NULL, NULL, NULL }, + }; + + const struct _name_pair { + const gchar *src_name; + const gchar *dst_name; + } name_pairs[] = { + { "mail-flag-for-followup", "mail-flag-for-followup-full" }, + { "mail-forward-attached", "mail-forward-attached-full" }, + { "mail-forward-inline", "mail-forward-inline-full" }, + { "mail-forward-quoted", "mail-forward-quoted-full" }, + { "mail-mark-important", "mail-mark-important-full" }, + { "mail-mark-junk", "mail-mark-junk-full" }, + { "mail-mark-notjunk", "mail-mark-notjunk-full" }, + { "mail-mark-unimportant", "mail-mark-unimportant-full" }, + { "mail-mark-unread", "mail-mark-unread-full" } + }; + EUIManager *ui_manager; + EMailReaderPrivate *priv; + EMailDisplay *display; + EUIAction *action; + GSettings *settings; + gint ii; + GError *local_error = NULL; + + g_return_if_fail (E_IS_MAIL_READER (self)); + + ui_manager = e_mail_reader_get_ui_manager (self); + if (!ui_manager) + return; + + display = e_mail_reader_get_mail_display (self); + + g_signal_connect_object (ui_manager, "create-item", + G_CALLBACK (e_mail_reader_ui_manager_create_item_cb), self, 0); + + e_ui_manager_add_actions (ui_manager, "mail", NULL, + mail_entries, G_N_ELEMENTS (mail_entries), self); + e_ui_manager_add_actions (ui_manager, "search-folders", NULL, + search_folder_entries, G_N_ELEMENTS (search_folder_entries), self); + + for (ii = 0; ii < G_N_ELEMENTS (name_pairs); ii++) { + e_binding_bind_property ( + e_ui_manager_get_action (ui_manager, name_pairs[ii].src_name), "sensitive", + e_ui_manager_get_action (ui_manager, name_pairs[ii].dst_name), "sensitive", + G_BINDING_SYNC_CREATE); + } + + if (!e_ui_parser_merge_file (e_ui_manager_get_parser (ui_manager), "evolution-mail-reader.eui", &local_error)) + g_warning ("%s: Failed to read %s file: %s", G_STRFUNC, "evolution-mail-reader.eui", local_error ? local_error->message : "Unknown error"); + + g_clear_error (&local_error); + + priv = E_MAIL_READER_GET_PRIVATE (self); + priv->reply_group_menu = G_MENU_MODEL (e_ui_manager_create_item (ui_manager, "mail-reply-group-menu")); + priv->forward_as_menu = G_MENU_MODEL (e_ui_manager_create_item (ui_manager, "mail-forward-as-menu")); + + action = e_mail_reader_get_action (self, "mail-delete"); + e_ui_action_add_secondary_accel (action, "Delete"); + e_ui_action_add_secondary_accel (action, "KP_Delete"); + + action = e_mail_reader_get_action (self, "mail-message-open"); + e_ui_action_add_secondary_accel (action, "Return"); + e_ui_action_add_secondary_accel (action, "KP_Enter"); + e_ui_action_add_secondary_accel (action, "ISO_Enter"); + + action = e_mail_reader_get_action (self, "mail-next-unread"); + e_ui_action_add_secondary_accel (action, "period"); + e_ui_action_add_secondary_accel (action, "bracketright"); + + action = e_mail_reader_get_action (self, "mail-previous-unread"); + e_ui_action_add_secondary_accel (action, "comma"); + e_ui_action_add_secondary_accel (action, "bracketleft"); + + action = e_mail_reader_get_action (self, "mail-reply-all"); + e_ui_action_add_secondary_accel (action, "Reply"); + + action = e_mail_reader_get_action (self, "mail-forward"); + e_ui_action_add_secondary_accel (action, "MailForward"); + + action = e_mail_reader_get_action (self, "mail-toggle-important"); + e_ui_action_add_secondary_accel (action, "exclam"); + + action = e_mail_reader_get_action (self, "mail-zoom-in"); + e_ui_action_add_secondary_accel (action, "ZoomIn"); + + action = e_mail_reader_get_action (self, "mail-zoom-out"); + e_ui_action_add_secondary_accel (action, "ZoomOut"); + + action = e_mail_reader_get_action (self, "mail-next-unread"); + e_ui_action_add_secondary_accel (action, "period"); + + action = e_mail_reader_get_action (self, "mail-previous-unread"); + e_ui_action_add_secondary_accel (action, "comma"); + + action = e_mail_reader_get_action (self, "mail-zoom-in"); + e_ui_action_add_secondary_accel (action, "equal"); + e_ui_action_add_secondary_accel (action, "KP_Add"); + + action = e_mail_reader_get_action (self, "mail-zoom-out"); + e_ui_action_add_secondary_accel (action, "KP_Subtract"); + + /* Bind GObject properties to GSettings keys. */ + + settings = e_util_ref_settings ("org.gnome.evolution.mail"); + + action = e_mail_reader_get_action (self, "mail-caret-mode"); + g_settings_bind ( + settings, "caret-mode", + action, "active", G_SETTINGS_BIND_DEFAULT); + + action = e_mail_reader_get_action (self, "mail-show-all-headers"); + g_settings_bind ( + settings, "show-all-headers", + action, "active", G_SETTINGS_BIND_DEFAULT); + + /* Mode change when viewing message source is ignored. */ + if (e_mail_display_get_mode (display) == E_MAIL_FORMATTER_MODE_SOURCE || + e_mail_display_get_mode (display) == E_MAIL_FORMATTER_MODE_RAW) { + e_ui_action_set_sensitive (action, FALSE); + e_ui_action_set_visible (action, FALSE); + } + + g_object_unref (settings); + +#ifndef G_OS_WIN32 + /* Lockdown integration. */ + + settings = e_util_ref_settings ("org.gnome.desktop.lockdown"); + + action = e_mail_reader_get_action (self, "mail-print"); + g_settings_bind ( + settings, "disable-printing", + action, "visible", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_NO_SENSITIVITY | + G_SETTINGS_BIND_INVERT_BOOLEAN); + + action = e_mail_reader_get_action (self, "mail-print-preview"); + g_settings_bind ( + settings, "disable-printing", + action, "visible", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_NO_SENSITIVITY | + G_SETTINGS_BIND_INVERT_BOOLEAN); + + action = e_mail_reader_get_action (self, "mail-save-as"); + g_settings_bind ( + settings, "disable-save-to-disk", + action, "visible", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_NO_SENSITIVITY | + G_SETTINGS_BIND_INVERT_BOOLEAN); + + g_object_unref (settings); +#endif + + /* Bind properties. */ + + action = e_mail_reader_get_action (self, "mail-caret-mode"); + + e_binding_bind_property ( + action, "active", + display, "caret-mode", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); +} static void mail_reader_double_click_cb (EMailReader *reader, @@ -3438,129 +3729,14 @@ mail_reader_double_click_cb (EMailReader *reader, gint col, GdkEvent *event) { - GtkAction *action; + EUIAction *action; /* Ignore double clicks on columns that handle their own state. */ if (MESSAGE_LIST_COLUMN_IS_ACTIVE (col)) return; action = e_mail_reader_get_action (reader, "mail-message-open"); - gtk_action_activate (action); -} - -static gboolean -mail_reader_key_press_event_cb (EMailReader *reader, - GdkEventKey *event) -{ - GtkAction *action; - const gchar *action_name; - - if (!gtk_widget_has_focus (GTK_WIDGET (reader))) { - EMailDisplay *display; - - display = e_mail_reader_get_mail_display (reader); - if (e_web_view_get_need_input (E_WEB_VIEW (display)) && - gtk_widget_has_focus (GTK_WIDGET (display))) - return FALSE; - } - - if ((event->state & GDK_CONTROL_MASK) != 0) - goto ctrl; - - /* alone */ - switch (event->keyval) { - case GDK_KEY_Delete: - case GDK_KEY_KP_Delete: - action_name = "mail-delete"; - break; - - case GDK_KEY_Return: - case GDK_KEY_KP_Enter: - case GDK_KEY_ISO_Enter: - if (E_IS_MAIL_BROWSER (reader)) - return FALSE; - - action_name = "mail-message-open"; - break; - - case GDK_KEY_period: - case GDK_KEY_bracketright: - action_name = "mail-next-unread"; - break; - - case GDK_KEY_comma: - case GDK_KEY_bracketleft: - action_name = "mail-previous-unread"; - break; - -#ifdef HAVE_XFREE - case XF86XK_Reply: - action_name = "mail-reply-all"; - break; - - case XF86XK_MailForward: - action_name = "mail-forward"; - break; -#endif - - case GDK_KEY_exclam: - action_name = "mail-toggle-important"; - break; - - case GDK_KEY_ZoomIn: - action_name = "mail-zoom-in"; - break; - - case GDK_KEY_ZoomOut: - action_name = "mail-zoom-out"; - break; - - default: - return FALSE; - } - - goto exit; - -ctrl: - - /* Ctrl + */ - switch (event->keyval) { - case GDK_KEY_period: - action_name = "mail-next-unread"; - break; - - case GDK_KEY_comma: - action_name = "mail-previous-unread"; - break; - - case GDK_KEY_equal: - case GDK_KEY_KP_Add: - action_name = "mail-zoom-in"; - break; - - case GDK_KEY_KP_Subtract: - action_name = "mail-zoom-out"; - break; - - default: - return FALSE; - } - -exit: - action = e_mail_reader_get_action (reader, action_name); - gtk_action_activate (action); - - return TRUE; -} - -static gint -mail_reader_key_press_cb (EMailReader *reader, - gint row, - ETreePath path, - gint col, - GdkEvent *event) -{ - return mail_reader_key_press_event_cb (reader, &event->key); + g_action_activate (G_ACTION (action), NULL); } static gboolean @@ -3894,34 +4070,6 @@ mail_reader_reload (EMailReader *reader) e_mail_display_reload (mail_display); } -static void -mail_reader_remove_ui (EMailReader *reader) -{ - EMailReaderPrivate *priv; - GtkWindow *window; - GtkUIManager *ui_manager = NULL; - - g_return_if_fail (E_IS_MAIL_READER (reader)); - - priv = E_MAIL_READER_GET_PRIVATE (reader); - - if (!priv->main_menu_label_merge_id) - return; - - window = e_mail_reader_get_window (reader); - g_return_if_fail (window != NULL); - - if (E_IS_SHELL_WINDOW (window)) - ui_manager = e_shell_window_get_ui_manager (E_SHELL_WINDOW (window)); - else if (E_IS_MAIL_BROWSER (window)) - ui_manager = e_mail_browser_get_ui_manager (E_MAIL_BROWSER (window)); - - g_return_if_fail (ui_manager != NULL); - g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); - - gtk_ui_manager_remove_ui (ui_manager, priv->main_menu_label_merge_id); -} - static void mail_reader_message_loaded_cb (CamelFolder *folder, GAsyncResult *result, @@ -4501,9 +4649,11 @@ mail_reader_show_search_bar (EMailReader *reader) } static void -action_mail_label_cb (GtkToggleAction *action, - EMailReader *reader) +action_mail_label_cb (EUIAction *action, + GParamSpec *param, + gpointer user_data) { + EMailReader *reader = user_data; CamelFolder *folder; GPtrArray *uids; const gchar *tag; @@ -4520,7 +4670,7 @@ action_mail_label_cb (GtkToggleAction *action, camel_folder_freeze (folder); for (ii = 0; ii < uids->len; ii++) { - if (gtk_toggle_action_get_active (action)) + if (e_ui_action_get_active (action)) camel_folder_set_message_user_flag ( folder, uids->pdata[ii], tag, TRUE); else { @@ -4622,7 +4772,7 @@ mail_reader_gather_labels_info (EMailReader *reader, } static void -mail_reader_update_label_action (GtkToggleAction *action, +mail_reader_update_label_action (EUIAction *action, GHashTable *labels_info, /* gchar * ~> guint */ const gchar *label_tag) { @@ -4642,8 +4792,8 @@ mail_reader_update_label_action (GtkToggleAction *action, not_exists = (value & LABEL_NOTEXIST) != 0; sensitive = !(exists && not_exists); - gtk_toggle_action_set_active (action, exists); - gtk_action_set_sensitive (GTK_ACTION (action), sensitive); + e_ui_action_set_active (action, exists); + e_ui_action_set_sensitive (action, sensitive); } static void @@ -4653,50 +4803,33 @@ mail_reader_update_labels_menu (EMailReader *reader) EMailLabelListStore *label_store; EMailBackend *backend; EMailSession *session; - GtkWindow *window; - GtkUIManager *ui_manager = NULL; - GtkActionGroup *action_group; + EUIManager *ui_manager = NULL; + EUIActionGroup *action_group; GtkTreeIter iter; GHashTable *labels_info; /* gchar * ~> guint { LABEL_EXISTS | LABEL_NOTEXIST | LABEL_UNKNOWN } */ GPtrArray *uids; - const gchar *main_menu_path, *popup_menu_path; gboolean valid; gint ii = 0; priv = E_MAIL_READER_GET_PRIVATE (reader); - window = e_mail_reader_get_window (reader); - g_return_if_fail (window != NULL); + if (!priv->labels_menu) + return; - if (E_IS_SHELL_WINDOW (window)) - ui_manager = e_shell_window_get_ui_manager (E_SHELL_WINDOW (window)); - else if (E_IS_MAIL_BROWSER (window)) - ui_manager = e_mail_browser_get_ui_manager (E_MAIL_BROWSER (window)); - - g_return_if_fail (ui_manager != NULL); - g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); + ui_manager = e_mail_reader_get_ui_manager (reader); + if (!ui_manager) + return; backend = e_mail_reader_get_backend (reader); session = e_mail_backend_get_session (backend); label_store = e_mail_ui_session_get_label_store (E_MAIL_UI_SESSION (session)); - action_group = e_mail_reader_get_action_group (reader, E_MAIL_READER_ACTION_GROUP_LABELS); - main_menu_path = "/main-menu/custom-menus/mail-message-menu/mail-mark-as-menu/mail-label-menu/mail-label-actions"; - popup_menu_path = "/mail-message-popup/mail-label-menu/mail-label-actions"; + action_group = e_ui_manager_get_action_group (ui_manager, "mail-labels"); - /* Unmerge the previous menu items. */ - if (priv->main_menu_label_merge_id) - gtk_ui_manager_remove_ui (ui_manager, priv->main_menu_label_merge_id); - else - priv->main_menu_label_merge_id = gtk_ui_manager_new_merge_id (ui_manager); + e_ui_manager_freeze (ui_manager); - if (priv->popup_menu_label_merge_id) - gtk_ui_manager_remove_ui (ui_manager, priv->popup_menu_label_merge_id); - else - priv->popup_menu_label_merge_id = gtk_ui_manager_new_merge_id (ui_manager); - - e_action_group_remove_all_actions (action_group); - gtk_ui_manager_ensure_update (ui_manager); + g_menu_remove_all (priv->labels_menu); + e_ui_action_group_remove_all (action_group); uids = e_mail_reader_get_selected_uids (reader); labels_info = mail_reader_gather_labels_info (reader, label_store, uids); @@ -4704,66 +4837,61 @@ mail_reader_update_labels_menu (EMailReader *reader) valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (label_store), &iter); while (valid) { - EMailLabelAction *label_action; - GtkAction *action; - gchar *action_name; - gchar *stock_id; + EUIAction *action; + GMenuItem *menu_item; + gchar action_name[128]; + gchar *icon_name; gchar *label; gchar *tag; label = e_mail_label_list_store_get_name (label_store, &iter); - stock_id = e_mail_label_list_store_get_stock_id (label_store, &iter); + icon_name = e_mail_label_list_store_dup_icon_name (label_store, &iter); tag = e_mail_label_list_store_get_tag (label_store, &iter); - action_name = g_strdup_printf ("mail-label-%d", ii); - /* XXX Add a tooltip! */ - label_action = e_mail_label_action_new (action_name, label, NULL, stock_id); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "mail-label-%d", ii) < sizeof (action_name)); - g_object_set_data_full ( - G_OBJECT (label_action), "tag", - tag, (GDestroyNotify) g_free); + action = e_ui_action_new_stateful ("mail-labels", action_name, NULL, g_variant_new_boolean (FALSE)); + e_ui_action_set_label (action, label); + if (icon_name && *icon_name) + e_ui_action_set_icon_name (action, icon_name); + + g_object_set_data_full (G_OBJECT (action), "tag", tag, g_free); /* Configure the action before we connect to signals. */ - mail_reader_update_label_action (GTK_TOGGLE_ACTION (label_action), labels_info, tag); + mail_reader_update_label_action (action, labels_info, tag); g_signal_connect ( - label_action, "toggled", + action, "notify::active", G_CALLBACK (action_mail_label_cb), reader); - /* The action group takes ownership of the action. */ - action = GTK_ACTION (label_action); - if (ii + 1 < 10) { gchar accel[5]; accel[0] = '1' + ii; accel[1] = '\0'; - gtk_action_group_add_action_with_accel (action_group, action, accel); - } else { - gtk_action_group_add_action (action_group, action); + e_ui_action_set_accel (action, accel); } - g_object_unref (label_action); - gtk_ui_manager_add_ui ( - ui_manager, priv->main_menu_label_merge_id, main_menu_path, - action_name, action_name, GTK_UI_MANAGER_AUTO, FALSE); + e_ui_action_group_add (action_group, action); - gtk_ui_manager_add_ui ( - ui_manager, priv->popup_menu_label_merge_id, popup_menu_path, - action_name, action_name, GTK_UI_MANAGER_AUTO, FALSE); + menu_item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (ui_manager, menu_item, action); + g_menu_append_item (priv->labels_menu, menu_item); + g_clear_object (&menu_item); + g_object_unref (action); g_free (label); - g_free (stock_id); - g_free (action_name); + g_free (icon_name); - valid = gtk_tree_model_iter_next ( - GTK_TREE_MODEL (label_store), &iter); + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (label_store), &iter); ii++; } g_hash_table_destroy (labels_info); g_ptr_array_unref (uids); + + e_ui_manager_thaw (ui_manager); } static void @@ -4867,9 +4995,11 @@ mail_label_change_more_set_none_clicked_cb (GtkWidget *button, } static void -action_mail_label_change_more_cb (GtkAction *action, - EMailReader *reader) +action_mail_label_change_more_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; GtkBox *box; GtkGrid *grid; GtkWidget *widget, *popover; @@ -4897,18 +5027,18 @@ action_mail_label_change_more_cb (GtkAction *action, while (valid) { GtkWidget *checkbox; gchar *label; - gchar *stock_id; + gchar *icon_name; gchar *tag; guint value; gboolean exists, not_exists; label = e_mail_label_list_store_get_name (label_store, &iter); - stock_id = e_mail_label_list_store_get_stock_id (label_store, &iter); + icon_name = e_mail_label_list_store_dup_icon_name (label_store, &iter); tag = e_mail_label_list_store_get_tag (label_store, &iter); checkbox = gtk_check_button_new_with_mnemonic (label); - if (stock_id && *stock_id) { - gtk_button_set_image (GTK_BUTTON (checkbox), gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU)); + if (icon_name && *icon_name) { + gtk_button_set_image (GTK_BUTTON (checkbox), gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU)); gtk_button_set_always_show_image (GTK_BUTTON (checkbox), TRUE); } g_object_set_data_full (G_OBJECT (checkbox), "tag", tag, g_free); @@ -4929,7 +5059,7 @@ action_mail_label_change_more_cb (GtkAction *action, g_ptr_array_add (checkboxes, checkbox); g_free (label); - g_free (stock_id); + g_free (icon_name); valid = gtk_tree_model_iter_next (model, &iter); } @@ -5048,8 +5178,7 @@ static void mail_reader_update_actions (EMailReader *reader, guint32 state) { - GtkAction *action; - const gchar *action_name; + EUIAction *action; gboolean sensitive; EMailDisplay *mail_display; @@ -5146,356 +5275,277 @@ mail_reader_update_actions (EMailReader *reader, last_message_selected = row < 0 || row + 1 >= count; } - action_name = "mail-add-sender"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-add-sender"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-archive"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-archive"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-check-for-junk"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-check-for-junk"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-color-assign"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-color-assign"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-color-unset"; sensitive = any_messages_selected && selection_has_color; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-color-unset"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-copy"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-copy"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-create-menu"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-create-menu"); + e_ui_action_set_sensitive (action, sensitive); /* If a single message is selected, let the user hit delete to * advance the cursor even if the message is already deleted. */ - action_name = "mail-delete"; sensitive = (single_message_selected || selection_has_undeleted_messages) && (state & E_MAIL_READER_FOLDER_IS_VTRASH) == 0; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-delete"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-add-note"; sensitive = single_message_selected && !selection_has_mail_note; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_visible (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-add-note"); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, sensitive); - action_name = "mail-edit-note"; sensitive = single_message_selected && selection_has_mail_note; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_visible (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-edit-note"); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, sensitive); - action_name = "mail-delete-note"; sensitive = single_message_selected && selection_has_mail_note; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_visible (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-delete-note"); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, sensitive); - action_name = "mail-filters-apply"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-filters-apply"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-filter-rule-for-mailing-list"; sensitive = single_message_selected && selection_is_mailing_list; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-filter-rule-for-mailing-list"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-find"; - sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + sensitive = single_message_selected && mail_display && gtk_widget_is_visible (GTK_WIDGET (mail_display)); + action = e_mail_reader_get_action (reader, "mail-find"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-flag-clear"; sensitive = enable_flag_clear; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-flag-clear"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-flag-completed"; sensitive = enable_flag_completed; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-flag-completed"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-flag-for-followup"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-flag-for-followup"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-forward"; sensitive = have_enabled_account && any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-forward"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-forward-attached"; sensitive = have_enabled_account && any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-forward-attached"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-forward-attached-full"; sensitive = have_enabled_account && any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-forward-as-menu"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-forward-as-menu"; - sensitive = have_enabled_account && any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - - action_name = "mail-forward-inline"; sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-forward-inline"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-forward-inline-full"; sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-forward-quoted"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-forward-quoted"; - sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - - action_name = "mail-forward-quoted-full"; - sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - - action_name = "mail-goto-menu"; sensitive = TRUE; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-goto-menu"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-load-images"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-load-images"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-mark-as-menu"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-as-menu"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-mark-ignore-thread-sub"; sensitive = selection_has_notignore_thread_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_visible (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-ignore-thread-sub"); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, sensitive); - action_name = "mail-mark-ignore-thread-whole"; sensitive = selection_has_notignore_thread_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_visible (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-ignore-thread-whole"); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, sensitive); - action_name = "mail-mark-important"; sensitive = selection_has_unimportant_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-important"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-mark-junk"; sensitive = selection_has_not_junk_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-junk"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-mark-notjunk"; sensitive = selection_has_junk_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-notjunk"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-mark-read"; sensitive = selection_has_unread_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-read"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-mark-unignore-thread-sub"; sensitive = selection_has_ignore_thread_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_visible (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-unignore-thread-sub"); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, sensitive); - action_name = "mail-mark-unignore-thread-whole"; sensitive = selection_has_ignore_thread_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); - gtk_action_set_visible (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-unignore-thread-whole"); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_visible (action, sensitive); - action_name = "mail-mark-unimportant"; sensitive = selection_has_important_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-unimportant"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-mark-unread"; sensitive = selection_has_read_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-mark-unread"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-message-edit"; sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-message-edit"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-message-new"; sensitive = have_enabled_account; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-message-new"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-message-open"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-message-open"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-move"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-move"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-next"; sensitive = any_messages_selected && !last_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-next"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-next-important"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-next-important"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-next-thread"; sensitive = single_message_selected && !last_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-next-thread"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-next-unread"; sensitive = TRUE; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-next-unread"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-previous"; sensitive = any_messages_selected && !first_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-previous"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-previous-important"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-previous-important"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-previous-unread"; sensitive = TRUE; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-previous-unread"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-previous-thread"; sensitive = any_messages_selected && !first_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-previous-thread"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-print"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-print"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-print-preview"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-print-preview"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-redirect"; sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-redirect"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-remove-attachments"; sensitive = any_messages_selected && selection_has_attachment_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-remove-attachments"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-remove-duplicates"; sensitive = multiple_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-remove-duplicates"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-reply-all"; sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-reply-all"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-reply-alternative"; sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-reply-alternative"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-reply-group"; sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-reply-group"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-reply-group-menu"; sensitive = have_enabled_account && any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-reply-group-menu"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-reply-list"; sensitive = have_enabled_account && single_message_selected && selection_is_mailing_list; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-reply-list"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-reply-sender"; sensitive = have_enabled_account && single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-reply-sender"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-save-as"; sensitive = any_messages_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-save-as"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-show-source"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-show-source"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-undelete"; sensitive = selection_has_deleted_messages; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-undelete"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-zoom-100"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-zoom-100"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-zoom-in"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-zoom-in"); + e_ui_action_set_sensitive (action, sensitive); - action_name = "mail-zoom-out"; sensitive = single_message_selected; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_sensitive (action, sensitive); + action = e_mail_reader_get_action (reader, "mail-zoom-out"); + e_ui_action_set_sensitive (action, sensitive); action = e_mail_reader_get_action (reader, "mail-search-web"); - gtk_action_set_sensitive (action, single_message_selected && + e_ui_action_set_sensitive (action, single_message_selected && mail_display && e_web_view_has_selection (E_WEB_VIEW (mail_display))); mail_reader_update_labels_menu (reader); @@ -5507,38 +5557,12 @@ mail_reader_close_on_delete_or_junk (EMailReader *reader) return FALSE; } -static void -mail_reader_init_charset_actions (EMailReader *reader, - GtkActionGroup *action_group) -{ - GtkRadioAction *default_action; - GSList *radio_group; - - radio_group = e_charset_add_radio_actions ( - action_group, "mail-charset-", NULL, - G_CALLBACK (action_mail_charset_cb), reader); - - /* XXX Add a tooltip! */ - default_action = gtk_radio_action_new ( - "mail-charset-default", _("Default"), NULL, NULL, -1); - - gtk_radio_action_set_group (default_action, radio_group); - - g_signal_connect ( - default_action, "changed", - G_CALLBACK (action_mail_charset_cb), reader); - - gtk_action_group_add_action ( - action_group, GTK_ACTION (default_action)); - - gtk_radio_action_set_current_value (default_action, -1); -} - static void e_mail_reader_default_init (EMailReaderInterface *iface) { quark_private = g_quark_from_static_string ("e-mail-reader-private"); + iface->init_ui_data = e_mail_reader_init_ui_data_default; iface->get_alert_sink = mail_reader_get_alert_sink; iface->get_selected_uids = mail_reader_get_selected_uids; iface->get_selected_uids_with_collapsed_threads = mail_reader_get_selected_uids_with_collapsed_threads; @@ -5553,7 +5577,6 @@ e_mail_reader_default_init (EMailReaderInterface *iface) iface->update_actions = mail_reader_update_actions; iface->close_on_delete_or_junk = mail_reader_close_on_delete_or_junk; iface->reload = mail_reader_reload; - iface->remove_ui = mail_reader_remove_ui; g_object_interface_install_property ( iface, @@ -5672,17 +5695,11 @@ e_mail_reader_default_init (EMailReaderInterface *iface) } void -e_mail_reader_init (EMailReader *reader, - gboolean init_actions, - gboolean connect_signals) +e_mail_reader_init (EMailReader *reader) { - GtkActionGroup *action_group; + EMailReaderPrivate *priv; GtkWidget *message_list; - GtkAction *action; - const gchar *action_name; EMailDisplay *display; - EMenuToolAction *menu_tool_action, *menu_tool_action_first; - GSettings *settings; g_return_if_fail (E_IS_MAIL_READER (reader)); @@ -5690,276 +5707,35 @@ e_mail_reader_init (EMailReader *reader, display = e_mail_reader_get_mail_display (reader); /* Initialize a private struct. */ - g_object_set_qdata_full ( - G_OBJECT (reader), quark_private, - g_slice_new0 (EMailReaderPrivate), - (GDestroyNotify) mail_reader_private_free); + priv = g_new0 (EMailReaderPrivate, 1); + g_object_set_qdata_full (G_OBJECT (reader), quark_private, priv, (GDestroyNotify) mail_reader_private_free); e_binding_bind_property ( reader, "group-by-threads", message_list, "group-by-threads", G_BINDING_SYNC_CREATE); - if (!init_actions) - goto connect_signals; - - /* Add the "standard" EMailReader actions. */ - - action_group = e_mail_reader_get_action_group ( - reader, E_MAIL_READER_ACTION_GROUP_STANDARD); - - gtk_action_group_add_actions ( - action_group, mail_reader_entries, - G_N_ELEMENTS (mail_reader_entries), reader); - e_action_group_add_popup_actions ( - action_group, mail_reader_popup_entries, - G_N_ELEMENTS (mail_reader_popup_entries)); - gtk_action_group_add_toggle_actions ( - action_group, mail_reader_toggle_entries, - G_N_ELEMENTS (mail_reader_toggle_entries), reader); - - mail_reader_init_charset_actions (reader, action_group); - - - /* The "mail-forward" action is special: it uses a GtkMenuToolButton - * for its toolbar item type. So we have to create it separately. */ - - menu_tool_action = e_menu_tool_action_new ( - "toolbar-mail-forward", _("_Forward"), - _("Forward the selected message to someone")); - - gtk_action_set_icon_name (GTK_ACTION (menu_tool_action), "mail-forward"); - gtk_action_set_visible (GTK_ACTION (menu_tool_action), !e_util_get_use_header_bar ()); - - e_binding_bind_property ( - e_mail_reader_get_action (reader, "mail-forward"), "sensitive", - menu_tool_action, "sensitive", - G_BINDING_SYNC_CREATE); - - g_signal_connect ( - menu_tool_action, "activate", - G_CALLBACK (action_mail_forward_cb), reader); - - gtk_action_group_add_action_with_accel ( - action_group, GTK_ACTION (menu_tool_action), "f"); - - menu_tool_action_first = menu_tool_action; - - menu_tool_action = e_menu_tool_action_new ( - "toolbar-mail-preview-forward", _("_Forward"), - _("Forward the selected message to someone")); - - gtk_action_set_icon_name (GTK_ACTION (menu_tool_action), "mail-forward"); - gtk_action_set_is_important (GTK_ACTION (menu_tool_action), TRUE); - - g_signal_connect ( - menu_tool_action, "activate", - G_CALLBACK (action_mail_forward_cb), reader); - - gtk_action_group_add_action (action_group, GTK_ACTION (menu_tool_action)); - - e_binding_bind_property ( - menu_tool_action_first, "sensitive", - menu_tool_action, "sensitive", - G_BINDING_SYNC_CREATE); - - /* Likewise the "mail-reply-group" action. */ - - menu_tool_action = e_menu_tool_action_new ( - /* Translators: "Group Reply" will reply either to a mailing list - * (if possible and if that configuration option is enabled), or else - * it will reply to all. The word "Group" was chosen because it covers - * either of those, without too strongly implying one or the other. */ - "toolbar-mail-reply-group", _("Group Reply"), - _("Reply to the mailing list, or to all recipients")); - - gtk_action_set_icon_name (GTK_ACTION (menu_tool_action), "mail-reply-all"); - gtk_action_set_visible (GTK_ACTION (menu_tool_action), !e_util_get_use_header_bar ()); - - e_binding_bind_property ( - e_mail_reader_get_action (reader, "mail-reply-group"), "sensitive", - menu_tool_action, "sensitive", - G_BINDING_SYNC_CREATE); - - g_signal_connect ( - menu_tool_action, "activate", - G_CALLBACK (action_mail_reply_group_cb), reader); - - gtk_action_group_add_action_with_accel ( - action_group, GTK_ACTION (menu_tool_action), "g"); - - menu_tool_action_first = menu_tool_action; - - menu_tool_action = e_menu_tool_action_new ( - /* Translators: "Group Reply" will reply either to a mailing list - * (if possible and if that configuration option is enabled), or else - * it will reply to all. The word "Group" was chosen because it covers - * either of those, without too strongly implying one or the other. */ - "toolbar-mail-preview-reply-group", _("Group Reply"), - _("Reply to the mailing list, or to all recipients")); - - gtk_action_set_icon_name (GTK_ACTION (menu_tool_action), "mail-reply-all"); - gtk_action_set_is_important (GTK_ACTION (menu_tool_action), TRUE); - - g_signal_connect ( - menu_tool_action, "activate", - G_CALLBACK (action_mail_reply_group_cb), reader); - - gtk_action_group_add_action (action_group, GTK_ACTION (menu_tool_action)); - - e_binding_bind_property ( - menu_tool_action_first, "sensitive", - menu_tool_action, "sensitive", - G_BINDING_SYNC_CREATE); - - /* Add EMailReader actions for Search Folders. The action group - * should be made invisible if Search Folders are disabled. */ - - action_group = e_mail_reader_get_action_group ( - reader, E_MAIL_READER_ACTION_GROUP_SEARCH_FOLDERS); - - gtk_action_group_add_actions ( - action_group, mail_reader_search_folder_entries, - G_N_ELEMENTS (mail_reader_search_folder_entries), reader); - - display = e_mail_reader_get_mail_display (reader); - - /* Bind GObject properties to GSettings keys. */ - - settings = e_util_ref_settings ("org.gnome.evolution.mail"); - - action_name = "mail-caret-mode"; - action = e_mail_reader_get_action (reader, action_name); - g_settings_bind ( - settings, "caret-mode", - action, "active", G_SETTINGS_BIND_DEFAULT); - - action_name = "mail-show-all-headers"; - action = e_mail_reader_get_action (reader, action_name); - g_settings_bind ( - settings, "show-all-headers", - action, "active", G_SETTINGS_BIND_DEFAULT); - - /* Mode change when viewing message source is ignored. */ - if (e_mail_display_get_mode (display) == E_MAIL_FORMATTER_MODE_SOURCE || - e_mail_display_get_mode (display) == E_MAIL_FORMATTER_MODE_RAW) { - gtk_action_set_sensitive (action, FALSE); - gtk_action_set_visible (action, FALSE); - } - - g_object_unref (settings); + priv->labels_menu = g_menu_new (); /* Fine tuning. */ - action_name = "mail-delete"; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_short_label (action, _("Delete")); - - action_name = "toolbar-mail-forward"; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_is_important (action, TRUE); - - action_name = "toolbar-mail-reply-group"; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_is_important (action, TRUE); - - action_name = "mail-next"; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_short_label (action, _("Next")); - - action_name = "mail-previous"; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_short_label (action, _("Previous")); - - action_name = "mail-reply-all"; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_is_important (action, TRUE); - - action_name = "mail-reply-sender"; - action = e_mail_reader_get_action (reader, action_name); - gtk_action_set_is_important (action, TRUE); - gtk_action_set_short_label (action, _("Reply")); - - action_name = "add-to-address-book"; - action = e_mail_display_get_action (display, action_name); g_signal_connect ( - action, "activate", + e_mail_display_get_action (display, "add-to-address-book"), "activate", G_CALLBACK (action_add_to_address_book_cb), reader); - action_name = "send-reply"; - action = e_mail_display_get_action (display, action_name); g_signal_connect ( - action, "activate", + e_mail_display_get_action (display, "send-reply"), "activate", G_CALLBACK (action_mail_reply_recipient_cb), reader); - action_name = "search-folder-recipient"; - action = e_mail_display_get_action (display, action_name); g_signal_connect ( - action, "activate", + e_mail_display_get_action (display, "search-folder-recipient"), "activate", G_CALLBACK (action_search_folder_recipient_cb), reader); - action_name = "search-folder-sender"; - action = e_mail_display_get_action (display, action_name); g_signal_connect ( - action, "activate", + e_mail_display_get_action (display, "search-folder-sender"), "activate", G_CALLBACK (action_search_folder_sender_cb), reader); -#ifndef G_OS_WIN32 - /* Lockdown integration. */ - - settings = e_util_ref_settings ("org.gnome.desktop.lockdown"); - - action_name = "mail-print"; - action = e_mail_reader_get_action (reader, action_name); - g_settings_bind ( - settings, "disable-printing", - action, "visible", - G_SETTINGS_BIND_GET | - G_SETTINGS_BIND_NO_SENSITIVITY | - G_SETTINGS_BIND_INVERT_BOOLEAN); - - action_name = "mail-print-preview"; - action = e_mail_reader_get_action (reader, action_name); - g_settings_bind ( - settings, "disable-printing", - action, "visible", - G_SETTINGS_BIND_GET | - G_SETTINGS_BIND_NO_SENSITIVITY | - G_SETTINGS_BIND_INVERT_BOOLEAN); - - action_name = "mail-save-as"; - action = e_mail_reader_get_action (reader, action_name); - g_settings_bind ( - settings, "disable-save-to-disk", - action, "visible", - G_SETTINGS_BIND_GET | - G_SETTINGS_BIND_NO_SENSITIVITY | - G_SETTINGS_BIND_INVERT_BOOLEAN); - - g_object_unref (settings); -#endif - - /* Bind properties. */ - - action_name = "mail-caret-mode"; - action = e_mail_reader_get_action (reader, action_name); - - e_binding_bind_property ( - action, "active", - display, "caret-mode", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - -connect_signals: - - if (!connect_signals) - return; - /* Connect signals. */ - g_signal_connect_swapped ( - display, "key-press-event", - G_CALLBACK (mail_reader_key_press_event_cb), reader); - g_signal_connect_swapped ( display, "load-changed", G_CALLBACK (mail_reader_load_changed_cb), reader); @@ -6010,10 +5786,6 @@ connect_signals: message_list, "double-click", G_CALLBACK (mail_reader_double_click_cb), reader); - g_signal_connect_swapped ( - message_list, "key-press", - G_CALLBACK (mail_reader_key_press_cb), reader); - g_signal_connect_swapped ( message_list, "selection-change", G_CALLBACK (e_mail_reader_changed), reader); @@ -6340,50 +6112,65 @@ void e_mail_reader_update_actions (EMailReader *reader, guint32 state) { + EUIManager *ui_manager; + g_return_if_fail (E_IS_MAIL_READER (reader)); + ui_manager = e_mail_reader_get_ui_manager (reader); + + if (ui_manager) + e_ui_manager_freeze (ui_manager); + g_signal_emit (reader, signals[UPDATE_ACTIONS], 0, state); + + if (ui_manager) + e_ui_manager_thaw (ui_manager); } -GtkAction * -e_mail_reader_get_action (EMailReader *reader, - const gchar *action_name) +void +e_mail_reader_init_ui_data (EMailReader *reader) { - GtkAction *action = NULL; - gint ii; + EMailReaderInterface *iface; - g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL); - g_return_val_if_fail (action_name != NULL, NULL); + g_return_if_fail (E_IS_MAIL_READER (reader)); - for (ii = 0; ii < E_MAIL_READER_NUM_ACTION_GROUPS; ii++) { - GtkActionGroup *group; - - group = e_mail_reader_get_action_group (reader, ii); - action = gtk_action_group_get_action (group, action_name); - - if (action != NULL) - break; - } - - if (action == NULL) - g_critical ( - "%s: action '%s' not found", G_STRFUNC, action_name); - - return action; + iface = E_MAIL_READER_GET_INTERFACE (reader); + if (iface->init_ui_data != NULL) + iface->init_ui_data (reader); } -GtkActionGroup * -e_mail_reader_get_action_group (EMailReader *reader, - EMailReaderActionGroup group) +EUIManager * +e_mail_reader_get_ui_manager (EMailReader *reader) { EMailReaderInterface *iface; g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL); iface = E_MAIL_READER_GET_INTERFACE (reader); - g_return_val_if_fail (iface->get_action_group != NULL, NULL); + g_return_val_if_fail (iface->get_ui_manager != NULL, NULL); - return iface->get_action_group (reader, group); + return iface->get_ui_manager (reader); +} + +EUIAction * +e_mail_reader_get_action (EMailReader *reader, + const gchar *action_name) +{ + EUIAction *action; + EUIManager *ui_manager; + + g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL); + g_return_val_if_fail (action_name != NULL, NULL); + + ui_manager = e_mail_reader_get_ui_manager (reader); + if (!ui_manager) + return NULL; + + action = e_ui_manager_get_action (ui_manager, action_name); + if (action == NULL) + g_critical ("%s: action '%s' not found", G_STRFUNC, action_name); + + return action; } EAlertSink * @@ -6451,36 +6238,28 @@ e_mail_reader_get_message_list (EMailReader *reader) return iface->get_message_list (reader); } -static void -e_mail_reader_popup_menu_deactivate_cb (GtkMenu *popup_menu, - EMailReader *reader) -{ - g_return_if_fail (GTK_IS_MENU (popup_menu)); - - g_signal_handlers_disconnect_by_func (popup_menu, e_mail_reader_popup_menu_deactivate_cb, reader); - gtk_menu_detach (popup_menu); -} - GtkMenu * e_mail_reader_get_popup_menu (EMailReader *reader) { - EMailReaderInterface *iface; + EUIManager *ui_manager; + GObject *ui_object; GtkMenu *menu; g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL); - iface = E_MAIL_READER_GET_INTERFACE (reader); - g_return_val_if_fail (iface->get_popup_menu != NULL, NULL); + ui_manager = e_mail_reader_get_ui_manager (reader); + if (!ui_manager) + return NULL; - menu = iface->get_popup_menu (reader); - if (!gtk_menu_get_attach_widget (GTK_MENU (menu))) { - gtk_menu_attach_to_widget (GTK_MENU (menu), - GTK_WIDGET (reader), - NULL); - g_signal_connect ( - menu, "deactivate", - G_CALLBACK (e_mail_reader_popup_menu_deactivate_cb), reader); - } + ui_object = e_ui_manager_create_item (ui_manager, "mail-preview-popup"); + g_return_val_if_fail (G_IS_MENU_MODEL (ui_object), NULL); + + menu = GTK_MENU (gtk_menu_new_from_model (G_MENU_MODEL (ui_object))); + + g_clear_object (&ui_object); + + gtk_menu_attach_to_widget (menu, GTK_WIDGET (reader), NULL); + e_util_connect_menu_detach_after_deactivate (menu); return menu; } @@ -6754,45 +6533,6 @@ e_mail_reader_set_delete_selects_previous (EMailReader *reader, g_object_notify (G_OBJECT (reader), "delete-selects-previous"); } -void -e_mail_reader_create_charset_menu (EMailReader *reader, - GtkUIManager *ui_manager, - guint merge_id) -{ - GtkAction *action; - const gchar *action_name; - const gchar *path; - GSList *list; - - g_return_if_fail (E_IS_MAIL_READER (reader)); - g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); - - action_name = "mail-charset-default"; - action = e_mail_reader_get_action (reader, action_name); - g_return_if_fail (action != NULL); - - list = gtk_radio_action_get_group (GTK_RADIO_ACTION (action)); - list = g_slist_copy (list); - list = g_slist_remove (list, action); - list = g_slist_sort (list, (GCompareFunc) e_action_compare_by_label); - - path = "/main-menu/view-menu/mail-message-view-actions/mail-encoding-menu"; - - while (list != NULL) { - action = list->data; - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, path, - gtk_action_get_name (action), - gtk_action_get_name (action), - GTK_UI_MANAGER_AUTO, FALSE); - - list = g_slist_delete_link (list, list); - } - - gtk_ui_manager_ensure_update (ui_manager); -} - void e_mail_reader_show_search_bar (EMailReader *reader) { @@ -6871,133 +6611,27 @@ e_mail_reader_reload (EMailReader *reader) iface->reload (reader); } -void -e_mail_reader_remove_ui (EMailReader *reader) +gboolean +e_mail_reader_ignore_accel (EMailReader *reader) { - EMailReaderInterface *iface; + EMailDisplay *mail_display; + GtkWidget *toplevel; - g_return_if_fail (E_IS_MAIL_READER (reader)); + g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE); - iface = E_MAIL_READER_GET_INTERFACE (reader); - g_return_if_fail (iface->remove_ui != NULL); + mail_display = e_mail_reader_get_mail_display (E_MAIL_READER (reader)); - iface->remove_ui (reader); -} - -/** - * e_mail_reader_create_reply_menu: - * @reader: An #EMailReader - * - * Get reply menu - * - * Returns: (transfer full): A new #GtkMenu - * - * Since: 3.46 - **/ -GtkWidget * -e_mail_reader_create_reply_menu (EMailReader *reader) -{ - GtkWindow *window; - GtkWidget *menu; - GtkAction *action; - GtkAccelGroup *accel_group; - GtkUIManager *ui_manager; - - menu = gtk_menu_new (); - - window = e_mail_reader_get_window (reader); - g_return_val_if_fail (window != NULL, menu); - - if (E_IS_SHELL_WINDOW (window)) - ui_manager = e_shell_window_get_ui_manager (E_SHELL_WINDOW (window)); - else if (E_IS_MAIL_BROWSER (window)) - ui_manager = e_mail_browser_get_ui_manager (E_MAIL_BROWSER (window)); - else - return menu; - - accel_group = gtk_ui_manager_get_accel_group (ui_manager); - - action = e_mail_reader_get_action (reader, "mail-reply-all"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); - - action = e_mail_reader_get_action (reader, "mail-reply-list"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); - - action = e_mail_reader_get_action (reader, "mail-reply-alternative"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); - - gtk_widget_show_all (menu); - - return menu; -} - -/** - * e_mail_reader_create_forward_menu: - * @reader: An #EMailReader - * - * Get forward menu - * - * Returns: (transfer full): A new #GtkMenu - * - * Since: 3.46 - **/ -GtkWidget * -e_mail_reader_create_forward_menu (EMailReader *reader) -{ - GtkWindow *window; - GtkWidget *menu; - GtkAction *action; - GtkAccelGroup *accel_group; - GtkUIManager *ui_manager; - - menu = gtk_menu_new (); - - window = e_mail_reader_get_window (reader); - g_return_val_if_fail (window != NULL, menu); - - if (E_IS_SHELL_WINDOW (window)) - ui_manager = e_shell_window_get_ui_manager (E_SHELL_WINDOW (window)); - else if (E_IS_MAIL_BROWSER (window)) - ui_manager = e_mail_browser_get_ui_manager (E_MAIL_BROWSER (window)); - else - return menu; - - accel_group = gtk_ui_manager_get_accel_group (ui_manager); - - action = e_mail_reader_get_action (reader, "mail-forward-attached-full"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); - - action = e_mail_reader_get_action (reader, "mail-forward-inline-full"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); - - action = e_mail_reader_get_action (reader, "mail-forward-quoted-full"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); - - action = e_mail_reader_get_action (reader, "mail-redirect"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); - - gtk_widget_show_all (menu); - - return menu; + if (!mail_display) + return FALSE; + + if (gtk_widget_has_focus (GTK_WIDGET (mail_display)) && + e_web_view_get_need_input (E_WEB_VIEW (mail_display))) + return TRUE; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (mail_display)); + + if (GTK_IS_WINDOW (toplevel)) + return e_util_ignore_accel_for_focused (gtk_window_get_focus (GTK_WINDOW (toplevel))); + + return FALSE; } diff --git a/src/mail/e-mail-reader.h b/src/mail/e-mail-reader.h index 41ce3946c8..cd542d0f44 100644 --- a/src/mail/e-mail-reader.h +++ b/src/mail/e-mail-reader.h @@ -54,9 +54,6 @@ (G_TYPE_INSTANCE_GET_INTERFACE \ ((obj), E_TYPE_MAIL_READER, EMailReaderInterface)) -/* Basename of the UI definition file. */ -#define E_MAIL_READER_UI_DEFINITION "evolution-mail-reader.ui" - G_BEGIN_DECLS typedef struct _EMailReader EMailReader; @@ -98,15 +95,13 @@ enum { struct _EMailReaderInterface { GTypeInterface parent_interface; - GtkActionGroup * - (*get_action_group) (EMailReader *reader, - EMailReaderActionGroup group); + void (*init_ui_data) (EMailReader *reader); + EUIManager * (*get_ui_manager) (EMailReader *reader); EAlertSink * (*get_alert_sink) (EMailReader *reader); EMailBackend * (*get_backend) (EMailReader *reader); EMailDisplay * (*get_mail_display) (EMailReader *reader); gboolean (*get_hide_deleted) (EMailReader *reader); GtkWidget * (*get_message_list) (EMailReader *reader); - GtkMenu * (*get_popup_menu) (EMailReader *reader); EPreviewPane * (*get_preview_pane) (EMailReader *reader); GPtrArray * (*get_selected_uids) (EMailReader *reader); GPtrArray * (*get_selected_uids_with_collapsed_threads) @@ -137,27 +132,25 @@ struct _EMailReaderInterface { gboolean (*close_on_delete_or_junk) (EMailReader *reader); void (*reload) (EMailReader *reader); - void (*remove_ui) (EMailReader *reader); /* Padding for future expansion */ gpointer reserved[1]; }; GType e_mail_reader_get_type (void); -void e_mail_reader_init (EMailReader *reader, - gboolean init_actions, - gboolean connect_signals); +void e_mail_reader_init (EMailReader *reader); void e_mail_reader_dispose (EMailReader *reader); void e_mail_reader_changed (EMailReader *reader); guint32 e_mail_reader_check_state (EMailReader *reader); EActivity * e_mail_reader_new_activity (EMailReader *reader); void e_mail_reader_update_actions (EMailReader *reader, guint32 state); -GtkAction * e_mail_reader_get_action (EMailReader *reader, +void e_mail_reader_init_ui_data_default + (EMailReader *self); +void e_mail_reader_init_ui_data (EMailReader *reader); +EUIManager * e_mail_reader_get_ui_manager (EMailReader *reader); +EUIAction * e_mail_reader_get_action (EMailReader *reader, const gchar *action_name); -GtkActionGroup * - e_mail_reader_get_action_group (EMailReader *reader, - EMailReaderActionGroup group); EAlertSink * e_mail_reader_get_alert_sink (EMailReader *reader); EMailBackend * e_mail_reader_get_backend (EMailReader *reader); EMailDisplay * e_mail_reader_get_mail_display (EMailReader *reader); @@ -200,10 +193,6 @@ gboolean e_mail_reader_get_delete_selects_previous void e_mail_reader_set_delete_selects_previous (EMailReader *reader, gboolean delete_selects_previous); -void e_mail_reader_create_charset_menu - (EMailReader *reader, - GtkUIManager *ui_manager, - guint merge_id); void e_mail_reader_show_search_bar (EMailReader *reader); void e_mail_reader_avoid_next_mark_as_seen (EMailReader *reader); @@ -213,10 +202,7 @@ void e_mail_reader_composer_created (EMailReader *reader, EMsgComposer *composer, CamelMimeMessage *message); void e_mail_reader_reload (EMailReader *reader); -void e_mail_reader_remove_ui (EMailReader *reader); -GtkWidget * e_mail_reader_create_reply_menu (EMailReader *reader); -GtkWidget * e_mail_reader_create_forward_menu - (EMailReader *reader); +gboolean e_mail_reader_ignore_accel (EMailReader *reader); G_END_DECLS diff --git a/src/mail/e-mail-templates-store.c b/src/mail/e-mail-templates-store.c index 6e61bd9a6e..0541705e4a 100644 --- a/src/mail/e-mail-templates-store.c +++ b/src/mail/e-mail-templates-store.c @@ -27,6 +27,9 @@ #include "e-mail-templates-store.h" +/* where on a GMenu the index of the action data is stored */ +#define TEMPLATES_STORE_ACTIONS_INDEX_KEY "templates-store-actions-index-key" + struct _EMailTemplatesStorePrivate { GWeakRef *account_store_weakref; /* EMailAccountStore * */ @@ -2042,9 +2045,22 @@ tmpl_action_data_free (gpointer ptr) } static void -templates_store_action_activated_cb (GtkAction *action, - TmplActionData *tad) +templates_store_action_activate_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + GMenu *top_menu = user_data; + GHashTable *actions_index; + TmplActionData *tad; + + g_return_if_fail (G_IS_MENU (top_menu)); + + actions_index = g_object_get_data (G_OBJECT (top_menu), TEMPLATES_STORE_ACTIONS_INDEX_KEY); + + g_return_if_fail (actions_index != NULL); + + tad = g_hash_table_lookup (actions_index, GUINT_TO_POINTER (g_variant_get_uint32 (parameter))); + g_return_if_fail (tad != NULL); g_return_if_fail (tad->action_cb != NULL); @@ -2054,15 +2070,11 @@ templates_store_action_activated_cb (GtkAction *action, static void templates_store_add_to_menu_recurse (EMailTemplatesStore *templates_store, GNode *node, - GtkUIManager *ui_manager, - GtkActionGroup *action_group, - const gchar *base_menu_path, - const gchar *base_popup_path, - guint merge_id, + GMenu *parent_menu, EMailTemplatesStoreActionFunc action_cb, gpointer action_cb_user_data, gboolean with_folder_menu, - guint *action_count) + GHashTable *actions_index) { TmplFolderData *tfd; @@ -2074,76 +2086,40 @@ templates_store_add_to_menu_recurse (EMailTemplatesStore *templates_store, tmpl_folder_data_lock (tfd); if (tfd->folder) { - GtkAction *action; - gchar *action_name, *menu_path = NULL, *popup_path = NULL; - const gchar *use_menu_path; - const gchar *use_popup_path; + GMenu *use_parent_menu = parent_menu; GSList *link; - if (with_folder_menu) { - action_name = g_strdup_printf ("templates-menu-%d", *action_count); - *action_count = *action_count + 1; - - action = gtk_action_new (action_name, camel_folder_get_display_name (tfd->folder), NULL, NULL); - gtk_action_group_add_action (action_group, action); - - gtk_ui_manager_add_ui (ui_manager, merge_id, base_menu_path, action_name, - action_name, GTK_UI_MANAGER_MENU, FALSE); - - gtk_ui_manager_add_ui (ui_manager, merge_id, base_popup_path, action_name, - action_name, GTK_UI_MANAGER_MENU, FALSE); - - menu_path = g_strdup_printf ("%s/%s", base_menu_path, action_name); - use_menu_path = menu_path; - - popup_path = g_strdup_printf ("%s/%s", base_popup_path, action_name); - use_popup_path = popup_path; - - g_object_unref (action); - g_free (action_name); - } else { - use_menu_path = base_menu_path; - use_popup_path = base_popup_path; - } + if (with_folder_menu) + use_parent_menu = g_menu_new (); if (node->children) { templates_store_add_to_menu_recurse (templates_store, node->children, - ui_manager, action_group, use_menu_path, use_popup_path, merge_id, - action_cb, action_cb_user_data, TRUE, action_count); + use_parent_menu, action_cb, action_cb_user_data, TRUE, actions_index); } for (link = tfd->messages; link; link = g_slist_next (link)) { TmplMessageData *tmd = link->data; if (tmd && tmd->uid && tmd->subject) { - action_name = g_strdup_printf ("templates-item-%d", *action_count); - *action_count = *action_count + 1; + GMenuItem *item; + guint action_idx = g_hash_table_size (actions_index) + 1; - action = gtk_action_new (action_name, tmd->subject, NULL, NULL); + item = g_menu_item_new (tmd->subject, "templates-store.template-use-this"); + g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_TARGET, "u", action_idx); + g_menu_append_item (use_parent_menu, item); + g_clear_object (&item); - g_signal_connect_data ( - action, "activate", - G_CALLBACK (templates_store_action_activated_cb), - tmpl_action_data_new (templates_store, tfd->folder, tmd->uid, action_cb, action_cb_user_data), - (GClosureNotify) tmpl_action_data_free, 0); - - gtk_action_group_add_action (action_group, action); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, use_menu_path, action_name, - action_name, GTK_UI_MANAGER_MENUITEM, FALSE); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, use_popup_path, action_name, - action_name, GTK_UI_MANAGER_MENUITEM, FALSE); - - g_object_unref (action); - g_free (action_name); + g_hash_table_insert (actions_index, GUINT_TO_POINTER (action_idx), + tmpl_action_data_new (templates_store, tfd->folder, tmd->uid, action_cb, action_cb_user_data)); } } - g_free (menu_path); - g_free (popup_path); + if (use_parent_menu != parent_menu) { + if (g_menu_model_get_n_items (G_MENU_MODEL (use_parent_menu)) > 0) + g_menu_append_submenu (parent_menu, camel_folder_get_display_name (tfd->folder), G_MENU_MODEL (use_parent_menu)); + + g_clear_object (&use_parent_menu); + } } tmpl_folder_data_unlock (tfd); @@ -2154,38 +2130,33 @@ templates_store_add_to_menu_recurse (EMailTemplatesStore *templates_store, } void -e_mail_templates_store_build_menu (EMailTemplatesStore *templates_store, - EShellView *shell_view, - GtkUIManager *ui_manager, - GtkActionGroup *action_group, - const gchar *base_menu_path, - const gchar *base_popup_path, - guint merge_id, - EMailTemplatesStoreActionFunc action_cb, - gpointer action_cb_user_data) +e_mail_templates_store_update_menu (EMailTemplatesStore *templates_store, + GMenu *menu_to_update, + EUIManager *ui_manager, + EMailTemplatesStoreActionFunc action_cb, + gpointer action_cb_user_data) { GSList *link; - GtkAction *action; + GHashTable *actions_index; gint multiple_accounts = 0; - guint action_count = 0; - const gchar *main_menu_path = base_menu_path; - const gchar *main_popup_path = base_popup_path; - gchar *tmp_menu_path = NULL; - gchar *action_name; g_return_if_fail (E_IS_MAIL_TEMPLATES_STORE (templates_store)); - g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); - g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); - g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); - g_return_if_fail (base_menu_path != NULL); - g_return_if_fail (base_popup_path != NULL); - g_return_if_fail (merge_id != 0); + g_return_if_fail (G_IS_MENU (menu_to_update)); g_return_if_fail (action_cb != NULL); templates_store_lock (templates_store); - gtk_ui_manager_remove_ui (ui_manager, merge_id); - e_action_group_remove_all_actions (action_group); + g_menu_remove_all (menu_to_update); + actions_index = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, tmpl_action_data_free); + + if (!e_ui_manager_has_action_group (ui_manager, "templates-store")) { + EUIAction *action; + + action = e_ui_action_new ("templates-store", "template-use-this", G_VARIANT_TYPE_UINT32); + e_ui_action_set_label (action, "template-use-this"); + + e_ui_manager_add_action (ui_manager, e_ui_action_get_map_name (action), action, templates_store_action_activate_cb, NULL, menu_to_update); + } for (link = templates_store->priv->stores; link && multiple_accounts <= 1; link = g_slist_next (link)) { TmplStoreData *tsd = link->data; @@ -2223,42 +2194,21 @@ e_mail_templates_store_build_menu (EMailTemplatesStore *templates_store, store = g_weak_ref_get (tsd->store_weakref); if (store) { - gchar *menu_path = NULL, *popup_path = NULL; - const gchar *use_menu_path = main_menu_path; - const gchar *use_popup_path = main_popup_path; + GMenu *parent_menu = menu_to_update; if (multiple_accounts > 1) { - action_name = g_strdup_printf ("templates-menu-%d", action_count); - action_count++; - - action = gtk_action_new (action_name, camel_service_get_display_name (CAMEL_SERVICE (store)), NULL, NULL); - - gtk_action_group_add_action (action_group, action); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, main_menu_path, action_name, - action_name, GTK_UI_MANAGER_MENU, FALSE); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, main_popup_path, action_name, - action_name, GTK_UI_MANAGER_MENU, FALSE); - - menu_path = g_strdup_printf ("%s/%s", main_menu_path, action_name); - use_menu_path = menu_path; - - popup_path = g_strdup_printf ("%s/%s", main_popup_path, action_name); - use_popup_path = popup_path; - - g_object_unref (action); - g_free (action_name); + parent_menu = g_menu_new (); } templates_store_add_to_menu_recurse (templates_store, tsd->folders->children, - ui_manager, action_group, use_menu_path, use_popup_path, merge_id, - action_cb, action_cb_user_data, FALSE, &action_count); + parent_menu, action_cb, action_cb_user_data, FALSE, actions_index); - g_free (menu_path); - g_free (popup_path); + if (parent_menu != menu_to_update) { + if (g_menu_model_get_n_items (G_MENU_MODEL (parent_menu)) > 0) + g_menu_append_submenu (menu_to_update, camel_service_get_display_name (CAMEL_SERVICE (store)), G_MENU_MODEL (parent_menu)); + + g_object_unref (parent_menu); + } } g_clear_object (&store); @@ -2269,9 +2219,13 @@ e_mail_templates_store_build_menu (EMailTemplatesStore *templates_store, templates_store_unlock (templates_store); - gtk_ui_manager_ensure_update (ui_manager); - - g_free (tmp_menu_path); + if (g_hash_table_size (actions_index) > 0) { + g_object_set_data_full (G_OBJECT (menu_to_update), TEMPLATES_STORE_ACTIONS_INDEX_KEY, + actions_index, (GDestroyNotify) g_hash_table_unref); + } else { + g_object_set_data_full (G_OBJECT (menu_to_update), TEMPLATES_STORE_ACTIONS_INDEX_KEY, NULL, NULL); + g_hash_table_unref (actions_index); + } } static void diff --git a/src/mail/e-mail-templates-store.h b/src/mail/e-mail-templates-store.h index cccae1a5cd..81212f29b9 100644 --- a/src/mail/e-mail-templates-store.h +++ b/src/mail/e-mail-templates-store.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -89,14 +90,10 @@ EMailTemplatesStore * EMailAccountStore * e_mail_templates_store_ref_account_store (EMailTemplatesStore *templates_store); -void e_mail_templates_store_build_menu +void e_mail_templates_store_update_menu (EMailTemplatesStore *templates_store, - EShellView *shell_view, - GtkUIManager *ui_manager, - GtkActionGroup *action_group, - const gchar *base_menu_path, - const gchar *base_popup_path, - guint merge_id, + GMenu *menu_to_update, + EUIManager *ui_manager, EMailTemplatesStoreActionFunc action_cb, gpointer action_cb_user_data); GtkTreeStore * e_mail_templates_store_build_model diff --git a/src/mail/e-mail-viewer.c b/src/mail/e-mail-viewer.c index b242b56075..f6509e450d 100644 --- a/src/mail/e-mail-viewer.c +++ b/src/mail/e-mail-viewer.c @@ -27,23 +27,20 @@ #include "e-mail-viewer.h" struct _EMailViewerPrivate { + EUIManager *ui_manager; GtkWidget *statusbar; - GtkMenuBar *real_menu_bar; EMenuBar *e_menu_bar; + GtkWidget *menu_button; /* owned by e_menu_bar */ GtkWidget *webview_preview; EAlertBar *alert_bar; EActivityBar *activity_bar; + EUIMenu *main_menu; EMailBackend *backend; GFile *file; GCancellable *cancellable; - GtkBuilder *builder; EMailDisplay *mail_display; GtkWidget *preview_pane; - GActionMap *action_map; - GtkAccelGroup *accel_group; - GMenuItem *file_import; - gboolean has_menumultiple; gboolean scan_from; }; @@ -514,7 +511,7 @@ mail_viewer_import (EMailViewer *self, } static void -import_one_activated_cb (GSimpleAction *action, +import_one_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -536,7 +533,7 @@ import_one_activated_cb (GSimpleAction *action, } static void -import_all_activated_cb (GSimpleAction *action, +import_all_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -576,7 +573,7 @@ mail_viewer_print_done_cb (GObject *source_object, } static void -open_activated_cb (GSimpleAction *action, +open_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -627,7 +624,7 @@ open_activated_cb (GSimpleAction *action, } static void -print_activated_cb (GSimpleAction *action, +print_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -645,7 +642,7 @@ print_activated_cb (GSimpleAction *action, } static void -close_activated_cb (GSimpleAction *action, +close_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -657,7 +654,7 @@ close_activated_cb (GSimpleAction *action, } static void -cut_activated_cb (GSimpleAction *action, +cut_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -669,7 +666,7 @@ cut_activated_cb (GSimpleAction *action, } static void -copy_activated_cb (GSimpleAction *action, +copy_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -681,7 +678,7 @@ copy_activated_cb (GSimpleAction *action, } static void -paste_activated_cb (GSimpleAction *action, +paste_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -693,7 +690,7 @@ paste_activated_cb (GSimpleAction *action, } static void -select_all_activated_cb (GSimpleAction *action, +select_all_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -705,7 +702,7 @@ select_all_activated_cb (GSimpleAction *action, } static void -find_activated_cb (GSimpleAction *action, +find_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -717,7 +714,7 @@ find_activated_cb (GSimpleAction *action, } static void -load_images_activated_cb (GSimpleAction *action, +load_images_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -729,7 +726,7 @@ load_images_activated_cb (GSimpleAction *action, } static void -activate_toggle_cb (GSimpleAction *action, +activate_toggle_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -741,15 +738,7 @@ activate_toggle_cb (GSimpleAction *action, } static void -activate_radio_cb (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) -{ - g_action_change_state (G_ACTION (action), parameter); -} - -static void -all_headers_change_state_cb (GSimpleAction *action, +all_headers_change_state_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -758,7 +747,7 @@ all_headers_change_state_cb (GSimpleAction *action, g_return_if_fail (E_IS_MAIL_VIEWER (self)); - g_simple_action_set_state (action, parameter); + e_ui_action_set_state (action, parameter); mode = e_mail_display_get_mode (self->priv->mail_display); @@ -771,7 +760,7 @@ all_headers_change_state_cb (GSimpleAction *action, } static void -msg_source_change_state_cb (GSimpleAction *action, +msg_source_change_state_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -779,28 +768,24 @@ msg_source_change_state_cb (GSimpleAction *action, g_return_if_fail (E_IS_MAIL_VIEWER (self)); - g_simple_action_set_state (action, parameter); + e_ui_action_set_state (action, parameter); if (g_variant_get_boolean (parameter)) { e_mail_display_set_mode (self->priv->mail_display, E_MAIL_FORMATTER_MODE_SOURCE); } else { - GAction *all_headers_action; - GVariant *all_headers_value; + EUIAction *all_headers_action; - all_headers_action = g_action_map_lookup_action (self->priv->action_map, "all-headers"); - all_headers_value = g_action_get_state (all_headers_action); + all_headers_action = e_ui_manager_get_action (self->priv->ui_manager, "all-headers"); - if (all_headers_value && g_variant_get_boolean (all_headers_value)) + if (e_ui_action_get_active (all_headers_action)) e_mail_display_set_mode (self->priv->mail_display, E_MAIL_FORMATTER_MODE_ALL_HEADERS); else e_mail_display_set_mode (self->priv->mail_display, E_MAIL_FORMATTER_MODE_NORMAL); - - g_clear_pointer (&all_headers_value, g_variant_unref); } } static void -caret_mode_change_state_cb (GSimpleAction *action, +caret_mode_change_state_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -808,13 +793,13 @@ caret_mode_change_state_cb (GSimpleAction *action, g_return_if_fail (E_IS_MAIL_VIEWER (self)); - g_simple_action_set_state (action, parameter); + e_ui_action_set_state (action, parameter); e_web_view_set_caret_mode (E_WEB_VIEW (self->priv->mail_display), g_variant_get_boolean (parameter)); } static void -zoom_in_activated_cb (GSimpleAction *action, +zoom_in_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -826,7 +811,7 @@ zoom_in_activated_cb (GSimpleAction *action, } static void -zoom_out_activated_cb (GSimpleAction *action, +zoom_out_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -838,7 +823,7 @@ zoom_out_activated_cb (GSimpleAction *action, } static void -zoom_zero_activated_cb (GSimpleAction *action, +zoom_zero_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -850,7 +835,7 @@ zoom_zero_activated_cb (GSimpleAction *action, } static void -charset_change_state_cb (GSimpleAction *action, +charset_change_state_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -859,7 +844,7 @@ charset_change_state_cb (GSimpleAction *action, g_return_if_fail (E_IS_MAIL_VIEWER (self)); - g_simple_action_set_state (action, parameter); + e_ui_action_set_state (action, parameter); formatter = e_mail_display_get_formatter (self->priv->mail_display); @@ -868,7 +853,7 @@ charset_change_state_cb (GSimpleAction *action, charset = g_variant_get_string (parameter, NULL); - /* Default value it an empty string in the GMenu, but a NULL for the formatter */ + /* Default value is an empty string in the GMenu, but a NULL for the formatter */ if (charset && !*charset) charset = NULL; @@ -904,7 +889,7 @@ mail_viewer_edit_as_new_composer_created_cb (GObject *source_object, } static void -edit_as_new_activated_cb (GSimpleAction *action, +edit_as_new_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -924,7 +909,7 @@ edit_as_new_activated_cb (GSimpleAction *action, } static void -add_sender_activated_cb (GSimpleAction *action, +add_sender_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -992,7 +977,7 @@ mail_viewer_goto (EMailViewer *self, } static void -go_to_next_activated_cb (GSimpleAction *action, +go_to_next_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1004,7 +989,7 @@ go_to_next_activated_cb (GSimpleAction *action, } static void -go_to_previous_activated_cb (GSimpleAction *action, +go_to_previous_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1091,7 +1076,7 @@ mail_viewer_reply_message (EMailViewer *self, } static void -reply_sender_activated_cb (GSimpleAction *action, +reply_sender_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1103,7 +1088,7 @@ reply_sender_activated_cb (GSimpleAction *action, } static void -reply_list_activated_cb (GSimpleAction *action, +reply_list_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1115,7 +1100,7 @@ reply_list_activated_cb (GSimpleAction *action, } static void -reply_all_activated_cb (GSimpleAction *action, +reply_all_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1127,7 +1112,7 @@ reply_all_activated_cb (GSimpleAction *action, } static void -reply_alt_activated_cb (GSimpleAction *action, +reply_alt_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1198,7 +1183,7 @@ mail_viewer_forward_message (EMailViewer *self, } static void -forward_activated_cb (GSimpleAction *action, +forward_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1216,7 +1201,7 @@ forward_activated_cb (GSimpleAction *action, } static void -forward_attached_activated_cb (GSimpleAction *action, +forward_attached_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1228,7 +1213,7 @@ forward_attached_activated_cb (GSimpleAction *action, } static void -forward_inline_activated_cb (GSimpleAction *action, +forward_inline_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1240,7 +1225,7 @@ forward_inline_activated_cb (GSimpleAction *action, } static void -forward_quoted_activated_cb (GSimpleAction *action, +forward_quoted_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1274,7 +1259,7 @@ mail_viewer_redirect_composer_created_cb (GObject *source_object, } static void -redirect_activated_cb (GSimpleAction *action, +redirect_activated_cb (EUIAction *action, GVariant *parameter, gpointer user_data) { @@ -1293,174 +1278,6 @@ redirect_activated_cb (GSimpleAction *action, e_msg_composer_new (shell, mail_viewer_redirect_composer_created_cb, g_object_ref (msg)); } -static void -mail_viewer_init_actions (EMailViewer *self) -{ - GActionEntry actions[] = { - { "import-one", import_one_activated_cb, NULL, NULL, NULL }, - { "import-all", import_all_activated_cb, NULL, NULL, NULL }, - { "open", open_activated_cb, NULL, NULL, NULL }, - { "print", print_activated_cb, NULL, NULL, NULL }, - { "close", close_activated_cb, NULL, NULL, NULL }, - { "cut", cut_activated_cb, NULL, NULL, NULL }, - { "copy", copy_activated_cb, NULL, NULL, NULL }, - { "paste", paste_activated_cb, NULL, NULL, NULL }, - { "select-all", select_all_activated_cb, NULL, NULL, NULL }, - { "find", find_activated_cb, NULL, NULL, NULL }, - { "load-images", load_images_activated_cb, NULL, NULL, NULL }, - { "all-headers", activate_toggle_cb, NULL, "false", all_headers_change_state_cb }, - { "msg-source", activate_toggle_cb, NULL, "false", msg_source_change_state_cb }, - { "caret-mode", activate_toggle_cb, NULL, "false", caret_mode_change_state_cb }, - { "zoom-in", zoom_in_activated_cb, NULL, NULL, NULL }, - { "zoom-out", zoom_out_activated_cb, NULL, NULL, NULL }, - { "zoom-zero", zoom_zero_activated_cb, NULL, NULL, NULL }, - { "charset", activate_radio_cb, "s", "''", charset_change_state_cb }, - { "edit-as-new", edit_as_new_activated_cb, NULL, NULL, NULL }, - { "add-sender", add_sender_activated_cb, NULL, NULL, NULL }, - { "goto-next", go_to_next_activated_cb, NULL, NULL, NULL }, - { "goto-previous", go_to_previous_activated_cb, NULL, NULL, NULL }, - { "reply-sender", reply_sender_activated_cb, NULL, NULL, NULL }, - { "reply-list", reply_list_activated_cb, NULL, NULL, NULL }, - { "reply-all", reply_all_activated_cb, NULL, NULL, NULL }, - { "reply-alt", reply_alt_activated_cb, NULL, NULL, NULL }, - { "forward", forward_activated_cb, NULL, NULL, NULL }, - { "forward-attached", forward_attached_activated_cb, NULL, NULL, NULL }, - { "forward-inline", forward_inline_activated_cb, NULL, NULL, NULL }, - { "forward-quoted", forward_quoted_activated_cb, NULL, NULL, NULL }, - { "redirect", redirect_activated_cb, NULL, NULL, NULL } - }; - GSimpleActionGroup *group; - - group = g_simple_action_group_new (); - - g_action_map_add_action_entries (G_ACTION_MAP (group), actions, G_N_ELEMENTS (actions), self); - gtk_widget_insert_action_group (GTK_WIDGET (self), "mail-viewer", G_ACTION_GROUP (group)); - - self->priv->action_map = G_ACTION_MAP (group); -} - -static void -mail_viewer_closure_accel_activate (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - GAction *action = G_ACTION (closure->data); - - if (g_action_get_enabled (action)) { - const GVariantType *param_type; - - param_type = g_action_get_parameter_type (action); - if (!param_type) { - g_action_activate (action, NULL); - } else if (param_type == G_VARIANT_TYPE_BOOLEAN) { - GVariant *current_value = g_action_get_state (action); - GVariant *new_value; - - new_value = g_variant_new_boolean (current_value ? !g_variant_get_boolean (current_value) : TRUE); - g_variant_ref_sink (new_value); - - g_action_activate (action, new_value); - - g_clear_pointer (¤t_value, g_variant_unref); - g_clear_pointer (&new_value, g_variant_unref); - } else { - g_warn_if_reached (); - } - - /* accelerator was handled */ - g_value_set_boolean (return_value, TRUE); - } -} - -static void -mail_viewer_traverse_menu_model (EMailViewer *self, - GMenuModel *menu_model, - gint item_index) -{ - GMenuLinkIter *iter; - gchar *accel_str = NULL; - - if (g_menu_model_get_item_attribute (menu_model, item_index, "accel", "s", &accel_str)) { - gchar *action_name = NULL; - - if (g_menu_model_get_item_attribute (menu_model, item_index, "action", "s", &action_name) && action_name) { - if (g_str_has_prefix (action_name, "mail-viewer.")) { - const gchar *after_dot = action_name + strlen ("mail-viewer."); - GAction *action = g_action_map_lookup_action (self->priv->action_map, after_dot); - - if (action) { - guint key = 0; - GdkModifierType mods = 0; - - gtk_accelerator_parse (accel_str, &key, &mods); - - if (key != 0) { - GClosure *closure; - - closure = g_closure_new_object (sizeof (GClosure), G_OBJECT (action)); - g_closure_set_marshal (closure, mail_viewer_closure_accel_activate); - - gtk_accel_group_connect (self->priv->accel_group, key, mods, GTK_ACCEL_LOCKED, closure); - } - } - } - - g_free (action_name); - } - - g_free (accel_str); - } - - iter = g_menu_model_iterate_item_links (menu_model, item_index); - if (iter) { - while (g_menu_link_iter_next (iter)) { - GMenuModel *submenu_model = g_menu_link_iter_get_value (iter); - if (submenu_model) { - gint ii, n_items; - - n_items = g_menu_model_get_n_items (submenu_model); - - for (ii = 0; ii < n_items; ii++) { - mail_viewer_traverse_menu_model (self, submenu_model, ii); - } - } - g_clear_object (&submenu_model); - } - - g_clear_object (&iter); - } -} - -static void -mail_viewer_init_accel_group (EMailViewer *self) -{ - GMenuModel *menu_model; - gint n_items, ii; - - g_return_if_fail (self->priv->accel_group == NULL); - - self->priv->accel_group = gtk_accel_group_new (); - - menu_model = G_MENU_MODEL (gtk_builder_get_object (self->priv->builder, "menu")); - n_items = g_menu_model_get_n_items (menu_model); - - for (ii = 0; ii < n_items; ii++) { - mail_viewer_traverse_menu_model (self, menu_model, ii); - } - - menu_model = G_MENU_MODEL (gtk_builder_get_object (self->priv->builder, "goto-menu")); - n_items = g_menu_model_get_n_items (menu_model); - - for (ii = 0; ii < n_items; ii++) { - mail_viewer_traverse_menu_model (self, menu_model, ii); - } - - gtk_window_add_accel_group (GTK_WINDOW (self), self->priv->accel_group); -} - static void mail_viewer_update_actions (EMailViewer *self) { @@ -1477,7 +1294,7 @@ mail_viewer_update_actions (EMailViewer *self) "zoom-in", "zoom-out", "zoom-zero", - "charset", + "EMailViewer::charset-menu", "edit-as-new", "add-sender", "reply-sender", @@ -1489,21 +1306,23 @@ mail_viewer_update_actions (EMailViewer *self) "forward-quoted", "redirect" }; - GActionMap *action_map; - GAction *action; + CamelMimeMessage *msg; + EUIAction *action; + EUIManager *ui_manager; GtkTreeView *tree_view; GtkTreeModel *model; - CamelMimeMessage *msg; gboolean has_message = FALSE; gboolean has_list_post_header = FALSE; gboolean can_goto_next = FALSE; gboolean can_goto_previous = FALSE; guint ii; - action_map = self->priv->action_map; - if (!action_map) + ui_manager = self->priv->ui_manager; + if (!ui_manager) return; + e_ui_menu_freeze (self->priv->main_menu); + msg = mail_viewer_get_current_message (self); has_message = msg != NULL; @@ -1529,18 +1348,20 @@ mail_viewer_update_actions (EMailViewer *self) } for (ii = 0; ii < G_N_ELEMENTS (actions); ii++) { - action = g_action_map_lookup_action (action_map, actions[ii]); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), has_message); + action = e_ui_manager_get_action (ui_manager, actions[ii]); + e_ui_action_set_sensitive (action, has_message); } - action = g_action_map_lookup_action (action_map, "reply-list"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), has_message && has_list_post_header); + action = e_ui_manager_get_action (ui_manager, "reply-list"); + e_ui_action_set_sensitive (action, has_message && has_list_post_header); - action = g_action_map_lookup_action (action_map, "goto-next"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_goto_next); + action = e_ui_manager_get_action (ui_manager, "goto-next"); + e_ui_action_set_sensitive (action, can_goto_next); - action = g_action_map_lookup_action (action_map, "goto-previous"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_goto_previous); + action = e_ui_manager_get_action (ui_manager, "goto-previous"); + e_ui_action_set_sensitive (action, can_goto_previous); + + e_ui_menu_thaw (self->priv->main_menu); } static void @@ -1757,12 +1578,12 @@ mail_viewer_can_execute_editing_command_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { - GSimpleAction *action = user_data; + EUIAction *action = user_data; gboolean can_do_command; can_do_command = webkit_web_view_can_execute_editing_command_finish (WEBKIT_WEB_VIEW (source_object), result, NULL); - g_simple_action_set_enabled (action, can_do_command); + e_ui_action_set_sensitive (action, can_do_command); g_object_unref (action); } @@ -1773,62 +1594,375 @@ mail_viewer_update_clipboard_actions (EMailViewer *self) if (self->priv->mail_display) { WebKitWebView *web_view = WEBKIT_WEB_VIEW (self->priv->mail_display); - GAction *action; + EUIAction *action; - action = g_action_map_lookup_action (self->priv->action_map, "copy"); - g_simple_action_set_enabled (G_SIMPLE_ACTION (action), e_web_view_has_selection (E_WEB_VIEW (web_view))); + action = e_ui_manager_get_action (self->priv->ui_manager, "copy"); + e_ui_action_set_sensitive (action, e_web_view_has_selection (E_WEB_VIEW (web_view))); - action = g_action_map_lookup_action (self->priv->action_map, "cut"); + action = e_ui_manager_get_action (self->priv->ui_manager, "cut"); webkit_web_view_can_execute_editing_command (web_view, WEBKIT_EDITING_COMMAND_CUT, NULL, mail_viewer_can_execute_editing_command_cb, g_object_ref (action)); - action = g_action_map_lookup_action (self->priv->action_map, "paste"); + action = e_ui_manager_get_action (self->priv->ui_manager, "paste"); webkit_web_view_can_execute_editing_command (web_view, WEBKIT_EDITING_COMMAND_PASTE, NULL, mail_viewer_can_execute_editing_command_cb, g_object_ref (action)); } } static gboolean -mail_viewer_key_press_event_cb (GtkWidget *widget, - GdkEventKey *event) +e_mail_viewer_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) { - EMailViewer *self = E_MAIL_VIEWER (widget); - GtkWidget *focused; + EMailViewer *self = user_data; + const gchar *name; - if (!event || (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0 || - event->keyval == GDK_KEY_Tab || - event->keyval == GDK_KEY_Return || - event->keyval == GDK_KEY_KP_Tab || - event->keyval == GDK_KEY_KP_Enter) - return event && e_mail_display_need_key_event (self->priv->mail_display, event); + g_return_val_if_fail (E_IS_MAIL_VIEWER (self), FALSE); - focused = gtk_window_get_focus (GTK_WINDOW (self)); + name = g_action_get_name (G_ACTION (action)); - if (focused && (GTK_IS_ENTRY (focused) || GTK_IS_EDITABLE (focused) || - (GTK_IS_TREE_VIEW (focused) && gtk_tree_view_get_search_column (GTK_TREE_VIEW (focused)) >= 0))) { - gtk_widget_event (focused, (GdkEvent *) event); - return event->keyval != GDK_KEY_Escape; + if (!g_str_has_prefix (name, "EMailViewer::")) + return FALSE; + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (for_kind == E_UI_ELEMENT_KIND_MENU) { + if (is_action ("EMailViewer::charset-menu")) { + GMenu *charset_menu; + GMenuItem *menu_item; + + charset_menu = g_menu_new (); + + menu_item = g_menu_item_new (_("_Default"), NULL); + g_menu_item_set_action_and_target (menu_item, "mail-viewer.EMailViewer::charset-menu", "s", ""); + g_menu_append_item (charset_menu, menu_item); + g_clear_object (&menu_item); + + e_charset_add_to_g_menu (charset_menu, "mail-viewer.EMailViewer::charset-menu"); + + *out_item = G_OBJECT (g_menu_item_new_submenu (e_ui_action_get_label (action), G_MENU_MODEL (charset_menu))); + + g_clear_object (&charset_menu); + + if (self->priv->mail_display) { + EMailFormatter *formatter; + + formatter = e_mail_display_get_formatter (self->priv->mail_display); + if (formatter) { + const gchar *charset; + + charset = e_mail_formatter_get_charset (formatter); + e_ui_action_set_state (action, g_variant_new_string (charset ? charset : "")); + } else { + e_ui_action_set_state (action, g_variant_new_string ("")); + } + } else { + e_ui_action_set_state (action, g_variant_new_string ("")); + } + } else { + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + if (is_action ("EMailViewer::menu-button")) + *out_item = G_OBJECT (g_object_ref (self->priv->menu_button)); + else + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); } - if (e_web_view_get_need_input (E_WEB_VIEW (self->priv->mail_display)) && - gtk_widget_has_focus (GTK_WIDGET (self->priv->mail_display))) { - gtk_widget_event (GTK_WIDGET (self->priv->mail_display), (GdkEvent *) event); - return TRUE; - } + #undef is_action - if (e_mail_display_need_key_event (self->priv->mail_display, event)) + return TRUE; +} + +static gboolean +e_mail_viewer_ui_manager_ignore_accel_cb (EUIManager *ui_amanger, + EUIAction *action, + gpointer user_data) +{ + EMailViewer *self = user_data; + + g_return_val_if_fail (E_IS_MAIL_VIEWER (self), FALSE); + + if (self->priv->mail_display && + gtk_widget_has_focus (GTK_WIDGET (self->priv->mail_display)) && + e_web_view_get_need_input (E_WEB_VIEW (self->priv->mail_display))) return TRUE; - if (event->keyval == GDK_KEY_Escape) { - GAction *action; + return e_util_ignore_accel_for_focused (gtk_window_get_focus (GTK_WINDOW (self))); +} - action = g_action_map_lookup_action (self->priv->action_map, "close"); - g_action_activate (action, NULL); +static void +mail_viewer_init_ui_manager (EMailViewer *self) +{ + static const EUIActionEntry entries[] = { + { "file-import", + NULL, + N_("_Import…"), + NULL, + NULL, + import_all_activated_cb, NULL, NULL, NULL }, - return TRUE; - } + { "import-one", + NULL, + N_("_Import…"), + NULL, + NULL, + import_one_activated_cb, NULL, NULL, NULL }, - return FALSE; + { "import-all", + NULL, + N_("_Import All…"), + NULL, + NULL, + import_all_activated_cb, NULL, NULL, NULL }, + + { "open", + "document-open", + N_("_Open…"), + "o", + NULL, + open_activated_cb, NULL, NULL, NULL }, + + { "print", + "document-print", + N_("_Print"), + "p", + NULL, + print_activated_cb, NULL, NULL, NULL }, + + { "close", + NULL, + N_("_Close"), + "w", + NULL, + close_activated_cb, NULL, NULL, NULL }, + + { "cut", + "edit-cut", + N_("C_ut"), + "x", + NULL, + cut_activated_cb, NULL, NULL, NULL }, + + { "copy", + "edit-copy", + N_("_Copy"), + "c", + NULL, + copy_activated_cb, NULL, NULL, NULL }, + + { "paste", + "edit-paste", + N_("_Paste"), + "v", + NULL, + paste_activated_cb, NULL, NULL, NULL }, + + { "select-all", + "edit-select-all", + N_("_Select All"), + NULL, + NULL, + select_all_activated_cb, NULL, NULL, NULL }, + + { "find", + "edit-find", + N_("_Find in Message…"), + "f", + NULL, + find_activated_cb, NULL, NULL, NULL }, + + { "load-images", + "image-x-generic", + N_("_Load Images"), + "i", + NULL, + load_images_activated_cb, NULL, NULL, NULL }, + + { "all-headers", + NULL, + N_("All Message _Headers"), + NULL, + NULL, + activate_toggle_cb, NULL, "false", all_headers_change_state_cb }, + + { "msg-source", + NULL, + N_("Message _Source"), + "u", + NULL, + activate_toggle_cb, NULL, "false", msg_source_change_state_cb }, + + { "caret-mode", + NULL, + N_("_Caret Mode"), + "F7", + NULL, + activate_toggle_cb, NULL, "false", caret_mode_change_state_cb }, + + { "zoom-in", + "zoom-in", + N_("_Zoom In"), + "plus", + NULL, + zoom_in_activated_cb, NULL, NULL, NULL }, + + { "zoom-out", + "zoom-out", + N_("Zoom _Out"), + "minus", + NULL, + zoom_out_activated_cb, NULL, NULL, NULL }, + + { "zoom-zero", + "zoom-original", + N_("_Normal Size"), + "0", + NULL, + zoom_zero_activated_cb, NULL, NULL, NULL }, + + { "EMailViewer::charset-menu", + NULL, + N_("Ch_aracter Encoding"), + NULL, + NULL, + NULL, "s", "''", charset_change_state_cb }, + + { "edit-as-new", + NULL, + N_("_Edit as New Message"), + NULL, + NULL, + edit_as_new_activated_cb, NULL, NULL, NULL }, + + { "add-sender", + NULL, + N_("A_dd Sender to Address Book"), + NULL, + NULL, + add_sender_activated_cb, NULL, NULL, NULL }, + + { "goto-next", + "go-next", + N_("Go to _Next Message"), + "Page_Down", + NULL, + go_to_next_activated_cb, NULL, NULL, NULL }, + + { "goto-previous", + "go-previous", + N_("Go to _Previous Message"), + "Page_Up", + NULL, + go_to_previous_activated_cb, NULL, NULL, NULL }, + + { "reply-sender", + "mail-reply-sender", + N_("_Reply to Sender"), + "r", + NULL, + reply_sender_activated_cb, NULL, NULL, NULL }, + + { "reply-list", + NULL, + N_("Reply to _List"), + "l", + NULL, + reply_list_activated_cb, NULL, NULL, NULL }, + + { "reply-all", + "mail-reply-all", + N_("Reply to _All"), + "r", + NULL, + reply_all_activated_cb, NULL, NULL, NULL }, + + { "reply-alt", + NULL, + N_("Al_ternative Reply…"), + "r", + NULL, + reply_alt_activated_cb, NULL, NULL, NULL }, + + { "forward", + "mail-forward", + N_("_Forward"), + "f", + NULL, + forward_activated_cb, NULL, NULL, NULL }, + + { "forward-attached", + NULL, + N_("_Attached"), + NULL, + NULL, + forward_attached_activated_cb, NULL, NULL, NULL }, + + { "forward-inline", + NULL, + N_("_Inline"), + NULL, + NULL, + forward_inline_activated_cb, NULL, NULL, NULL }, + + { "forward-quoted", + NULL, + N_("_Quoted"), + NULL, + NULL, + forward_quoted_activated_cb, NULL, NULL, NULL }, + + { "redirect", + NULL, + N_("Re_direct"), + NULL, + NULL, + redirect_activated_cb, NULL, NULL, NULL }, + + /* menus */ + { "menu-file", NULL, N_("_File"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "menu-edit", NULL, N_("_Edit"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "menu-view", NULL, N_("_View"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "menu-zoom", NULL, N_("_Zoom"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "menu-charset", NULL, N_("Ch_aracter Encoding"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "menu-message", NULL, N_("_Message"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "menu-forward-as", NULL, N_("F_orward As"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EMailViewer::menu-button", NULL, N_("Menu"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + + EUIAction *action; + GError *local_error = NULL; + + g_return_if_fail (self->priv->ui_manager == NULL); + + self->priv->ui_manager = e_ui_manager_new (); + + g_signal_connect_object (self->priv->ui_manager, "create-item", + G_CALLBACK (e_mail_viewer_ui_manager_create_item_cb), self, 0); + g_signal_connect_object (self->priv->ui_manager, "ignore-accel", + G_CALLBACK (e_mail_viewer_ui_manager_ignore_accel_cb), self, 0); + + e_ui_manager_add_actions (self->priv->ui_manager, "mail-viewer", NULL, entries, G_N_ELEMENTS (entries), self); + + e_ui_action_set_visible (e_ui_manager_get_action (self->priv->ui_manager, "import-all"), FALSE); + + if (!e_ui_parser_merge_file (e_ui_manager_get_parser (self->priv->ui_manager), "evolution-mail-viewer.eui", &local_error)) + g_critical ("%s: Failed to merge .eui data: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error"); + + g_clear_error (&local_error); + + action = e_ui_manager_get_action (self->priv->ui_manager, "close"); + e_ui_action_add_secondary_accel (action, "Escape"); + + gtk_window_add_accel_group (GTK_WINDOW (self), e_ui_manager_get_accel_group (self->priv->ui_manager)); + e_ui_manager_set_action_groups_widget (self->priv->ui_manager, GTK_WIDGET (self)); } static void @@ -1895,9 +2029,8 @@ mail_viewer_dispose (GObject *object) } g_clear_object (&self->priv->e_menu_bar); - g_clear_object (&self->priv->action_map); - g_clear_object (&self->priv->accel_group); - g_clear_object (&self->priv->file_import); + g_clear_object (&self->priv->main_menu); + g_clear_object (&self->priv->ui_manager); /* Chain up to parent's method. */ G_OBJECT_CLASS (e_mail_viewer_parent_class)->dispose (object); @@ -1909,7 +2042,6 @@ mail_viewer_finalize (GObject *object) EMailViewer *self = E_MAIL_VIEWER (object); g_clear_object (&self->priv->backend); - g_clear_object (&self->priv->builder); g_clear_object (&self->priv->file); /* Chain up to parent's method. */ @@ -1922,11 +2054,10 @@ mail_viewer_constructed (GObject *object) EMailViewer *self = E_MAIL_VIEWER (object); EShell *shell; EAttachmentStore *attachment_store; - GObject *menu_object; + GObject *ui_item; GtkWidget *widget; GtkWidget *content_box; GtkWidget *mail_display; - GtkWidget *menu_button = NULL; GtkTreeView *tree_view; GtkTreeSelection *selection; GtkCellRenderer *renderer; @@ -1942,28 +2073,20 @@ mail_viewer_constructed (GObject *object) gtk_container_add (GTK_CONTAINER (self), content_box); gtk_widget_show (content_box); - self->priv->builder = gtk_builder_new (); - e_load_ui_builder_definition (self->priv->builder, "evolution-mail-viewer.ui"); + mail_viewer_init_ui_manager (self); widget = gtk_statusbar_new (); gtk_box_pack_end (GTK_BOX (content_box), widget, FALSE, FALSE, 0); gtk_widget_show (widget); self->priv->statusbar = widget; - menu_object = gtk_builder_get_object (self->priv->builder, "menu"); - widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (menu_object)); + ui_item = e_ui_manager_create_item (self->priv->ui_manager, "main-menu"); + widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (ui_item)); + self->priv->main_menu = E_UI_MENU (ui_item); + gtk_box_pack_start (GTK_BOX (content_box), widget, FALSE, FALSE, 0); gtk_widget_show (widget); - self->priv->real_menu_bar = GTK_MENU_BAR (widget); - self->priv->e_menu_bar = e_menu_bar_new (self->priv->real_menu_bar, GTK_WINDOW (self), &menu_button); - self->priv->has_menumultiple = FALSE; - - self->priv->file_import = g_menu_item_new (_("Import…"), "mail-viewer.import-all"); - menu_object = gtk_builder_get_object (self->priv->builder, "filesection"); - g_menu_insert_item (G_MENU (menu_object), 0, self->priv->file_import); - - menu_object = gtk_builder_get_object (self->priv->builder, "charset-submenu"); - e_charset_add_to_g_menu (G_MENU (menu_object), "mail-viewer.charset"); + self->priv->e_menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (self), &self->priv->menu_button); widget = e_alert_bar_new (); gtk_widget_set_margin_bottom (widget, 6); @@ -1976,20 +2099,9 @@ mail_viewer_constructed (GObject *object) self->priv->activity_bar = E_ACTIVITY_BAR (widget); if (e_util_get_use_header_bar ()) { - GtkHeaderBar *header_bar; - - widget = e_header_bar_new (); - header_bar = GTK_HEADER_BAR (widget); - - if (menu_button) - e_header_bar_pack_end (E_HEADER_BAR (header_bar), menu_button, G_MAXUINT); - + ui_item = e_ui_manager_create_item (self->priv->ui_manager, "main-headerbar"); + widget = GTK_WIDGET (ui_item); gtk_window_set_titlebar (GTK_WINDOW (self), widget); - gtk_widget_show (widget); - } else if (menu_button) { - g_object_ref_sink (menu_button); - gtk_widget_destroy (menu_button); - menu_button = NULL; } widget = e_web_view_preview_new (); @@ -2024,7 +2136,7 @@ mail_viewer_constructed (GObject *object) selection, "changed", G_CALLBACK (mail_viewer_selection_changed_cb), self); - mail_display = e_mail_display_new (e_mail_backend_get_remote_content (self->priv->backend)); + mail_display = e_mail_display_new (e_mail_backend_get_remote_content (self->priv->backend), NULL); g_signal_connect_swapped ( mail_display, "status-message", @@ -2063,15 +2175,12 @@ mail_viewer_constructed (GObject *object) self->priv->mail_display, "notify::has-selection", G_CALLBACK (mail_viewer_update_clipboard_actions), self, G_CONNECT_SWAPPED); - g_signal_connect ( - self, "key-press-event", - G_CALLBACK (mail_viewer_key_press_event_cb), NULL); - - mail_viewer_init_accel_group (self); mail_viewer_update_actions (self); mail_viewer_update_clipboard_actions (self); e_extensible_load_extensions (E_EXTENSIBLE (object)); + + gtk_window_add_accel_group (GTK_WINDOW (self), e_ui_manager_get_accel_group (e_web_view_get_ui_manager (E_WEB_VIEW (mail_display)))); } static void @@ -2114,8 +2223,6 @@ e_mail_viewer_init (EMailViewer *self) GTK_WINDOW (self), "/org/gnome/evolution/mail/viewer-window/", E_RESTORE_WINDOW_SIZE); - - mail_viewer_init_actions (self); } EMailViewer * @@ -2191,27 +2298,12 @@ mail_viewer_read_file_data_idle_cb (gpointer user_data) } } - if ((!needs_menumultiple) != (!self->priv->has_menumultiple)) { - GMenu *msgsubmenu, *filesection; - - self->priv->has_menumultiple = needs_menumultiple; - - msgsubmenu = G_MENU (gtk_builder_get_object (self->priv->builder, "msgsubmenu")); - - if (needs_menumultiple) { - GObject *goto_menu = gtk_builder_get_object (self->priv->builder, "goto-menu"); - - g_menu_item_set_label (self->priv->file_import, _("_Import All…")); - g_menu_insert_section (msgsubmenu, 1, NULL, G_MENU_MODEL (goto_menu)); - } else { - g_menu_item_set_label (self->priv->file_import, _("_Import…")); - g_menu_remove (msgsubmenu, 1); - } - - filesection = G_MENU (gtk_builder_get_object (self->priv->builder, "filesection")); - g_menu_remove (filesection, 0); - g_menu_insert_item (filesection, 0, self->priv->file_import); - } + e_ui_menu_freeze (self->priv->main_menu); + e_ui_action_set_visible (e_ui_manager_get_action (self->priv->ui_manager, "file-import"), !needs_menumultiple); + e_ui_action_set_visible (e_ui_manager_get_action (self->priv->ui_manager, "import-all"), needs_menumultiple); + e_ui_action_set_visible (e_ui_manager_get_action (self->priv->ui_manager, "goto-previous"), needs_menumultiple); + e_ui_action_set_visible (e_ui_manager_get_action (self->priv->ui_manager, "goto-next"), needs_menumultiple); + e_ui_menu_thaw (self->priv->main_menu); } g_clear_object (&self); diff --git a/src/mail/e-mail.h b/src/mail/e-mail.h index b579e88be9..38505f1c0a 100644 --- a/src/mail/e-mail.h +++ b/src/mail/e-mail.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/src/mail/em-composer-utils.c b/src/mail/em-composer-utils.c index 984025477f..50d3bb1e29 100644 --- a/src/mail/em-composer-utils.c +++ b/src/mail/em-composer-utils.c @@ -475,13 +475,13 @@ composer_presend_check_recipients (EMsgComposer *composer, "prompt-on-many-to-cc-recips", "mail:ask-many-to-cc-recips", head, msg, NULL)) { - GtkAction *action; + EUIAction *action; g_free (head); g_free (msg); action = E_COMPOSER_ACTION_VIEW_BCC (composer); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + e_ui_action_set_active (action, TRUE); goto finished; } @@ -2665,7 +2665,7 @@ static void emu_update_composers_security (EMsgComposer *composer, guint32 validity_found) { - GtkAction *action; + EUIAction *action; GSettings *settings; gboolean sign_reply; @@ -2681,34 +2681,34 @@ emu_update_composers_security (EMsgComposer *composer, action = NULL; if (validity_found & E_MAIL_PART_VALIDITY_SMIME) { - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_SIGN (composer))) && - !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_ENCRYPT (composer)))) + if (!e_ui_action_get_active (E_COMPOSER_ACTION_PGP_SIGN (composer)) && + !e_ui_action_get_active (E_COMPOSER_ACTION_PGP_ENCRYPT (composer))) action = E_COMPOSER_ACTION_SMIME_SIGN (composer); } else { - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_SIGN (composer))) && - !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_ENCRYPT (composer)))) + if (!e_ui_action_get_active (E_COMPOSER_ACTION_SMIME_SIGN (composer)) && + !e_ui_action_get_active (E_COMPOSER_ACTION_SMIME_ENCRYPT (composer))) action = E_COMPOSER_ACTION_PGP_SIGN (composer); } if (action) - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + e_ui_action_set_active (action, TRUE); } if (validity_found & E_MAIL_PART_VALIDITY_ENCRYPTED) { action = NULL; if (validity_found & E_MAIL_PART_VALIDITY_SMIME) { - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_SIGN (composer))) && - !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_ENCRYPT (composer)))) + if (!e_ui_action_get_active (E_COMPOSER_ACTION_PGP_SIGN (composer)) && + !e_ui_action_get_active (E_COMPOSER_ACTION_PGP_ENCRYPT (composer))) action = E_COMPOSER_ACTION_SMIME_ENCRYPT (composer); } else { - if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_SIGN (composer))) && - !gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_ENCRYPT (composer)))) + if (!e_ui_action_get_active (E_COMPOSER_ACTION_SMIME_SIGN (composer)) && + !e_ui_action_get_active (E_COMPOSER_ACTION_SMIME_ENCRYPT (composer))) action = E_COMPOSER_ACTION_PGP_ENCRYPT (composer); } if (action) - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + e_ui_action_set_active (action, TRUE); } } @@ -4422,6 +4422,24 @@ emcu_create_templates_combo (EShell *shell, return combo; } +static void +emcu_add_editor_mode_unknown (EActionComboBox *mode_combo) +{ + EUIAction *existing_action, *new_action; + GPtrArray *existing_radio_group; + + existing_action = e_action_combo_box_get_action (mode_combo); + existing_radio_group = e_ui_action_get_radio_group (existing_action); + + new_action = e_ui_action_new_stateful (e_ui_action_get_map_name (existing_action), + "unknown", G_VARIANT_TYPE_INT32, g_variant_new_int32 (E_CONTENT_EDITOR_MODE_UNKNOWN)); + e_ui_action_set_label (new_action, _("Use global setting")); + e_ui_action_set_radio_group (new_action, existing_radio_group); + e_ui_action_set_action_group (new_action, e_ui_action_get_action_group (existing_action)); + + g_object_unref (new_action); +} + /** * em_utils_reply_alternative: * @parent: (nullable): a parent #GtkWindow for the question dialog @@ -4462,7 +4480,6 @@ em_utils_reply_alternative (GtkWindow *parent, GtkLabel *sender_label, *list_label, *all_label; GtkRadioButton *style_default, *style_attach, *style_inline, *style_quote, *style_no_quote; EActionComboBox *mode_combo; - GtkRadioAction *radio_action, *html_mode_radio_action; GtkToggleButton *bottom_posting; GtkToggleButton *top_signature; GtkCheckButton *apply_template; @@ -4613,9 +4630,7 @@ em_utils_reply_alternative (GtkWindow *parent, widget, "sensitive", G_BINDING_SYNC_CREATE); - html_mode_radio_action = e_action_combo_box_get_action (mode_combo); - radio_action = gtk_radio_action_new ("unknown", _("Use global setting"), NULL, NULL, E_CONTENT_EDITOR_MODE_UNKNOWN); - gtk_radio_action_join_group (radio_action, html_mode_radio_action); + emcu_add_editor_mode_unknown (mode_combo); e_action_combo_box_update_model (mode_combo); /* One line gap between sections */ @@ -5504,7 +5519,7 @@ em_composer_utils_update_security (EMsgComposer *composer, g_return_if_fail (E_IS_MSG_COMPOSER (composer)); if (validity_pgp_sum != 0 || validity_smime_sum != 0) { - GtkToggleAction *action; + EUIAction *action; GSettings *settings; gboolean sign_reply; @@ -5514,25 +5529,25 @@ em_composer_utils_update_security (EMsgComposer *composer, if ((validity_pgp_sum & E_MAIL_PART_VALIDITY_PGP) != 0) { if (sign_reply && (validity_pgp_sum & E_MAIL_PART_VALIDITY_SIGNED) != 0) { - action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_SIGN (composer)); - gtk_toggle_action_set_active (action, TRUE); + action = E_COMPOSER_ACTION_PGP_SIGN (composer); + e_ui_action_set_active (action, TRUE); } if ((validity_pgp_sum & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0) { - action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_PGP_ENCRYPT (composer)); - gtk_toggle_action_set_active (action, TRUE); + action = E_COMPOSER_ACTION_PGP_ENCRYPT (composer); + e_ui_action_set_active (action, TRUE); } } if ((validity_smime_sum & E_MAIL_PART_VALIDITY_SMIME) != 0) { if (sign_reply && (validity_smime_sum & E_MAIL_PART_VALIDITY_SIGNED) != 0) { - action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_SIGN (composer)); - gtk_toggle_action_set_active (action, TRUE); + action = E_COMPOSER_ACTION_SMIME_SIGN (composer); + e_ui_action_set_active (action, TRUE); } if ((validity_smime_sum & E_MAIL_PART_VALIDITY_ENCRYPTED) != 0) { - action = GTK_TOGGLE_ACTION (E_COMPOSER_ACTION_SMIME_ENCRYPT (composer)); - gtk_toggle_action_set_active (action, TRUE); + action = E_COMPOSER_ACTION_SMIME_ENCRYPT (composer); + e_ui_action_set_active (action, TRUE); } } } diff --git a/src/mail/em-folder-selector.c b/src/mail/em-folder-selector.c index dc9b737544..a9965a6983 100644 --- a/src/mail/em-folder-selector.c +++ b/src/mail/em-folder-selector.c @@ -408,8 +408,8 @@ folder_selector_folder_created_cb (EMailFolderCreateDialog *dialog, static void folder_selector_action_add_cb (ETreeViewFrame *tree_view_frame, - GtkAction *action, - EMFolderSelector *selector) + EUIAction *action, + EMFolderSelector *selector) { GtkWidget *new_dialog; EMailSession *session; @@ -579,7 +579,7 @@ folder_selector_constructed (GObject *object) EMFolderSelector *selector; EMailSession *session; EMFolderTreeModel *model; - GtkAction *action; + EUIAction *action; GtkWidget *content_area; GtkWidget *container; GtkWidget *widget; @@ -707,12 +707,12 @@ folder_selector_constructed (GObject *object) action = e_tree_view_frame_lookup_toolbar_action ( E_TREE_VIEW_FRAME (selector->priv->tree_view_frame), E_TREE_VIEW_FRAME_ACTION_ADD); - gtk_action_set_tooltip (action, _("Create a new folder")); + e_ui_action_set_tooltip (action, _("Create a new folder")); action = e_tree_view_frame_lookup_toolbar_action ( E_TREE_VIEW_FRAME (selector->priv->tree_view_frame), E_TREE_VIEW_FRAME_ACTION_REMOVE); - gtk_action_set_visible (action, FALSE); + e_ui_action_set_visible (action, FALSE); } static void diff --git a/src/mail/mail-send-recv.c b/src/mail/mail-send-recv.c index a4cfd4129d..32ceff4983 100644 --- a/src/mail/mail-send-recv.c +++ b/src/mail/mail-send-recv.c @@ -34,6 +34,7 @@ #include "e-mail-account-store.h" #include "e-mail-reader-utils.h" #include "e-mail-ui-session.h" +#include "e-mail-view.h" #include "em-event.h" #include "em-filter-rule.h" #include "em-utils.h" @@ -504,10 +505,11 @@ mail_send_recv_send_fail_alert_response_cb (EAlert *alert, gpointer user_data) { EShellView *shell_view; - EShellContent *shell_content; EShellSidebar *shell_sidebar; EMFolderTree *folder_tree = NULL; EMailSession *session; + EMailReader *reader; + EMailView *mail_view = NULL; CamelFolder *outbox; GPtrArray *uids; @@ -518,19 +520,22 @@ mail_send_recv_send_fail_alert_response_cb (EAlert *alert, if (!shell_view) return; - shell_content = e_shell_view_get_shell_content (shell_view); + g_object_get (e_shell_view_get_shell_content (shell_view), "mail-view", &mail_view, NULL); + g_return_if_fail (mail_view != NULL); + shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); g_object_get (G_OBJECT (shell_sidebar), "folder-tree", &folder_tree, NULL); g_return_if_fail (folder_tree != NULL); + reader = E_MAIL_READER (mail_view); session = em_folder_tree_get_session (folder_tree); outbox = e_mail_session_get_local_folder (session, E_MAIL_LOCAL_FOLDER_OUTBOX); uids = g_object_get_data (G_OBJECT (alert), "message-uids"); if (uids && response_id == GTK_RESPONSE_APPLY) { - e_mail_reader_edit_messages (E_MAIL_READER (shell_content), outbox, uids, TRUE, TRUE); + e_mail_reader_edit_messages (reader, outbox, uids, TRUE, TRUE); } else if (folder_tree) { gchar *folder_uri; @@ -542,7 +547,7 @@ mail_send_recv_send_fail_alert_response_cb (EAlert *alert, em_folder_tree_set_selected (folder_tree, folder_uri, FALSE); - selected_folder = e_mail_reader_ref_folder (E_MAIL_READER (shell_content)); + selected_folder = e_mail_reader_ref_folder (reader); /* This makes sure the Outbox folder content is shown even when the On This Computer account is disabled */ @@ -553,7 +558,7 @@ mail_send_recv_send_fail_alert_response_cb (EAlert *alert, gtk_tree_selection_unselect_all (selection); em_folder_tree_set_selected (folder_tree, folder_uri, FALSE); - e_mail_reader_set_folder (E_MAIL_READER (shell_content), outbox); + e_mail_reader_set_folder (reader, outbox); } g_clear_object (&selected_folder); @@ -563,6 +568,7 @@ mail_send_recv_send_fail_alert_response_cb (EAlert *alert, } g_clear_object (&folder_tree); + g_clear_object (&mail_view); } struct ReportErrorToUIData @@ -598,7 +604,7 @@ report_error_to_ui_cb (gpointer user_data) data->error->message ? data->error->message : _("Unknown error"), NULL); if (data->send_failed_uids) { - GtkAction *action; + EUIAction *action; if (data->send_failed_uids->len == 1) { g_object_set_data_full (G_OBJECT (alert), "message-uids", @@ -607,12 +613,14 @@ report_error_to_ui_cb (gpointer user_data) } if (data->send_failed_uids->len == 1) { - action = gtk_action_new ("send-failed-edit-action", _("Edit Message"), NULL, NULL); + action = e_ui_action_new ("mail-send-recv-map", "send-failed-edit-action", NULL); + e_ui_action_set_label (action, _("Edit Message")); e_alert_add_action (alert, action, GTK_RESPONSE_APPLY, FALSE); g_object_unref (action); } - action = gtk_action_new ("send-failed-outbox-action", _("Open Outbox Folder"), NULL, NULL); + action = e_ui_action_new ("mail-send-recv-map", "send-failed-outbox-action", NULL); + e_ui_action_set_label (action, _("Open Outbox Folder")); e_alert_add_action (alert, action, GTK_RESPONSE_REJECT, FALSE); g_object_unref (action); diff --git a/src/mail/message-list.c b/src/mail/message-list.c index e86ad2819d..04e196f59e 100644 --- a/src/mail/message-list.c +++ b/src/mail/message-list.c @@ -3527,15 +3527,15 @@ message_list_selectable_update_actions (ESelectable *selectable, gint n_clipboard_targets) { ETreeTableAdapter *adapter; - GtkAction *action; + EUIAction *action; gint row_count; adapter = e_tree_get_table_adapter (E_TREE (selectable)); row_count = e_table_model_row_count (E_TABLE_MODEL (adapter)); action = e_focus_tracker_get_select_all_action (focus_tracker); - gtk_action_set_tooltip (action, _("Select all visible messages")); - gtk_action_set_sensitive (action, row_count > 0); + e_ui_action_set_tooltip (action, _("Select all visible messages")); + e_ui_action_set_sensitive (action, row_count > 0); } static void diff --git a/src/modules/addressbook/e-book-shell-backend.c b/src/modules/addressbook/e-book-shell-backend.c index a145740411..3eb4c818cf 100644 --- a/src/modules/addressbook/e-book-shell-backend.c +++ b/src/modules/addressbook/e-book-shell-backend.c @@ -154,9 +154,11 @@ exit: } static void -action_contact_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_contact_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; ESource *source = NULL; ESourceRegistry *registry; @@ -198,15 +200,17 @@ action_contact_new_cb (GtkAction *action, } /* Use a callback function appropriate for the action. */ - action_name = gtk_action_get_name (action); - if (strcmp (action_name, "contact-new") == 0) + action_name = g_action_get_name (G_ACTION (action)); + if (g_strcmp0 (action_name, "contact-new") == 0 || + g_strcmp0 (action_name, "new-menu-contact-new") == 0) e_client_cache_get_client ( client_cache, source, E_SOURCE_EXTENSION_ADDRESS_BOOK, (guint32) -1, NULL, book_shell_backend_new_contact_cb, g_object_ref (shell_window)); - if (strcmp (action_name, "contact-new-list") == 0) + if (g_strcmp0 (action_name, "contact-new-list") == 0 || + g_strcmp0 (action_name, "new-menu-contact-new-list") == 0) e_client_cache_get_client ( client_cache, source, E_SOURCE_EXTENSION_ADDRESS_BOOK, (guint32) -1, @@ -218,9 +222,11 @@ action_contact_new_cb (GtkAction *action, } static void -action_address_book_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_address_book_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; ESourceRegistry *registry; GtkWidget *config; @@ -244,7 +250,7 @@ action_address_book_new_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title (GTK_WINDOW (dialog), _("New Address Book")); @@ -252,33 +258,6 @@ action_address_book_new_cb (GtkAction *action, gtk_widget_show (dialog); } -static GtkActionEntry item_entries[] = { - - { "contact-new", - "contact-new", - NC_("New", "_Contact"), - "c", - N_("Create a new contact"), - G_CALLBACK (action_contact_new_cb) }, - - { "contact-new-list", - "stock_contact-list", - NC_("New", "Contact _List"), - "l", - N_("Create a new contact list"), - G_CALLBACK (action_contact_new_cb) } -}; - -static GtkActionEntry source_entries[] = { - - { "address-book-new", - "address-book-new", - NC_("New", "Address _Book"), - NULL, - N_("Create a new address book"), - G_CALLBACK (action_address_book_new_cb) } -}; - static gboolean book_shell_backend_init_preferences (EShell *shell) { @@ -566,6 +545,31 @@ static void book_shell_backend_window_added_cb (EShellBackend *shell_backend, GtkWindow *window) { + static const EUIActionEntry item_entries[] = { + { "new-menu-contact-new", + "contact-new", + NC_("New", "_Contact"), + "c", + N_("Create a new contact"), + action_contact_new_cb, NULL, NULL, NULL }, + + { "new-menu-contact-new-list", + "stock_contact-list", + NC_("New", "Contact _List"), + "l", + N_("Create a new contact list"), + action_contact_new_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry source_entries[] = { + { "new-menu-address-book-new", + "address-book-new", + NC_("New", "Address _Book"), + NULL, + N_("Create a new address book"), + action_address_book_new_cb, NULL, NULL, NULL } + }; + const gchar *backend_name; if (!E_IS_SHELL_WINDOW (window)) diff --git a/src/modules/addressbook/e-book-shell-content.c b/src/modules/addressbook/e-book-shell-content.c index d962df282e..fd57947d5a 100644 --- a/src/modules/addressbook/e-book-shell-content.c +++ b/src/modules/addressbook/e-book-shell-content.c @@ -565,7 +565,6 @@ e_book_shell_content_set_current_view (EBookShellContent *book_shell_content, EShellView *shell_view; EShellContent *shell_content; EShellSearchbar *searchbar; - EShellWindow *shell_window; EBookShellView *book_shell_view; GtkNotebook *notebook; GtkWidget *child; @@ -576,7 +575,6 @@ e_book_shell_content_set_current_view (EBookShellContent *book_shell_content, shell_content = E_SHELL_CONTENT (book_shell_content); shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); book_shell_view = E_BOOK_SHELL_VIEW (shell_view); searchbar = e_book_shell_content_get_searchbar (book_shell_content); @@ -593,8 +591,7 @@ e_book_shell_content_set_current_view (EBookShellContent *book_shell_content, GalViewInstance *view_instance; GalView *gl_view; EActionComboBox *combo_box; - GtkAction *action; - GtkRadioAction *radio_action; + EUIAction *action; gint filter_id = 0, search_id = 0; gchar *search_text = NULL; EFilterRule *advanced_search = NULL; @@ -608,8 +605,8 @@ e_book_shell_content_set_current_view (EBookShellContent *book_shell_content, combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); e_action_combo_box_set_current_value (combo_box, filter_id); - radio_action = e_shell_searchbar_get_search_option (searchbar); - gtk_radio_action_set_current_value (radio_action, search_id); + action = e_shell_searchbar_get_search_option (searchbar); + e_ui_action_set_state (action, g_variant_new_int32 (search_id)); e_shell_searchbar_set_search_text (searchbar, search_text); @@ -626,11 +623,11 @@ e_book_shell_content_set_current_view (EBookShellContent *book_shell_content, gl_view = gal_view_instance_get_current_view (view_instance); action = ACTION (CONTACT_CARDS_SORT_BY_MENU); - gtk_action_set_visible (action, GAL_IS_VIEW_MINICARD (gl_view)); + e_ui_action_set_visible (action, GAL_IS_VIEW_MINICARD (gl_view)); if (GAL_IS_VIEW_MINICARD (gl_view)) { action = ACTION (CONTACT_CARDS_SORT_BY_FILE_AS); - gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), gal_view_minicard_get_sort_by (GAL_VIEW_MINICARD (gl_view))); + e_ui_action_set_state (action, g_variant_new_int32 (gal_view_minicard_get_sort_by (GAL_VIEW_MINICARD (gl_view)))); } } diff --git a/src/modules/addressbook/e-book-shell-view-actions.c b/src/modules/addressbook/e-book-shell-view-actions.c index 6540136ebb..7ae793a43e 100644 --- a/src/modules/addressbook/e-book-shell-view-actions.c +++ b/src/modules/addressbook/e-book-shell-view-actions.c @@ -27,9 +27,11 @@ #include static void -action_address_book_copy_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -41,9 +43,11 @@ action_address_book_copy_cb (GtkAction *action, } static void -action_address_book_delete_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; EBookShellSidebar *book_shell_sidebar; @@ -83,9 +87,11 @@ action_address_book_delete_cb (GtkAction *action, } static void -action_address_book_manage_groups_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_manage_groups_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShellView *shell_view; ESourceSelector *selector; @@ -98,9 +104,11 @@ action_address_book_manage_groups_cb (GtkAction *action, } static void -action_address_book_move_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_move_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -112,9 +120,11 @@ action_address_book_move_cb (GtkAction *action, } static void -action_address_book_new_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ESourceRegistry *registry; @@ -135,7 +145,7 @@ action_address_book_new_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title (GTK_WINDOW (dialog), _("New Address Book")); @@ -144,9 +154,11 @@ action_address_book_new_cb (GtkAction *action, } static void -action_address_book_print_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; GtkPrintOperationAction print_action; @@ -160,9 +172,11 @@ action_address_book_print_cb (GtkAction *action, } static void -action_address_book_print_preview_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_print_preview_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; GtkPrintOperationAction print_action; @@ -176,9 +190,11 @@ action_address_book_print_preview_cb (GtkAction *action, } static void -action_address_book_properties_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_properties_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; EBookShellSidebar *book_shell_sidebar; @@ -207,7 +223,7 @@ action_address_book_properties_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title ( @@ -257,9 +273,11 @@ address_book_refresh_done_cb (GObject *source_object, } static void -action_address_book_refresh_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_refresh_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellSidebar *book_shell_sidebar; ESourceSelector *selector; EClient *client = NULL; @@ -354,9 +372,11 @@ book_shell_view_refresh_backend_done_cb (GObject *source_object, } static void -action_address_book_refresh_backend_cb (GtkAction *action, - EShellView *shell_view) +action_address_book_refresh_backend_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; EShellBackend *shell_backend; EShellContent *shell_content; EShell *shell; @@ -488,10 +508,12 @@ map_window_show_contact_editor_cb (EContactMapWindow *window, /* We need this function to he defined all the time. */ static void -action_address_book_map_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_map_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { #ifdef ENABLE_CONTACT_MAPS + EBookShellView *book_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellBackend *shell_backend; @@ -551,9 +573,11 @@ action_address_book_map_cb (GtkAction *action, } static void -action_address_book_rename_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_rename_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellSidebar *book_shell_sidebar; ESourceSelector *selector; @@ -564,9 +588,11 @@ action_address_book_rename_cb (GtkAction *action, } static void -action_address_book_save_as_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -643,9 +669,11 @@ exit: } static void -action_address_book_stop_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_address_book_stop_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -744,9 +772,11 @@ action_contact_bulk_edit_got_selected_cb (GObject *source_object, } static void -action_contact_bulk_edit_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_bulk_edit_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShellView *shell_view; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -776,9 +806,11 @@ action_contact_bulk_edit_cb (GtkAction *action, } static void -action_contact_copy_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -790,9 +822,11 @@ action_contact_copy_cb (GtkAction *action, } static void -action_contact_delete_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -804,9 +838,11 @@ action_contact_delete_cb (GtkAction *action, } static void -action_contact_find_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_find_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EPreviewPane *preview_pane; @@ -868,9 +904,11 @@ action_contact_forward_got_selected_cb (GObject *source_object, } static void -action_contact_forward_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -904,9 +942,11 @@ action_contact_forward_cb (GtkAction *action, } static void -action_contact_move_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_move_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -918,9 +958,11 @@ action_contact_move_cb (GtkAction *action, } static void -action_contact_new_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -949,9 +991,11 @@ action_contact_new_cb (GtkAction *action, } static void -action_contact_new_list_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_new_list_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShellView *shell_view; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -970,9 +1014,11 @@ action_contact_new_list_cb (GtkAction *action, } static void -action_contact_open_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; @@ -984,33 +1030,27 @@ action_contact_open_cb (GtkAction *action, } static void -action_contact_preview_cb (GtkToggleAction *action, - EBookShellView *book_shell_view) -{ - EBookShellContent *book_shell_content; - gboolean visible; - - book_shell_content = book_shell_view->priv->book_shell_content; - visible = gtk_toggle_action_get_active (action); - e_book_shell_content_set_preview_visible (book_shell_content, visible); -} - -static void -action_contact_preview_show_maps_cb (GtkToggleAction *action, - EBookShellView *book_shell_view) +action_contact_preview_show_maps_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; gboolean show_maps; + e_ui_action_set_state (action, parameter); + book_shell_content = book_shell_view->priv->book_shell_content; - show_maps = gtk_toggle_action_get_active (action); + show_maps = e_ui_action_get_active (action); e_book_shell_content_set_preview_show_maps (book_shell_content, show_maps); } static void -action_contact_print_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EBookShellContent *book_shell_content; EAddressbookView *view; GtkPrintOperationAction print_action; @@ -1101,9 +1141,11 @@ action_contact_save_as_got_selected_cb (GObject *source_object, } static void -action_contact_save_as_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -1192,9 +1234,11 @@ action_contact_send_message_got_selected_cb (GObject *source_object, } static void -action_contact_send_message_cb (GtkAction *action, - EBookShellView *book_shell_view) +action_contact_send_message_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *book_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -1228,558 +1272,409 @@ action_contact_send_message_cb (GtkAction *action, } static void -action_contact_view_cb (GtkRadioAction *action, - GtkRadioAction *current, - EBookShellView *book_shell_view) -{ - EBookShellContent *book_shell_content; - GtkOrientable *orientable; - GtkOrientation orientation; - - book_shell_content = book_shell_view->priv->book_shell_content; - orientable = GTK_ORIENTABLE (book_shell_content); - - switch (gtk_radio_action_get_current_value (action)) { - case 0: - orientation = GTK_ORIENTATION_VERTICAL; - break; - case 1: - orientation = GTK_ORIENTATION_HORIZONTAL; - break; - default: - g_return_if_reached (); - } - - gtk_orientable_set_orientation (orientable, orientation); -} - -static void -action_contact_cards_sort_by_cb (GtkRadioAction *action, - GtkRadioAction *current, - EBookShellView *book_shell_view) +action_contact_cards_sort_by_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EBookShellView *self = user_data; GalViewInstance *view_instance; GalView *gl_view; EAddressbookView *addr_view; - addr_view = e_book_shell_content_get_current_view (book_shell_view->priv->book_shell_content); + e_ui_action_set_state (action, parameter); + + addr_view = e_book_shell_content_get_current_view (self->priv->book_shell_content); view_instance = e_addressbook_view_get_view_instance (addr_view); gl_view = gal_view_instance_get_current_view (view_instance); if (GAL_IS_VIEW_MINICARD (gl_view)) - gal_view_minicard_set_sort_by (GAL_VIEW_MINICARD (gl_view), gtk_radio_action_get_current_value (action)); + gal_view_minicard_set_sort_by (GAL_VIEW_MINICARD (gl_view), g_variant_get_int32 (parameter)); else g_warn_if_reached (); } -static GtkActionEntry contact_entries[] = { - - { "address-book-copy", - "edit-copy", - N_("Co_py All Contacts To…"), - NULL, - N_("Copy the contacts of the selected address book to another"), - G_CALLBACK (action_address_book_copy_cb) }, - - { "address-book-delete", - "edit-delete", - N_("D_elete Address Book"), - NULL, - N_("Delete the selected address book"), - G_CALLBACK (action_address_book_delete_cb) }, - - { "address-book-manage-groups", - NULL, - N_("_Manage Address Book groups…"), - NULL, - N_("Manage task list groups order and visibility"), - G_CALLBACK (action_address_book_manage_groups_cb) }, - - { "address-book-move", - "folder-move", - N_("Mo_ve All Contacts To…"), - NULL, - N_("Move the contacts of the selected address book to another"), - G_CALLBACK (action_address_book_move_cb) }, - - { "address-book-new", - "address-book-new", - N_("_New Address Book"), - NULL, - N_("Create a new address book"), - G_CALLBACK (action_address_book_new_cb) }, - - { "address-book-properties", - "document-properties", - N_("Address _Book Properties"), - NULL, - N_("Show properties of the selected address book"), - G_CALLBACK (action_address_book_properties_cb) }, - - { "address-book-refresh", - "view-refresh", - N_("Re_fresh"), - NULL, - N_("Refresh the selected address book"), - G_CALLBACK (action_address_book_refresh_cb) }, - - { "address-book-refresh-backend", - "view-refresh", - N_("Re_fresh list of account address books"), - NULL, - NULL, - G_CALLBACK (action_address_book_refresh_backend_cb) }, - - { "address-book-map", - NULL, - N_("Address Book _Map"), - NULL, - N_("Show map with all contacts from selected address book"), - G_CALLBACK (action_address_book_map_cb) }, - - { "address-book-rename", - NULL, - N_("_Rename…"), - "F2", - N_("Rename the selected address book"), - G_CALLBACK (action_address_book_rename_cb) }, - - { "address-book-stop", - "process-stop", - N_("_Stop"), - NULL, - N_("Stop loading"), - G_CALLBACK (action_address_book_stop_cb) }, - - { "contact-bulk-edit", - NULL, - N_("_Bulk Edit…"), - "b", - N_("Edit selected contacts in a bulk"), - G_CALLBACK (action_contact_bulk_edit_cb) }, - - { "contact-copy", - NULL, - N_("_Copy Contact To…"), - "y", - N_("Copy selected contacts to another address book"), - G_CALLBACK (action_contact_copy_cb) }, - - { "contact-delete", - "edit-delete", - N_("_Delete Contact"), - "d", - N_("Delete selected contacts"), - G_CALLBACK (action_contact_delete_cb) }, - - { "contact-find", - "edit-find", - N_("_Find in Contact…"), - "f", - N_("Search for text in the displayed contact"), - G_CALLBACK (action_contact_find_cb) }, - - { "contact-forward", - "mail-forward", - N_("_Forward Contact…"), - NULL, - N_("Send selected contacts to another person"), - G_CALLBACK (action_contact_forward_cb) }, - - { "contact-move", - NULL, - N_("_Move Contact To…"), - "v", - N_("Move selected contacts to another address book"), - G_CALLBACK (action_contact_move_cb) }, - - { "contact-new", - "contact-new", - N_("_New Contact…"), - NULL, - N_("Create a new contact"), - G_CALLBACK (action_contact_new_cb) }, - - { "contact-new-list", - "stock_contact-list", - N_("New Contact _List…"), - NULL, - N_("Create a new contact list"), - G_CALLBACK (action_contact_new_list_cb) }, - - { "contact-open", - NULL, - N_("_Open Contact"), - "o", - N_("View the current contact"), - G_CALLBACK (action_contact_open_cb) }, - - { "contact-send-message", - "mail-message-new", - N_("_Send Message to Contact…"), - NULL, - N_("Send a message to the selected contacts"), - G_CALLBACK (action_contact_send_message_cb) }, - - /*** Menus ***/ - - { "contact-actions-menu", - NULL, - N_("_Actions"), - NULL, - NULL, - NULL }, - - { "contact-preview-menu", - NULL, - N_("_Preview"), - NULL, - NULL, - NULL }, - - { "contact-cards-sort-by-menu", - NULL, - N_("_Sort Cards By"), - NULL, - NULL, - NULL }, -}; - -static EPopupActionEntry contact_popup_entries[] = { - - { "address-book-popup-delete", - N_("_Delete"), - "address-book-delete" }, - - { "address-book-popup-manage-groups", - N_("_Manage groups…"), - "address-book-manage-groups" }, - - { "address-book-popup-properties", - N_("_Properties"), - "address-book-properties" }, - - { "address-book-popup-refresh", - NULL, - "address-book-refresh" }, - - { "address-book-popup-refresh-backend", - NULL, - "address-book-refresh-backend" }, - - { "address-book-popup-map", - N_("Address Book Map"), - "address-book-map" }, - - { "address-book-popup-rename", - NULL, - "address-book-rename" }, - - { "contact-popup-copy", - NULL, - "contact-copy" }, - - { "contact-popup-forward", - NULL, - "contact-forward" }, - - { "contact-popup-move", - NULL, - "contact-move" }, - - { "contact-popup-open", - NULL, - "contact-open" }, - - { "contact-popup-send-message", - NULL, - "contact-send-message" }, -}; - -static GtkToggleActionEntry contact_toggle_entries[] = { - - { "contact-preview", - NULL, - N_("Contact _Preview"), - "m", - N_("Show contact preview window"), - G_CALLBACK (action_contact_preview_cb), - TRUE }, - - { "contact-preview-show-maps", - NULL, - N_("Show _Maps"), - NULL, - N_("Show maps in contact preview window"), - G_CALLBACK (action_contact_preview_show_maps_cb), - FALSE } -}; - -static GtkRadioActionEntry contact_view_entries[] = { - - /* This action represents the initial active contact view. - * It should not be visible in the UI, nor should it be - * possible to switch to it from another shell view. */ - { "contact-view-initial", - NULL, - NULL, - NULL, - NULL, - -1 }, - - { "contact-view-classic", - NULL, - N_("_Classic View"), - NULL, - N_("Show contact preview below the contact list"), - 0 }, - - { "contact-view-vertical", - NULL, - N_("_Vertical View"), - NULL, - N_("Show contact preview alongside the contact list"), - 1 } -}; - -static GtkRadioActionEntry contact_filter_entries[] = { - - { "contact-filter-any-category", - NULL, - N_("Any Category"), - NULL, - NULL, - CONTACT_FILTER_ANY_CATEGORY }, - - { "contact-filter-unmatched", - NULL, - N_("Unmatched"), - NULL, - NULL, - CONTACT_FILTER_UNMATCHED } -}; - -static GtkRadioActionEntry contact_search_entries[] = { - - { "contact-search-advanced-hidden", - NULL, - N_("Advanced Search"), - NULL, - NULL, - CONTACT_SEARCH_ADVANCED }, - - { "contact-search-any-field-contains", - NULL, - N_("Any field contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - CONTACT_SEARCH_ANY_FIELD_CONTAINS }, - - { "contact-search-email-begins-with", - NULL, - N_("Email begins with"), - NULL, - NULL, /* XXX Add a tooltip! */ - CONTACT_SEARCH_EMAIL_BEGINS_WITH }, - - { "contact-search-email-contains", - NULL, - N_("Email contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - CONTACT_SEARCH_EMAIL_CONTAINS }, - - { "contact-search-phone-contains", - NULL, - N_("Phone contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - CONTACT_SEARCH_PHONE_CONTAINS }, - - { "contact-search-name-contains", - NULL, - N_("Name contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - CONTACT_SEARCH_NAME_CONTAINS } -}; - -static GtkRadioActionEntry contact_cards_sort_by_entries[] = { - - { "contact-cards-sort-by-file-as", - NULL, - N_("_File Under"), - NULL, - NULL, - E_CARDS_SORT_BY_FILE_AS }, - - { "contact-cards-sort-by-given-name", - NULL, - N_("_Given Name"), - NULL, - NULL, - E_CARDS_SORT_BY_GIVEN_NAME }, - - { "contact-cards-sort-by-family-name", - NULL, - N_("Family _Name"), - NULL, - NULL, - E_CARDS_SORT_BY_FAMILY_NAME }, -}; - -static GtkActionEntry lockdown_printing_entries[] = { - - { "address-book-print", - "document-print", - N_("_Print…"), - "p", - N_("Print all shown contacts"), - G_CALLBACK (action_address_book_print_cb) }, - - { "address-book-print-preview", - "document-print-preview", - N_("Pre_view…"), - NULL, - N_("Preview the contacts to be printed"), - G_CALLBACK (action_address_book_print_preview_cb) }, - - { "contact-print", - "document-print", - N_("_Print…"), - NULL, - N_("Print selected contacts"), - G_CALLBACK (action_contact_print_cb) } -}; - -static EPopupActionEntry lockdown_printing_popup_entries[] = { - - { "contact-popup-print", - NULL, - "contact-print" } -}; - -static GtkActionEntry lockdown_save_to_disk_entries[] = { - - { "address-book-save-as", - "document-save-as", - N_("S_ave Address Book as vCard"), - NULL, - N_("Save the contacts of the selected address book as a vCard"), - G_CALLBACK (action_address_book_save_as_cb) }, - - { "contact-save-as", - "document-save-as", - /* Translators: This is an action label */ - N_("_Save as vCard…"), - NULL, - N_("Save selected contacts as a vCard"), - G_CALLBACK (action_contact_save_as_cb) } -}; - -static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = { - - { "address-book-popup-save-as", - /* Translators: This is an action label */ - N_("_Save as vCard…"), - "address-book-save-as" }, - - { "contact-popup-save-as", - NULL, - "contact-save-as" } -}; - void -e_book_shell_view_actions_init (EBookShellView *book_shell_view) +e_book_shell_view_actions_init (EBookShellView *self) { - EBookShellContent *book_shell_content; + static const EUIActionEntry contact_entries[] = { + + { "address-book-copy", + "edit-copy", + N_("Co_py All Contacts To…"), + NULL, + N_("Copy the contacts of the selected address book to another"), + action_address_book_copy_cb, NULL, NULL, NULL }, + + { "address-book-delete", + "edit-delete", + N_("D_elete Address Book"), + NULL, + N_("Delete the selected address book"), + action_address_book_delete_cb, NULL, NULL, NULL }, + + { "address-book-delete-popup", + "edit-delete", + N_("_Delete"), + NULL, + N_("Delete the selected address book"), + action_address_book_delete_cb, NULL, NULL, NULL }, + + { "address-book-manage-groups", + NULL, + N_("_Manage Address Book groups…"), + NULL, + N_("Manage addres book groups order and visibility"), + action_address_book_manage_groups_cb, NULL, NULL, NULL }, + + { "address-book-manage-groups-popup", + NULL, + N_("_Manage groups…"), + NULL, + N_("Manage addres book groups order and visibility"), + action_address_book_manage_groups_cb, NULL, NULL, NULL }, + + { "address-book-move", + "folder-move", + N_("Mo_ve All Contacts To…"), + NULL, + N_("Move the contacts of the selected address book to another"), + action_address_book_move_cb, NULL, NULL, NULL }, + + { "address-book-new", + "address-book-new", + N_("_New Address Book"), + NULL, + N_("Create a new address book"), + action_address_book_new_cb, NULL, NULL, NULL }, + + { "address-book-properties", + "document-properties", + N_("Address _Book Properties"), + NULL, + N_("Show properties of the selected address book"), + action_address_book_properties_cb, NULL, NULL, NULL }, + + { "address-book-properties-popup", + "document-properties", + N_("_Properties"), + NULL, + N_("Show properties of the selected address book"), + action_address_book_properties_cb, NULL, NULL, NULL }, + + { "address-book-refresh", + "view-refresh", + N_("Re_fresh"), + NULL, + N_("Refresh the selected address book"), + action_address_book_refresh_cb, NULL, NULL, NULL }, + + { "address-book-refresh-backend", + "view-refresh", + N_("Re_fresh list of account address books"), + NULL, + NULL, + action_address_book_refresh_backend_cb, NULL, NULL, NULL }, + + { "address-book-map", + NULL, + N_("Address Book _Map"), + NULL, + N_("Show map with all contacts from selected address book"), + action_address_book_map_cb, NULL, NULL, NULL }, + + { "address-book-map-popup", + NULL, + N_("Address Book Map"), + NULL, + N_("Show map with all contacts from selected address book"), + action_address_book_map_cb, NULL, NULL, NULL }, + + { "address-book-rename", + NULL, + N_("_Rename…"), + NULL, + N_("Rename the selected address book"), + action_address_book_rename_cb, NULL, NULL, NULL }, + + { "address-book-stop", + "process-stop", + N_("_Stop"), + NULL, + N_("Stop loading"), + action_address_book_stop_cb, NULL, NULL, NULL }, + + { "contact-bulk-edit", + NULL, + N_("_Bulk Edit…"), + "b", + N_("Edit selected contacts in a bulk"), + action_contact_bulk_edit_cb, NULL, NULL, NULL }, + + { "contact-copy", + NULL, + N_("_Copy Contact To…"), + "y", + N_("Copy selected contacts to another address book"), + action_contact_copy_cb, NULL, NULL, NULL }, + + { "contact-delete", + "edit-delete", + N_("_Delete Contact"), + "d", + N_("Delete selected contacts"), + action_contact_delete_cb, NULL, NULL, NULL }, + + { "contact-find", + "edit-find", + N_("_Find in Contact…"), + "f", + N_("Search for text in the displayed contact"), + action_contact_find_cb, NULL, NULL, NULL }, + + { "contact-forward", + "mail-forward", + N_("_Forward Contact…"), + NULL, + N_("Send selected contacts to another person"), + action_contact_forward_cb, NULL, NULL, NULL }, + + { "contact-move", + NULL, + N_("_Move Contact To…"), + "v", + N_("Move selected contacts to another address book"), + action_contact_move_cb, NULL, NULL, NULL }, + + { "contact-new", + "contact-new", + N_("_New Contact…"), + NULL, + N_("Create a new contact"), + action_contact_new_cb, NULL, NULL, NULL }, + + { "contact-new-list", + "stock_contact-list", + N_("New Contact _List…"), + NULL, + N_("Create a new contact list"), + action_contact_new_list_cb, NULL, NULL, NULL }, + + { "contact-open", + NULL, + N_("_Open Contact"), + "o", + N_("View the current contact"), + action_contact_open_cb, NULL, NULL, NULL }, + + { "contact-send-message", + "mail-message-new", + N_("_Send Message to Contact…"), + NULL, + N_("Send a message to the selected contacts"), + action_contact_send_message_cb, NULL, NULL, NULL }, + + /*** Menus ***/ + + { "contact-actions-menu", + NULL, + N_("_Actions"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, + + { "contact-preview-menu", + NULL, + N_("_Preview"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, + + { "contact-cards-sort-by-menu", + NULL, + N_("_Sort Cards By"), + NULL, + NULL, + NULL, NULL, NULL, NULL } + }; + + static const EUIActionEntry contact_toggle_entries[] = { + + { "contact-preview", + NULL, + N_("Contact _Preview"), + "m", + N_("Show contact preview window"), + NULL, NULL, "true", NULL }, + + { "contact-preview-show-maps", + NULL, + N_("Show _Maps"), + NULL, + N_("Show maps in contact preview window"), + NULL, NULL, "false", action_contact_preview_show_maps_cb } + }; + + static const EUIActionEnumEntry contact_view_entries[] = { + + { "contact-view-classic", + NULL, + N_("_Classic View"), + NULL, + N_("Show contact preview below the contact list"), + NULL, 0 }, + + { "contact-view-vertical", + NULL, + N_("_Vertical View"), + NULL, + N_("Show contact preview alongside the contact list"), + NULL, 1 } + }; + + static const EUIActionEnumEntry contact_search_entries[] = { + + { "contact-search-advanced-hidden", + NULL, + N_("Advanced Search"), + NULL, + NULL, + NULL, CONTACT_SEARCH_ADVANCED }, + + { "contact-search-any-field-contains", + NULL, + N_("Any field contains"), + NULL, + NULL, + NULL, CONTACT_SEARCH_ANY_FIELD_CONTAINS }, + + { "contact-search-email-begins-with", + NULL, + N_("Email begins with"), + NULL, + NULL, + NULL, CONTACT_SEARCH_EMAIL_BEGINS_WITH }, + + { "contact-search-email-contains", + NULL, + N_("Email contains"), + NULL, + NULL, + NULL, CONTACT_SEARCH_EMAIL_CONTAINS }, + + { "contact-search-phone-contains", + NULL, + N_("Phone contains"), + NULL, + NULL, + NULL, CONTACT_SEARCH_PHONE_CONTAINS }, + + { "contact-search-name-contains", + NULL, + N_("Name contains"), + NULL, + NULL, + NULL, CONTACT_SEARCH_NAME_CONTAINS } + }; + + static const EUIActionEnumEntry contact_cards_sort_by_entries[] = { + + { "contact-cards-sort-by-file-as", + NULL, + N_("_File Under"), + NULL, + NULL, + action_contact_cards_sort_by_cb, E_CARDS_SORT_BY_FILE_AS }, + + { "contact-cards-sort-by-given-name", + NULL, + N_("_Given Name"), + NULL, + NULL, + action_contact_cards_sort_by_cb, E_CARDS_SORT_BY_GIVEN_NAME }, + + { "contact-cards-sort-by-family-name", + NULL, + N_("Family _Name"), + NULL, + NULL, + action_contact_cards_sort_by_cb, E_CARDS_SORT_BY_FAMILY_NAME }, + }; + + static const EUIActionEntry lockdown_printing_entries[] = { + + { "address-book-print", + "document-print", + N_("_Print…"), + "p", + N_("Print all shown contacts"), + action_address_book_print_cb, NULL, NULL, NULL }, + + { "address-book-print-preview", + "document-print-preview", + N_("Pre_view…"), + NULL, + N_("Preview the contacts to be printed"), + action_address_book_print_preview_cb, NULL, NULL, NULL }, + + { "contact-print", + "document-print", + N_("_Print…"), + NULL, + N_("Print selected contacts"), + action_contact_print_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry lockdown_save_to_disk_entries[] = { + + { "address-book-save-as", + "document-save-as", + N_("S_ave Address Book as vCard"), + NULL, + N_("Save the contacts of the selected address book as a vCard"), + action_address_book_save_as_cb, NULL, NULL, NULL }, + + { "address-book-save-as-popup", + "document-save-as", + /* Translators: This is an action label */ + N_("_Save as vCard…"), + NULL, + N_("Save the contacts of the selected address book as a vCard"), + action_address_book_save_as_cb, NULL, NULL, NULL }, + + { "contact-save-as", + "document-save-as", + /* Translators: This is an action label */ + N_("_Save as vCard…"), + NULL, + N_("Save selected contacts as a vCard"), + action_contact_save_as_cb, NULL, NULL, NULL } + }; + EShellView *shell_view; - EShellWindow *shell_window; - EShellSearchbar *searchbar; - EPreviewPane *preview_pane; - EWebView *web_view; - GtkActionGroup *action_group; - GSettings *settings; - GtkAction *action; + EUIManager *ui_manager; - shell_view = E_SHELL_VIEW (book_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - - book_shell_content = book_shell_view->priv->book_shell_content; - searchbar = e_book_shell_content_get_searchbar (book_shell_content); - preview_pane = e_book_shell_content_get_preview_pane (book_shell_content); - web_view = e_preview_pane_get_web_view (preview_pane); + shell_view = E_SHELL_VIEW (self); + ui_manager = e_shell_view_get_ui_manager (shell_view); /* Contact Actions */ - action_group = ACTION_GROUP (CONTACTS); - gtk_action_group_add_actions ( - action_group, contact_entries, - G_N_ELEMENTS (contact_entries), book_shell_view); - e_action_group_add_popup_actions ( - action_group, contact_popup_entries, - G_N_ELEMENTS (contact_popup_entries)); - gtk_action_group_add_toggle_actions ( - action_group, contact_toggle_entries, - G_N_ELEMENTS (contact_toggle_entries), book_shell_view); - gtk_action_group_add_radio_actions ( - action_group, contact_view_entries, - G_N_ELEMENTS (contact_view_entries), -1, - G_CALLBACK (action_contact_view_cb), book_shell_view); - gtk_action_group_add_radio_actions ( - action_group, contact_search_entries, - G_N_ELEMENTS (contact_search_entries), - -1, NULL, NULL); - gtk_action_group_add_radio_actions ( - action_group, contact_cards_sort_by_entries, - G_N_ELEMENTS (contact_cards_sort_by_entries), -1, - G_CALLBACK (action_contact_cards_sort_by_cb), book_shell_view); - - /* Advanced Search Action */ - action = ACTION (CONTACT_SEARCH_ADVANCED_HIDDEN); - gtk_action_set_visible (action, FALSE); - e_shell_searchbar_set_search_option ( - searchbar, GTK_RADIO_ACTION (action)); + e_ui_manager_add_actions (ui_manager, "contacts", NULL, + contact_entries, G_N_ELEMENTS (contact_entries), self); + e_ui_manager_add_actions (ui_manager, "contacts", NULL, + contact_toggle_entries, G_N_ELEMENTS (contact_toggle_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "contacts", NULL, + contact_view_entries, G_N_ELEMENTS (contact_view_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "contacts", NULL, + contact_search_entries, G_N_ELEMENTS (contact_search_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "contacts", NULL, + contact_cards_sort_by_entries, G_N_ELEMENTS (contact_cards_sort_by_entries), self); /* Lockdown Printing Actions */ - action_group = ACTION_GROUP (LOCKDOWN_PRINTING); - gtk_action_group_add_actions ( - action_group, lockdown_printing_entries, - G_N_ELEMENTS (lockdown_printing_entries), - book_shell_view); - e_action_group_add_popup_actions ( - action_group, lockdown_printing_popup_entries, - G_N_ELEMENTS (lockdown_printing_popup_entries)); + e_ui_manager_add_actions (ui_manager, "lockdown-printing", NULL, + lockdown_printing_entries, G_N_ELEMENTS (lockdown_printing_entries), self); /* Lockdown Save-to-Disk Actions */ - action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK); - gtk_action_group_add_actions ( - action_group, lockdown_save_to_disk_entries, - G_N_ELEMENTS (lockdown_save_to_disk_entries), - book_shell_view); - e_action_group_add_popup_actions ( - action_group, lockdown_save_to_disk_popup_entries, - G_N_ELEMENTS (lockdown_save_to_disk_popup_entries)); - - /* Bind GObject properties to GSettings keys. */ - - settings = e_util_ref_settings ("org.gnome.evolution.addressbook"); - - g_settings_bind ( - settings, "show-preview", - ACTION (CONTACT_PREVIEW), "active", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "layout", - ACTION (CONTACT_VIEW_VERTICAL), "current-value", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "preview-show-maps", - ACTION (CONTACT_PREVIEW_SHOW_MAPS), "active", - G_SETTINGS_BIND_DEFAULT); - - g_object_unref (settings); + e_ui_manager_add_actions (ui_manager, "lockdown-save-to-disk", NULL, + lockdown_save_to_disk_entries, G_N_ELEMENTS (lockdown_save_to_disk_entries), self); /* Fine tuning. */ @@ -1798,54 +1693,65 @@ e_book_shell_view_actions_init (EBookShellView *book_shell_view) ACTION (CONTACT_PREVIEW_SHOW_MAPS), "sensitive", G_BINDING_SYNC_CREATE); - e_web_view_set_open_proxy (web_view, ACTION (CONTACT_OPEN)); - e_web_view_set_print_proxy (web_view, ACTION (CONTACT_PRINT)); - e_web_view_set_save_as_proxy (web_view, ACTION (CONTACT_SAVE_AS)); - /* Never show the action for the preview panel, the feature required WebKit1 functionality (gtk+ widgets inside webview). Re-enable once there is a good replacement. See also accum_address_map() in eab-contact-formatter.cpp. */ - gtk_action_set_visible (ACTION (CONTACT_PREVIEW_SHOW_MAPS), FALSE); + e_ui_action_set_visible (ACTION (CONTACT_PREVIEW_SHOW_MAPS), FALSE); /* Hide it from the start */ - gtk_action_set_visible (ACTION (CONTACT_CARDS_SORT_BY_MENU), FALSE); + e_ui_action_set_visible (ACTION (CONTACT_CARDS_SORT_BY_MENU), FALSE); } void e_book_shell_view_update_search_filter (EBookShellView *book_shell_view) { + static const EUIActionEnumEntry contact_filter_entries[] = { + + { "contact-filter-any-category", + NULL, + N_("Any Category"), + NULL, + NULL, + NULL, CONTACT_FILTER_ANY_CATEGORY }, + + { "contact-filter-unmatched", + NULL, + N_("Unmatched"), + NULL, + NULL, + NULL, CONTACT_FILTER_UNMATCHED } + }; + EBookShellContent *book_shell_content; EShellView *shell_view; - EShellWindow *shell_window; EShellSearchbar *searchbar; EActionComboBox *combo_box; - GtkActionGroup *action_group; - GtkRadioAction *radio_action; + EUIActionGroup *action_group; + EUIAction *action; GList *list, *iter; - GSList *group; + GPtrArray *radio_group; gint ii; shell_view = E_SHELL_VIEW (book_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - action_group = ACTION_GROUP (CONTACTS_FILTER); - e_action_group_remove_all_actions (action_group); + action_group = e_ui_manager_get_action_group (e_shell_view_get_ui_manager (shell_view), "contacts-filter"); + e_ui_action_group_remove_all (action_group); /* Add the standard filter actions. No callback is needed * because changes in the EActionComboBox are detected and * handled by EShellSearchbar. */ - gtk_action_group_add_radio_actions ( - action_group, contact_filter_entries, - G_N_ELEMENTS (contact_filter_entries), - CONTACT_FILTER_ANY_CATEGORY, NULL, NULL); + e_ui_manager_add_actions_enum (e_shell_view_get_ui_manager (shell_view), + e_ui_action_group_get_name (action_group), NULL, + contact_filter_entries, G_N_ELEMENTS (contact_filter_entries), NULL); - /* Retrieve the radio group from an action we just added. */ - list = gtk_action_group_list_actions (action_group); - radio_action = GTK_RADIO_ACTION (list->data); - group = gtk_radio_action_get_group (radio_action); - g_list_free (list); + radio_group = g_ptr_array_new (); + + for (ii = 0; ii < G_N_ELEMENTS (contact_filter_entries); ii++) { + action = e_ui_action_group_get_action (action_group, contact_filter_entries[ii].name); + e_ui_action_set_radio_group (action, radio_group); + } /* Build the category actions. */ @@ -1853,14 +1759,14 @@ e_book_shell_view_update_search_filter (EBookShellView *book_shell_view) for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) { const gchar *category_name = iter->data; gchar *filename; - GtkAction *action; - gchar *action_name; + gchar action_name[128]; - action_name = g_strdup_printf ( - "contact-filter-category-%d", ii); - radio_action = gtk_radio_action_new ( - action_name, category_name, NULL, NULL, ii); - g_free (action_name); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "contact-filter-category-%d", ii) < sizeof (action_name)); + + action = e_ui_action_new (e_ui_action_group_get_name (action_group), action_name, NULL); + e_ui_action_set_label (action, category_name); + e_ui_action_set_state (action, g_variant_new_int32 (ii)); + e_ui_action_set_radio_group (action, radio_group); /* Convert the category icon file to a themed icon name. */ filename = e_categories_dup_icon_file_for (category_name); @@ -1874,21 +1780,16 @@ e_book_shell_view_update_search_filter (EBookShellView *book_shell_view) if ((cp = strrchr (basename, '.')) != NULL) *cp = '\0'; - g_object_set ( - radio_action, "icon-name", basename, NULL); + e_ui_action_set_icon_name (action, basename); g_free (basename); } g_free (filename); - gtk_radio_action_set_group (radio_action, group); - group = gtk_radio_action_get_group (radio_action); + e_ui_action_group_add (action_group, action); - /* The action group takes ownership of the action. */ - action = GTK_ACTION (radio_action); - gtk_action_group_add_action (action_group, action); - g_object_unref (radio_action); + g_object_unref (action); } g_list_free_full (list, g_free); @@ -1899,10 +1800,12 @@ e_book_shell_view_update_search_filter (EBookShellView *book_shell_view) e_shell_view_block_execute_search (shell_view); /* Use any action in the group; doesn't matter which. */ - e_action_combo_box_set_action (combo_box, radio_action); + e_action_combo_box_set_action (combo_box, action); ii = CONTACT_FILTER_UNMATCHED; e_action_combo_box_add_separator_after (combo_box, ii); e_shell_view_unblock_execute_search (shell_view); + + g_ptr_array_unref (radio_group); } diff --git a/src/modules/addressbook/e-book-shell-view-actions.h b/src/modules/addressbook/e-book-shell-view-actions.h index d4915ffcbd..4b507ad345 100644 --- a/src/modules/addressbook/e-book-shell-view-actions.h +++ b/src/modules/addressbook/e-book-shell-view-actions.h @@ -21,98 +21,92 @@ #ifndef E_BOOK_SHELL_VIEW_ACTIONS_H #define E_BOOK_SHELL_VIEW_ACTIONS_H -#include +#include /* Address Book Actions */ -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_COPY(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-copy") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-delete") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_MOVE(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-move") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-print") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_PRINT_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-print-preview") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_PROPERTIES(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-properties") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_REFRESH(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-refresh") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_REFRESH_BACKEND(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-refresh-backend") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_RENAME(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-rename") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_SAVE_AS(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-save-as") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_STOP(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-stop") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_MAP(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-map") -#define E_SHELL_WINDOW_ACTION_ADDRESS_BOOK_POPUP_MAP(window) \ - E_SHELL_WINDOW_ACTION ((window), "address-book-popup-map") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_COPY(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-copy") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-delete") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_MOVE(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-move") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-print") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_PRINT_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-print-preview") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_PROPERTIES(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-properties") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_REFRESH(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-refresh") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_REFRESH_BACKEND(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-refresh-backend") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_RENAME(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-rename") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_SAVE_AS(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-save-as") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_STOP(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-stop") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_MAP(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-map") +#define E_SHELL_VIEW_ACTION_ADDRESS_BOOK_MAP_POPUP(view) \ + E_SHELL_VIEW_ACTION ((view), "address-book-map-popup") /* Contact Actions */ -#define E_SHELL_WINDOW_ACTION_CONTACT_BULK_EDIT(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-bulk-edit") -#define E_SHELL_WINDOW_ACTION_CONTACT_COPY(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-copy") -#define E_SHELL_WINDOW_ACTION_CONTACT_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-delete") -#define E_SHELL_WINDOW_ACTION_CONTACT_FIND(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-find") -#define E_SHELL_WINDOW_ACTION_CONTACT_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-forward") -#define E_SHELL_WINDOW_ACTION_CONTACT_MOVE(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-move") -#define E_SHELL_WINDOW_ACTION_CONTACT_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-new") -#define E_SHELL_WINDOW_ACTION_CONTACT_NEW_LIST(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-new-list") -#define E_SHELL_WINDOW_ACTION_CONTACT_OPEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-open") -#define E_SHELL_WINDOW_ACTION_CONTACT_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-preview") -#define E_SHELL_WINDOW_ACTION_CONTACT_PREVIEW_SHOW_MAPS(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-preview-show-maps") -#define E_SHELL_WINDOW_ACTION_CONTACT_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-print") -#define E_SHELL_WINDOW_ACTION_CONTACT_SAVE_AS(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-save-as") -#define E_SHELL_WINDOW_ACTION_CONTACT_SEND_MESSAGE(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-send-message") -#define E_SHELL_WINDOW_ACTION_CONTACT_VIEW_CLASSIC(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-view-classic") -#define E_SHELL_WINDOW_ACTION_CONTACT_VIEW_VERTICAL(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-view-vertical") +#define E_SHELL_VIEW_ACTION_CONTACT_BULK_EDIT(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-bulk-edit") +#define E_SHELL_VIEW_ACTION_CONTACT_COPY(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-copy") +#define E_SHELL_VIEW_ACTION_CONTACT_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-delete") +#define E_SHELL_VIEW_ACTION_CONTACT_FIND(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-find") +#define E_SHELL_VIEW_ACTION_CONTACT_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-forward") +#define E_SHELL_VIEW_ACTION_CONTACT_MOVE(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-move") +#define E_SHELL_VIEW_ACTION_CONTACT_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-new") +#define E_SHELL_VIEW_ACTION_CONTACT_NEW_LIST(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-new-list") +#define E_SHELL_VIEW_ACTION_CONTACT_OPEN(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-open") +#define E_SHELL_VIEW_ACTION_CONTACT_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-preview") +#define E_SHELL_VIEW_ACTION_CONTACT_PREVIEW_SHOW_MAPS(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-preview-show-maps") +#define E_SHELL_VIEW_ACTION_CONTACT_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-print") +#define E_SHELL_VIEW_ACTION_CONTACT_SAVE_AS(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-save-as") +#define E_SHELL_VIEW_ACTION_CONTACT_SEND_MESSAGE(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-send-message") +#define E_SHELL_VIEW_ACTION_CONTACT_VIEW_CLASSIC(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-view-classic") +#define E_SHELL_VIEW_ACTION_CONTACT_VIEW_VERTICAL(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-view-vertical") /* Search Actions */ -#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_ADVANCED_HIDDEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-search-advanced-hidden") -#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_ANY_FIELD_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-search-any-field-contains") -#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_EMAIL_BEGINS_WITH(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-search-email-begins-with") -#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_EMAIL_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-search-email-contains") -#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_NAME_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-search-name-contains") -#define E_SHELL_WINDOW_ACTION_CONTACT_SEARCH_PHONE_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-search-phone-contains") +#define E_SHELL_VIEW_ACTION_CONTACT_SEARCH_ADVANCED_HIDDEN(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-search-advanced-hidden") +#define E_SHELL_VIEW_ACTION_CONTACT_SEARCH_ANY_FIELD_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-search-any-field-contains") +#define E_SHELL_VIEW_ACTION_CONTACT_SEARCH_EMAIL_BEGINS_WITH(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-search-email-begins-with") +#define E_SHELL_VIEW_ACTION_CONTACT_SEARCH_EMAIL_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-search-email-contains") +#define E_SHELL_VIEW_ACTION_CONTACT_SEARCH_NAME_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-search-name-contains") +#define E_SHELL_VIEW_ACTION_CONTACT_SEARCH_PHONE_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-search-phone-contains") /* Sort Cards By Actions */ -#define E_SHELL_WINDOW_ACTION_CONTACT_CARDS_SORT_BY_MENU(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-cards-sort-by-menu") -#define E_SHELL_WINDOW_ACTION_CONTACT_CARDS_SORT_BY_FILE_AS(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-cards-sort-by-file-as") -#define E_SHELL_WINDOW_ACTION_CONTACT_CARDS_SORT_BY_GIVEN_NAME(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-cards-sort-by-given-name") -#define E_SHELL_WINDOW_ACTION_CONTACT_CARDS_SORT_BY_FAMILY_NAME(window) \ - E_SHELL_WINDOW_ACTION ((window), "contact-cards-sort-by-family-name") - -/* Action Groups */ -#define E_SHELL_WINDOW_ACTION_GROUP_CONTACTS(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "contacts") -#define E_SHELL_WINDOW_ACTION_GROUP_CONTACTS_FILTER(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "contacts-filter") +#define E_SHELL_VIEW_ACTION_CONTACT_CARDS_SORT_BY_MENU(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-cards-sort-by-menu") +#define E_SHELL_VIEW_ACTION_CONTACT_CARDS_SORT_BY_FILE_AS(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-cards-sort-by-file-as") +#define E_SHELL_VIEW_ACTION_CONTACT_CARDS_SORT_BY_GIVEN_NAME(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-cards-sort-by-given-name") +#define E_SHELL_VIEW_ACTION_CONTACT_CARDS_SORT_BY_FAMILY_NAME(view) \ + E_SHELL_VIEW_ACTION ((view), "contact-cards-sort-by-family-name") #endif /* E_BOOK_SHELL_VIEW_ACTIONS_H */ diff --git a/src/modules/addressbook/e-book-shell-view-private.c b/src/modules/addressbook/e-book-shell-view-private.c index 3dbbde81b7..a8a067b211 100644 --- a/src/modules/addressbook/e-book-shell-view-private.c +++ b/src/modules/addressbook/e-book-shell-view-private.c @@ -122,7 +122,7 @@ static void popup_event (EShellView *shell_view, GdkEvent *button_event) { - e_book_shell_view_show_popup_menu (shell_view, "/contact-popup", button_event, NULL); + e_book_shell_view_show_popup_menu (shell_view, "contact-popup", button_event, NULL); } static void @@ -377,7 +377,7 @@ book_shell_view_selector_popup_event_cb (EShellView *shell_view, ESource *clicked_source, GdkEvent *button_event) { - e_book_shell_view_show_popup_menu (shell_view, "/address-book-popup", button_event, clicked_source); + e_book_shell_view_show_popup_menu (shell_view, "address-book-popup", button_event, clicked_source); return TRUE; } @@ -433,14 +433,15 @@ book_shell_view_source_removed_cb (ESourceRegistry *registry, static void book_shell_view_notify_view_id_cb (EBookShellView *book_shell_view) { + EShellView *shell_view; EBookShellContent *book_shell_content; - EShellWindow *shell_window; EAddressbookView *address_view; GalViewInstance *view_instance; GalView *gl_view; - GtkAction *action; + EUIAction *action; const gchar *view_id; + shell_view = E_SHELL_VIEW (book_shell_view); book_shell_content = book_shell_view->priv->book_shell_content; address_view = e_book_shell_content_get_current_view (book_shell_content); view_instance = e_addressbook_view_get_view_instance (address_view); @@ -456,18 +457,51 @@ book_shell_view_notify_view_id_cb (EBookShellView *book_shell_view) gal_view_instance_set_current_view_id (view_instance, view_id); - shell_window = e_shell_view_get_shell_window (E_SHELL_VIEW (book_shell_view)); gl_view = gal_view_instance_get_current_view (view_instance); action = ACTION (CONTACT_CARDS_SORT_BY_MENU); - gtk_action_set_visible (action, GAL_IS_VIEW_MINICARD (gl_view)); + e_ui_action_set_visible (action, GAL_IS_VIEW_MINICARD (gl_view)); + e_ui_action_set_sensitive (action, e_ui_action_get_visible (action)); if (GAL_IS_VIEW_MINICARD (gl_view)) { action = ACTION (CONTACT_CARDS_SORT_BY_FILE_AS); - gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), gal_view_minicard_get_sort_by (GAL_VIEW_MINICARD (gl_view))); + e_ui_action_set_state (action, g_variant_new_int32 (gal_view_minicard_get_sort_by (GAL_VIEW_MINICARD (gl_view)))); } } +static void +book_shell_view_contact_view_notify_state_cb (GObject *object, + GParamSpec *param, + gpointer user_data) +{ + GAction *action = G_ACTION (object); + EBookShellView *self = user_data; + EBookShellContent *book_shell_content; + GVariant *state; + GtkOrientable *orientable; + GtkOrientation orientation; + + state = g_action_get_state (action); + + book_shell_content = self->priv->book_shell_content; + orientable = GTK_ORIENTABLE (book_shell_content); + + switch (g_variant_get_int32 (state)) { + case 0: + orientation = GTK_ORIENTATION_VERTICAL; + break; + case 1: + orientation = GTK_ORIENTATION_HORIZONTAL; + break; + default: + g_return_if_reached (); + } + + gtk_orientable_set_orientation (orientable, orientation); + + g_clear_pointer (&state, g_variant_unref); +} + void e_book_shell_view_private_init (EBookShellView *book_shell_view) { @@ -496,7 +530,12 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view) EShellContent *shell_content; EShellSidebar *shell_sidebar; EShellBackend *shell_backend; + EShellSearchbar *searchbar; ESourceSelector *selector; + EPreviewPane *preview_pane; + EWebView *web_view; + EUIAction *action; + GSettings *settings; gulong handler_id; shell_view = E_SHELL_VIEW (book_shell_view); @@ -506,9 +545,6 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view) shell_window = e_shell_view_get_shell_window (shell_view); shell = e_shell_window_get_shell (shell_window); - e_shell_window_add_action_group_full (shell_window, "contacts", "addressbook"); - e_shell_window_add_action_group_full (shell_window, "contacts-filter", "addressbook"); - /* Cache these to avoid lots of awkward casting. */ priv->book_shell_backend = E_BOOK_SHELL_BACKEND (g_object_ref (shell_backend)); priv->book_shell_content = E_BOOK_SHELL_CONTENT (g_object_ref (shell_content)); @@ -556,7 +592,56 @@ e_book_shell_view_private_constructed (EBookShellView *book_shell_view) (GHookFunc) e_book_shell_view_update_search_filter, book_shell_view); - e_book_shell_view_actions_init (book_shell_view); + preview_pane = e_book_shell_content_get_preview_pane (book_shell_view->priv->book_shell_content); + web_view = e_preview_pane_get_web_view (preview_pane); + e_web_view_set_open_proxy (web_view, ACTION (CONTACT_OPEN)); + e_web_view_set_print_proxy (web_view, ACTION (CONTACT_PRINT)); + e_web_view_set_save_as_proxy (web_view, ACTION (CONTACT_SAVE_AS)); + + /* Advanced Search Action */ + action = ACTION (CONTACT_SEARCH_ADVANCED_HIDDEN); + e_ui_action_set_visible (action, FALSE); + searchbar = e_book_shell_content_get_searchbar (book_shell_view->priv->book_shell_content); + e_shell_searchbar_set_search_option (searchbar, action); + + /* Bind GObject properties to GSettings keys. */ + + settings = e_util_ref_settings ("org.gnome.evolution.addressbook"); + + g_settings_bind ( + settings, "preview-show-maps", + ACTION (CONTACT_PREVIEW_SHOW_MAPS), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + action = ACTION (CONTACT_PREVIEW); + + g_settings_bind ( + settings, "show-preview", + action, "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + e_binding_bind_property ( + action, "active", + book_shell_view->priv->book_shell_content, "preview-visible", + G_BINDING_SYNC_CREATE); + + action = ACTION (CONTACT_VIEW_VERTICAL); + + g_settings_bind_with_mapping ( + settings, "layout", + action, "state", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY, + e_shell_view_util_layout_to_state_cb, + e_shell_view_util_state_to_layout_cb, NULL, NULL); + + g_object_unref (settings); + + g_signal_connect_object (action, "notify::state", + G_CALLBACK (book_shell_view_contact_view_notify_state_cb), book_shell_view, 0); + + /* to propagate the loaded state */ + book_shell_view_contact_view_notify_state_cb (G_OBJECT (action), NULL, book_shell_view); + e_shell_view_block_execute_search (shell_view); book_shell_view_activate_selected_source (book_shell_view, selector); e_shell_view_unblock_execute_search (shell_view); diff --git a/src/modules/addressbook/e-book-shell-view-private.h b/src/modules/addressbook/e-book-shell-view-private.h index 8c611b4606..9080f59745 100644 --- a/src/modules/addressbook/e-book-shell-view-private.h +++ b/src/modules/addressbook/e-book-shell-view-private.h @@ -46,11 +46,9 @@ #include "e-book-shell-sidebar.h" #include "e-book-shell-view-actions.h" -/* Shorthand, requires a variable named "shell_window". */ +/* Shorthand, requires a variable named "shell_view". */ #define ACTION(name) \ - (E_SHELL_WINDOW_ACTION_##name (shell_window)) -#define ACTION_GROUP(name) \ - (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window)) + (E_SHELL_VIEW_ACTION_##name (shell_view)) /* ETable Specifications */ #define ETSPEC_FILENAME "e-addressbook-view.etspec" diff --git a/src/modules/addressbook/e-book-shell-view.c b/src/modules/addressbook/e-book-shell-view.c index e0e1d57987..65fc382175 100644 --- a/src/modules/addressbook/e-book-shell-view.c +++ b/src/modules/addressbook/e-book-shell-view.c @@ -77,12 +77,19 @@ static void book_shell_view_constructed (GObject *object) { EBookShellView *book_shell_view; + EUIManager *ui_manager; + + ui_manager = e_shell_view_get_ui_manager (E_SHELL_VIEW (object)); + + e_ui_manager_freeze (ui_manager); /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_book_shell_view_parent_class)->constructed (object); book_shell_view = E_BOOK_SHELL_VIEW (object); e_book_shell_view_private_constructed (book_shell_view); + + e_ui_manager_thaw (ui_manager); } static void @@ -90,12 +97,12 @@ book_shell_view_execute_search (EShellView *shell_view) { EBookShellView *self; EBookShellContent *book_shell_content; - EShellWindow *shell_window; EShellContent *shell_content; EShellSearchbar *searchbar; EActionComboBox *combo_box; - GtkRadioAction *action; + EUIAction *action; EAddressbookView *view; + GVariant *state; gchar *query; gchar *temp; gchar *selected_category; @@ -108,14 +115,15 @@ book_shell_view_execute_search (EShellView *shell_view) if (self->priv->search_locked) return; - shell_window = e_shell_view_get_shell_window (shell_view); shell_content = e_shell_view_get_shell_content (shell_view); book_shell_content = E_BOOK_SHELL_CONTENT (shell_content); searchbar = e_book_shell_content_get_searchbar (book_shell_content); - action = GTK_RADIO_ACTION (ACTION (CONTACT_SEARCH_ANY_FIELD_CONTAINS)); - search_id = gtk_radio_action_get_current_value (action); + action = ACTION (CONTACT_SEARCH_ANY_FIELD_CONTAINS); + state = g_action_get_state (G_ACTION (action)); + search_id = g_variant_get_int32 (state); + g_clear_pointer (&state, g_variant_unref); if (search_id == CONTACT_SEARCH_ADVANCED) { query = e_shell_view_get_search_query (shell_view); @@ -231,8 +239,7 @@ book_shell_view_update_actions (EShellView *shell_view) { EShellContent *shell_content; EShellSidebar *shell_sidebar; - EShellWindow *shell_window; - GtkAction *action; + EUIAction *action; const gchar *label; gboolean sensitive; guint32 state; @@ -258,8 +265,6 @@ book_shell_view_update_actions (EShellView *shell_view) E_SHELL_VIEW_CLASS (e_book_shell_view_parent_class)-> update_actions (shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - shell_content = e_shell_view_get_shell_content (shell_view); state = e_shell_content_check_state (shell_content); @@ -301,122 +306,130 @@ book_shell_view_update_actions (EShellView *shell_view) action = ACTION (ADDRESS_BOOK_COPY); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_MOVE); sensitive = has_primary_source && source_is_editable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_DELETE); sensitive = primary_source_is_removable || primary_source_is_remote_deletable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_PRINT); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_PRINT_PREVIEW); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_PROPERTIES); sensitive = clicked_source_is_primary && primary_source_is_writable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_REFRESH); sensitive = clicked_source_is_primary && refresh_supported; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_REFRESH_BACKEND); sensitive = clicked_source_is_collection; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_RENAME); sensitive = clicked_source_is_primary && ( primary_source_is_writable && !primary_source_in_collection); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_SAVE_AS); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); - action = ACTION (ADDRESS_BOOK_POPUP_MAP); + action = ACTION (ADDRESS_BOOK_MAP_POPUP); sensitive = clicked_source_is_primary; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (ADDRESS_BOOK_STOP); sensitive = source_is_busy; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_BULK_EDIT); sensitive = any_contacts_selected && !selection_is_contact_list; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_COPY); sensitive = any_contacts_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_DELETE); sensitive = source_is_editable && any_contacts_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_FIND); sensitive = single_contact_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_FORWARD); sensitive = any_contacts_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); if (multiple_contacts_selected) label = _("_Forward Contacts"); else label = _("_Forward Contact"); - gtk_action_set_label (action, label); + e_ui_action_set_label (action, label); action = ACTION (CONTACT_MOVE); sensitive = source_is_editable && any_contacts_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_NEW); sensitive = source_is_editable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_NEW_LIST); sensitive = source_is_editable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_OPEN); sensitive = any_contacts_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_PRINT); sensitive = any_contacts_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_SAVE_AS); sensitive = any_contacts_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CONTACT_SEND_MESSAGE); sensitive = any_contacts_selected && selection_has_email; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); if (multiple_contacts_selected) label = _("_Send Message to Contacts"); else if (selection_is_contact_list) label = _("_Send Message to List"); else label = _("_Send Message to Contact"); - gtk_action_set_label (action, label); + e_ui_action_set_label (action, label); #ifndef ENABLE_CONTACT_MAPS - gtk_action_set_visible (ACTION (ADDRESS_BOOK_MAP), FALSE); - gtk_action_set_visible (ACTION (ADDRESS_BOOK_POPUP_MAP), FALSE); + e_ui_action_set_visible (ACTION (ADDRESS_BOOK_MAP), FALSE); + e_ui_action_set_visible (ACTION (ADDRESS_BOOK_MAP_POPUP), FALSE); #endif } +static void +book_shell_view_init_ui_data (EShellView *shell_view) +{ + g_return_if_fail (E_IS_BOOK_SHELL_VIEW (shell_view)); + + e_book_shell_view_actions_init (E_BOOK_SHELL_VIEW (shell_view)); +} + static void e_book_shell_view_class_finalize (EBookShellViewClass *class) { @@ -437,14 +450,14 @@ e_book_shell_view_class_init (EBookShellViewClass *class) shell_view_class = E_SHELL_VIEW_CLASS (class); shell_view_class->label = _("Contacts"); shell_view_class->icon_name = "x-office-address-book"; - shell_view_class->ui_definition = "evolution-contacts.ui"; + shell_view_class->ui_definition = "evolution-contacts.eui"; shell_view_class->ui_manager_id = "org.gnome.evolution.contacts"; - shell_view_class->search_options = "/contact-search-options"; shell_view_class->search_rules = "addresstypes.xml"; shell_view_class->new_shell_content = e_book_shell_content_new; shell_view_class->new_shell_sidebar = e_book_shell_sidebar_new; shell_view_class->execute_search = book_shell_view_execute_search; shell_view_class->update_actions = book_shell_view_update_actions; + shell_view_class->init_ui_data = book_shell_view_init_ui_data; g_object_class_install_property ( object_class, diff --git a/src/modules/backup-restore/evolution-backup-restore.c b/src/modules/backup-restore/evolution-backup-restore.c index d95fc6d982..2178fdc67d 100644 --- a/src/modules/backup-restore/evolution-backup-restore.c +++ b/src/modules/backup-restore/evolution-backup-restore.c @@ -65,18 +65,6 @@ void e_module_unload (GTypeModule *type_module); GType evolution_backup_restore_assistant_get_type (void); GType evolution_backup_restore_menu_items_get_type (void); -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -""; - G_DEFINE_DYNAMIC_TYPE ( EvolutionBackupRestoreAssistant, evolution_backup_restore_assistant, @@ -281,9 +269,12 @@ is_xz_available (void) } static void -action_settings_backup_cb (GtkAction *action, - EShellWindow *shell_window) +action_settings_backup_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; + gpointer parent_window; GFile *file; GFile *parent; GFileInfo *file_info; @@ -301,9 +292,11 @@ action_settings_backup_cb (GtkAction *action, g_free (tmp); + parent_window = e_shell_view_get_shell_window (shell_view); + if (!evolution_backup_restore_check_prog_exists ("tar", &error)) { e_alert_run_dialog_for_args ( - GTK_WINDOW (shell_window), + parent_window, "org.gnome.backup-restore:cannot-backup", error ? error->message : "Unknown error", NULL); g_clear_error (&error); @@ -312,7 +305,7 @@ action_settings_backup_cb (GtkAction *action, } file = e_shell_run_save_dialog ( - e_shell_window_get_shell (shell_window), + e_shell_window_get_shell (e_shell_view_get_shell_window (shell_view)), _("Select name of the Evolution backup file"), suggest, has_xz ? "*.tar.xz;*.tar.gz" : "*.tar.gz", set_local_only, has_xz ? suggest : NULL); @@ -338,7 +331,7 @@ action_settings_backup_cb (GtkAction *action, (tmp && !g_str_has_suffix (tmp, ".xz") && !evolution_backup_restore_check_prog_exists ("gzip", &error))) { e_alert_run_dialog_for_args ( - GTK_WINDOW (shell_window), + parent_window, "org.gnome.backup-restore:cannot-backup", error ? error->message : "Unknown error", NULL); g_clear_error (&error); @@ -373,7 +366,7 @@ action_settings_backup_cb (GtkAction *action, gchar *path; mask = dialog_prompt_user ( - GTK_WINDOW (shell_window), + parent_window, _("_Restart Evolution after backup"), "org.gnome.backup-restore:backup-confirm", NULL); if (mask & BR_OK) { @@ -383,7 +376,7 @@ action_settings_backup_cb (GtkAction *action, } } else { e_alert_run_dialog_for_args ( - GTK_WINDOW (shell_window), + parent_window, "org.gnome.backup-restore:insufficient-permissions", NULL); } @@ -408,7 +401,7 @@ validate_backup_file_data_free (gpointer ptr) guint32 mask; mask = dialog_prompt_user ( - GTK_WINDOW (vbf->shell_window), + vbf->shell_window ? GTK_WINDOW (vbf->shell_window) : NULL, _("Re_start Evolution after restore"), "org.gnome.backup-restore:restore-confirm", NULL); if (mask & BR_OK) @@ -447,17 +440,18 @@ validate_backup_file_thread (EAlertSinkThreadJobData *job_data, } static void -action_settings_restore_cb (GtkAction *action, - EShellWindow *shell_window) +action_settings_restore_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; EActivity *activity; - EShellView *shell_view; GFile *file; gchar *path, *description; ValidateBackupFileData *vbf; file = e_shell_run_open_dialog ( - e_shell_window_get_shell (shell_window), + e_shell_window_get_shell (e_shell_view_get_shell_window (shell_view)), _("Select name of the Evolution backup file to restore"), set_local_only, NULL); @@ -466,11 +460,12 @@ action_settings_restore_cb (GtkAction *action, path = g_file_get_path (file); - shell_view = e_shell_window_get_shell_view (shell_window, e_shell_window_get_active_view (shell_window)); description = g_strdup_printf (_("Checking content of backup file “%s”, please wait…"), path); vbf = g_slice_new0 (ValidateBackupFileData); - vbf->shell_window = g_object_ref (shell_window); + vbf->shell_window = e_shell_view_get_shell_window (shell_view); + if (vbf->shell_window) + g_object_ref (vbf->shell_window); vbf->path = g_strdup (path); activity = e_shell_view_submit_thread_job (shell_view, description, "org.gnome.backup-restore:invalid-backup", path, @@ -484,23 +479,6 @@ action_settings_restore_cb (GtkAction *action, g_free (path); } -static GtkActionEntry entries[] = { - - { "settings-backup", - NULL, - N_("_Back up Evolution Data…"), - NULL, - N_("Back up Evolution data and settings to an archive file"), - G_CALLBACK (action_settings_backup_cb) }, - - { "settings-restore", - NULL, - N_("R_estore Evolution Data…"), - NULL, - N_("Restore Evolution data and settings from an archive file"), - G_CALLBACK (action_settings_restore_cb) } -}; - static gboolean evolution_backup_restore_filename_to_visible (GBinding *binding, const GValue *source_value, @@ -605,34 +583,48 @@ evolution_backup_restore_assistant_init (EExtension *extension) static void evolution_backup_restore_menu_items_constructed (GObject *object) { - EExtension *extension; - EExtensible *extensible; - EShellWindow *shell_window; - GtkActionGroup *action_group; - GtkUIManager *ui_manager; - GError *error = NULL; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - extension = E_EXTENSION (object); - extensible = e_extension_get_extensible (extension); + static const EUIActionEntry entries[] = { + + { "settings-backup", + NULL, + N_("_Back up Evolution Data…"), + NULL, + N_("Back up Evolution data and settings to an archive file"), + action_settings_backup_cb, NULL, NULL }, + + { "settings-restore", + NULL, + N_("R_estore Evolution Data…"), + NULL, + N_("Restore Evolution data and settings from an archive file"), + action_settings_restore_cb, NULL, NULL } + }; + + EExtensible *extensible; + EShellView *shell_view; + EUIManager *ui_manager; /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (evolution_backup_restore_menu_items_parent_class)->constructed (object); - shell_window = E_SHELL_WINDOW (extensible); - action_group = e_shell_window_get_action_group (shell_window, "shell"); + extensible = e_extension_get_extensible (E_EXTENSION (object)); + shell_view = E_SHELL_VIEW (extensible); + ui_manager = e_shell_view_get_ui_manager (shell_view); - /* Add actions to the "shell" action group. */ - gtk_action_group_add_actions ( - action_group, entries, - G_N_ELEMENTS (entries), shell_window); - - /* Because we are loading from a hard-coded string, there is - * no chance of I/O errors. Failure here implies a malformed - * UI definition. Full stop. */ - ui_manager = e_shell_window_get_ui_manager (shell_window); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) - g_error ("%s", error->message); + e_ui_manager_add_actions_with_eui_data (ui_manager, "backup-restore", NULL, + entries, G_N_ELEMENTS (entries), shell_view, eui); } static void @@ -645,7 +637,7 @@ evolution_backup_restore_menu_items_class_init (EExtensionClass *class) object_class->constructed = evolution_backup_restore_menu_items_constructed; extension_class = E_EXTENSION_CLASS (class); - extension_class->extensible_type = E_TYPE_SHELL_WINDOW; + extension_class->extensible_type = E_TYPE_SHELL_VIEW; } static void @@ -672,4 +664,3 @@ G_MODULE_EXPORT void e_module_unload (GTypeModule *type_module) { } - diff --git a/src/modules/calendar/e-cal-attachment-handler.c b/src/modules/calendar/e-cal-attachment-handler.c index db16e1994d..61b4d883c6 100644 --- a/src/modules/calendar/e-cal-attachment-handler.c +++ b/src/modules/calendar/e-cal-attachment-handler.c @@ -45,16 +45,6 @@ struct _ImportContext { G_DEFINE_DYNAMIC_TYPE_EXTENDED (ECalAttachmentHandler, e_cal_attachment_handler, E_TYPE_ATTACHMENT_HANDLER, 0, G_ADD_PRIVATE_DYNAMIC (ECalAttachmentHandler)) -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -""; - static ICalComponent * attachment_handler_get_component (EAttachment *attachment) { @@ -390,108 +380,122 @@ attachment_handler_import_ical (EAttachmentHandler *handler, } static void -attachment_handler_import_to_calendar (GtkAction *action, - EAttachmentHandler *handler) +attachment_handler_import_to_calendar (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + attachment_handler_import_ical (handler, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, _("Select a Calendar")); } static void -attachment_handler_import_to_memos (GtkAction *action, - EAttachmentHandler *handler) +attachment_handler_import_to_memos (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + attachment_handler_import_ical (handler, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, _("Select a Memo List")); } static void -attachment_handler_import_to_tasks (GtkAction *action, - EAttachmentHandler *handler) +attachment_handler_import_to_tasks (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + attachment_handler_import_ical (handler, E_CAL_CLIENT_SOURCE_TYPE_TASKS, _("Select a Task List")); } -static GtkActionEntry standard_entries[] = { - - { "import-to-calendar", - "stock_mail-import", - N_("I_mport to Calendar"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (attachment_handler_import_to_calendar) }, - - { "import-to-memos", - "stock_mail-import", - N_("I_mport to Memo List"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (attachment_handler_import_to_memos) }, - - { "import-to-tasks", - "stock_mail-import", - N_("I_mport to Task List"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (attachment_handler_import_to_tasks) } -}; - static void cal_attachment_handler_update_actions (EAttachmentView *view) { - EAttachment *attachment; - GtkAction *action; + EUIAction *action; GList *selected; - ICalComponent *component; - ICalComponent *subcomponent; - ICalComponentKind kind; gboolean is_vevent = FALSE; gboolean is_vjournal = FALSE; gboolean is_vtodo = FALSE; selected = e_attachment_view_get_selected_attachments (view); - if (g_list_length (selected) != 1) - goto exit; + if (g_list_length (selected) == 1) { + EAttachment *attachment; + ICalComponent *component; - attachment = E_ATTACHMENT (selected->data); - component = attachment_handler_get_component (attachment); + attachment = E_ATTACHMENT (selected->data); + component = attachment_handler_get_component (attachment); - if (component == NULL) - goto exit; + if (component) { + ICalComponent *subcomponent; + ICalComponentKind kind; - subcomponent = i_cal_component_get_inner (component); + subcomponent = i_cal_component_get_inner (component); - if (subcomponent == NULL) - goto exit; + if (subcomponent != NULL) { + kind = i_cal_component_isa (subcomponent); + is_vevent = (kind == I_CAL_VEVENT_COMPONENT); + is_vjournal = (kind == I_CAL_VJOURNAL_COMPONENT); + is_vtodo = (kind == I_CAL_VTODO_COMPONENT); - kind = i_cal_component_isa (subcomponent); - is_vevent = (kind == I_CAL_VEVENT_COMPONENT); - is_vjournal = (kind == I_CAL_VJOURNAL_COMPONENT); - is_vtodo = (kind == I_CAL_VTODO_COMPONENT); + g_object_unref (subcomponent); + } + } + } - g_object_unref (subcomponent); - -exit: action = e_attachment_view_get_action (view, "import-to-calendar"); - gtk_action_set_visible (action, is_vevent); + e_ui_action_set_visible (action, is_vevent); action = e_attachment_view_get_action (view, "import-to-memos"); - gtk_action_set_visible (action, is_vjournal); + e_ui_action_set_visible (action, is_vjournal); action = e_attachment_view_get_action (view, "import-to-tasks"); - gtk_action_set_visible (action, is_vtodo); + e_ui_action_set_visible (action, is_vtodo); - g_list_foreach (selected, (GFunc) g_object_unref, NULL); - g_list_free (selected); + g_list_free_full (selected, g_object_unref); } static void cal_attachment_handler_constructed (GObject *object) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry standard_entries[] = { + + { "import-to-calendar", + "stock_mail-import", + N_("I_mport to Calendar"), + NULL, + NULL, + attachment_handler_import_to_calendar, NULL, NULL, NULL }, + + { "import-to-memos", + "stock_mail-import", + N_("I_mport to Memo List"), + NULL, + NULL, + attachment_handler_import_to_memos, NULL, NULL, NULL }, + + { "import-to-tasks", + "stock_mail-import", + N_("I_mport to Task List"), + NULL, + NULL, + attachment_handler_import_to_tasks, NULL, NULL, NULL } + }; + EAttachmentHandler *handler; EAttachmentView *view; - GtkActionGroup *action_group; - GtkUIManager *ui_manager; - GError *error = NULL; + EUIManager *ui_manager; handler = E_ATTACHMENT_HANDLER (object); @@ -499,19 +503,10 @@ cal_attachment_handler_constructed (GObject *object) G_OBJECT_CLASS (e_cal_attachment_handler_parent_class)->constructed (object); view = e_attachment_handler_get_view (handler); - - action_group = e_attachment_view_add_action_group (view, "calendar"); - gtk_action_group_add_actions ( - action_group, standard_entries, - G_N_ELEMENTS (standard_entries), handler); - ui_manager = e_attachment_view_get_ui_manager (view); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "calendar", NULL, + standard_entries, G_N_ELEMENTS (standard_entries), handler, eui); g_signal_connect ( view, "update_actions", diff --git a/src/modules/calendar/e-cal-base-shell-backend.c b/src/modules/calendar/e-cal-base-shell-backend.c index 834f29ca8e..1e1de4a235 100644 --- a/src/modules/calendar/e-cal-base-shell-backend.c +++ b/src/modules/calendar/e-cal-base-shell-backend.c @@ -201,9 +201,6 @@ cal_base_shell_backend_constructed (GObject *object) EShell *shell; EShellBackend *shell_backend; - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_cal_base_shell_backend_parent_class)->constructed (object); - shell_backend = E_SHELL_BACKEND (object); shell = e_shell_backend_get_shell (shell_backend); @@ -216,6 +213,9 @@ cal_base_shell_backend_constructed (GObject *object) shell, "window-added", G_CALLBACK (cal_base_shell_backend_window_added_cb), shell_backend); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_cal_base_shell_backend_parent_class)->constructed (object); } static void diff --git a/src/modules/calendar/e-cal-base-shell-backend.h b/src/modules/calendar/e-cal-base-shell-backend.h index 51bc09cc13..c1c71b1ef2 100644 --- a/src/modules/calendar/e-cal-base-shell-backend.h +++ b/src/modules/calendar/e-cal-base-shell-backend.h @@ -55,10 +55,10 @@ struct _ECalBaseShellBackend { struct _ECalBaseShellBackendClass { EShellBackendClass parent_class; - GtkActionEntry *new_item_entries; + const EUIActionEntry *new_item_entries; guint new_item_n_entries; - GtkActionEntry *source_entries; + const EUIActionEntry *source_entries; guint source_n_entries; gboolean (* handle_uri) (EShellBackend *shell_backend, diff --git a/src/modules/calendar/e-cal-base-shell-sidebar.c b/src/modules/calendar/e-cal-base-shell-sidebar.c index 2d995d26ac..1181288533 100644 --- a/src/modules/calendar/e-cal-base-shell-sidebar.c +++ b/src/modules/calendar/e-cal-base-shell-sidebar.c @@ -658,16 +658,14 @@ cal_base_shell_sidebar_get_property (GObject *object, static void e_cal_base_shell_sidebar_update_calendar_margin_cb (GObject *object, - GParamSpec *pspec, - gpointer *user_data) + GParamSpec *pspec, + gpointer *user_data) { - EShellWindow *shell_window; - GtkWidget *calendar; + EShellView *shell_view = E_SHELL_VIEW (object); + GtkWidget *calendar = GTK_WIDGET (user_data); gboolean switcher_visible; - shell_window = E_SHELL_WINDOW (object); - calendar = GTK_WIDGET (user_data); - switcher_visible = e_shell_window_get_switcher_visible (shell_window); + switcher_visible = e_shell_view_get_switcher_visible (shell_view); if (switcher_visible) gtk_widget_set_margin_bottom (calendar, 0); @@ -794,7 +792,7 @@ cal_base_shell_sidebar_constructed (GObject *object) e_drag_dest_add_calendar_targets (GTK_WIDGET (cal_base_shell_sidebar->priv->selector)); - g_signal_connect (shell_window, + g_signal_connect (shell_view, "notify::switcher-visible", G_CALLBACK (e_cal_base_shell_sidebar_update_calendar_margin_cb), widget); diff --git a/src/modules/calendar/e-cal-shell-backend.c b/src/modules/calendar/e-cal-shell-backend.c index 71321e182f..8c10c92a31 100644 --- a/src/modules/calendar/e-cal-shell-backend.c +++ b/src/modules/calendar/e-cal-shell-backend.c @@ -41,9 +41,11 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (ECalShellBackend, e_cal_shell_backend, E_TYPE_CA G_ADD_PRIVATE_DYNAMIC (ECalShellBackend)) static void -action_event_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_event_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; EShellView *shell_view; EShellBackend *shell_backend; @@ -54,9 +56,11 @@ action_event_new_cb (GtkAction *action, shell = e_shell_window_get_shell (shell_window); - action_name = gtk_action_get_name (action); - is_all_day = g_strcmp0 (action_name, "event-all-day-new") == 0; - is_meeting = g_strcmp0 (action_name, "event-meeting-new") == 0; + action_name = g_action_get_name (G_ACTION (action)); + is_all_day = g_strcmp0 (action_name, "event-all-day-new") == 0 || + g_strcmp0 (action_name, "new-menu-event-all-day-new") == 0; + is_meeting = g_strcmp0 (action_name, "event-meeting-new") == 0 || + g_strcmp0 (action_name, "new-menu-event-meeting-new") == 0; /* With a 'calendar' active shell view pass the new appointment * request to it, thus the event will inherit selected time from @@ -102,46 +106,15 @@ action_event_new_cb (GtkAction *action, } static void -action_calendar_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_calendar_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; + e_cal_base_shell_backend_util_new_source (shell_window, E_CAL_CLIENT_SOURCE_TYPE_EVENTS); } -static GtkActionEntry item_entries[] = { - - { "event-new", - "appointment-new", - NC_("New", "_Appointment"), - "a", - N_("Create a new appointment"), - G_CALLBACK (action_event_new_cb) }, - - { "event-all-day-new", - "stock_new-24h-appointment", - NC_("New", "All Day A_ppointment"), - NULL, - N_("Create a new all-day appointment"), - G_CALLBACK (action_event_new_cb) }, - - { "event-meeting-new", - "stock_people", - NC_("New", "M_eeting"), - "e", - N_("Create a new meeting request"), - G_CALLBACK (action_event_new_cb) } -}; - -static GtkActionEntry source_entries[] = { - - { "calendar-new", - "x-office-calendar", - NC_("New", "Cale_ndar"), - NULL, - N_("Create a new calendar"), - G_CALLBACK (action_calendar_new_cb) } -}; - static void cal_shell_backend_handle_uri_start_end_dates (EShellBackend *shell_backend, const GDate *start_date, @@ -288,6 +261,38 @@ cal_shell_backend_constructed (GObject *object) static void e_cal_shell_backend_class_init (ECalShellBackendClass *class) { + static const EUIActionEntry item_entries[] = { + { "new-menu-event-new", + "appointment-new", + NC_("New", "_Appointment"), + "a", + N_("Create a new appointment"), + action_event_new_cb, NULL, NULL, NULL }, + + { "new-menu-event-all-day-new", + "stock_new-24h-appointment", + NC_("New", "All Day A_ppointment"), + NULL, + N_("Create a new all-day appointment"), + action_event_new_cb, NULL, NULL, NULL }, + + { "new-menu-event-meeting-new", + "stock_people", + NC_("New", "M_eeting"), + "e", + N_("Create a new meeting request"), + action_event_new_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry source_entries[] = { + { "new-menu-calendar-new", + "x-office-calendar", + NC_("New", "Cale_ndar"), + NULL, + N_("Create a new calendar"), + action_calendar_new_cb, NULL, NULL, NULL } + }; + GObjectClass *object_class; EShellBackendClass *shell_backend_class; ECalBaseShellBackendClass *cal_base_shell_backend_class; diff --git a/src/modules/calendar/e-cal-shell-content.c b/src/modules/calendar/e-cal-shell-content.c index 9c2a0f9c8c..cd18d26602 100644 --- a/src/modules/calendar/e-cal-shell-content.c +++ b/src/modules/calendar/e-cal-shell-content.c @@ -785,15 +785,13 @@ cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content, if (view_kind != E_CAL_VIEW_KIND_LIST) { EShellView *shell_view; - EShellWindow *shell_window; shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content)); - shell_window = e_shell_view_get_shell_window (shell_view); /* Reset these two filters, because they force the List View */ - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (CALENDAR_FILTER_ACTIVE_APPOINTMENTS))) || - gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (ACTION (CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS)))) - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (ACTION (CALENDAR_FILTER_ANY_CATEGORY)), TRUE); + if (e_ui_action_get_active (ACTION (CALENDAR_FILTER_ACTIVE_APPOINTMENTS)) || + e_ui_action_get_active (ACTION (CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS))) + e_ui_action_set_active (ACTION (CALENDAR_FILTER_ANY_CATEGORY), TRUE); } e_cal_shell_content_set_current_view_id (cal_shell_content, view_kind); @@ -1556,11 +1554,14 @@ cal_shell_content_view_created (ECalBaseShellContent *cal_base_shell_content) gal_view_instance_load (view_instance); /* Keep the toolbar view buttons in sync with the calendar. */ - e_binding_bind_property ( + e_binding_bind_property_full ( cal_shell_content, "current-view-id", - ACTION (CALENDAR_VIEW_DAY), "current-value", + ACTION (CALENDAR_VIEW_DAY), "state", G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); + G_BINDING_SYNC_CREATE, + e_ui_action_util_gvalue_to_enum_state, + e_ui_action_util_enum_state_to_gvalue, + NULL, NULL); e_signal_connect_notify ( model, "notify::work-day-monday", @@ -2264,7 +2265,6 @@ e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content, ECalViewKind view_kind) { EShellView *shell_view; - EShellWindow *shell_window; time_t start_time = -1, end_time = -1; gint ii; @@ -2336,9 +2336,8 @@ e_cal_shell_content_set_current_view_id (ECalShellContent *cal_shell_content, cal_shell_content_switch_list_view (cal_shell_content, cal_shell_content->priv->current_view, view_kind); shell_view = e_shell_content_get_shell_view (E_SHELL_CONTENT (cal_shell_content)); - shell_window = e_shell_view_get_shell_window (shell_view); - gtk_action_set_sensitive (ACTION (CALENDAR_PREVIEW_MENU), view_kind == E_CAL_VIEW_KIND_YEAR); + e_ui_action_set_visible (ACTION (CALENDAR_PREVIEW_MENU), view_kind == E_CAL_VIEW_KIND_YEAR); cal_shell_content->priv->current_view = view_kind; diff --git a/src/modules/calendar/e-cal-shell-view-actions.c b/src/modules/calendar/e-cal-shell-view-actions.c index 824f808903..0b1d639532 100644 --- a/src/modules/calendar/e-cal-shell-view-actions.c +++ b/src/modules/calendar/e-cal-shell-view-actions.c @@ -23,7 +23,6 @@ #include "calendar/gui/e-cal-dialogs.h" #include "calendar/gui/e-cal-ops.h" #include "calendar/gui/e-comp-editor.h" -#include "calendar/gui/e-year-view.h" #include "calendar/gui/itip-utils.h" #include "calendar/gui/print.h" @@ -31,22 +30,22 @@ #include "e-cal-shell-view-private.h" #include "e-cal-shell-view.h" -/* This is for radio action groups whose value is persistent. We - * initialize it to a bogus value to ensure a "changed" signal is - * emitted when a valid value is restored. */ -#define BOGUS_INITIAL_VALUE G_MININT - static void -action_calendar_copy_cb (GtkAction *action, - EShellView *shell_view) +action_calendar_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; + e_cal_base_shell_view_copy_calendar (shell_view); } static void -action_calendar_delete_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalBaseShellSidebar *cal_shell_sidebar; EShellWindow *shell_window; EShellView *shell_view; @@ -86,33 +85,41 @@ action_calendar_delete_cb (GtkAction *action, } static void -action_calendar_go_back_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_go_back_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - e_cal_shell_content_move_view_range ( - cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_PREVIOUS, 0); + ECalShellView *cal_shell_view = user_data; + + e_cal_shell_content_move_view_range (cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_PREVIOUS, 0); } static void -action_calendar_go_forward_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_go_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - e_cal_shell_content_move_view_range ( - cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_NEXT, 0); + ECalShellView *cal_shell_view = user_data; + + e_cal_shell_content_move_view_range (cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_NEXT, 0); } static void -action_calendar_go_today_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_go_today_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - e_cal_shell_content_move_view_range ( - cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_TO_TODAY, 0); + ECalShellView *cal_shell_view = user_data; + + e_cal_shell_content_move_view_range (cal_shell_view->priv->cal_shell_content, E_CALENDAR_VIEW_MOVE_TO_TODAY, 0); } static void -action_calendar_jump_to_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_jump_to_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalDataModel *data_model; ECalShellContent *cal_shell_content; EShellWindow *shell_window; @@ -133,9 +140,11 @@ action_calendar_jump_to_cb (GtkAction *action, } static void -action_calendar_manage_groups_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_manage_groups_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; ESourceSelector *selector; @@ -148,9 +157,11 @@ action_calendar_manage_groups_cb (GtkAction *action, } static void -action_calendar_new_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -175,7 +186,7 @@ action_calendar_new_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title (GTK_WINDOW (dialog), _("New Calendar")); @@ -234,23 +245,31 @@ cal_shell_view_actions_print_or_preview (ECalShellView *cal_shell_view, } static void -action_calendar_print_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + cal_shell_view_actions_print_or_preview (cal_shell_view, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG); } static void -action_calendar_print_preview_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_print_preview_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + cal_shell_view_actions_print_or_preview (cal_shell_view, GTK_PRINT_OPERATION_ACTION_PREVIEW); } static void -action_calendar_properties_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_properties_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ECalBaseShellSidebar *cal_shell_sidebar; @@ -281,7 +300,7 @@ action_calendar_properties_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title (GTK_WINDOW (dialog), _("Calendar Properties")); @@ -290,9 +309,11 @@ action_calendar_properties_cb (GtkAction *action, } static void -action_calendar_purge_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_purge_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ECalShellContent *cal_shell_content; @@ -362,9 +383,11 @@ action_calendar_purge_cb (GtkAction *action, } static void -action_calendar_refresh_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_refresh_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalBaseShellSidebar *cal_shell_sidebar; ESourceSelector *selector; EClient *client = NULL; @@ -392,9 +415,11 @@ action_calendar_refresh_cb (GtkAction *action, } static void -action_calendar_refresh_backend_cb (GtkAction *action, - EShellView *shell_view) +action_calendar_refresh_backend_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; ESource *source; g_return_if_fail (E_IS_CAL_SHELL_VIEW (shell_view)); @@ -406,9 +431,11 @@ action_calendar_refresh_backend_cb (GtkAction *action, } static void -action_calendar_rename_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_rename_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalBaseShellSidebar *cal_shell_sidebar; ESourceSelector *selector; @@ -419,30 +446,41 @@ action_calendar_rename_cb (GtkAction *action, } static void -action_calendar_search_next_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_search_next_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + e_cal_shell_view_search_events (cal_shell_view, TRUE); } static void -action_calendar_search_prev_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_search_prev_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + e_cal_shell_view_search_events (cal_shell_view, FALSE); } static void -action_calendar_search_stop_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_search_stop_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + e_cal_shell_view_search_stop (cal_shell_view); } static void -action_calendar_select_all_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_select_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalBaseShellSidebar *cal_shell_sidebar; ESourceSelector *selector; @@ -453,9 +491,11 @@ action_calendar_select_all_cb (GtkAction *action, } static void -action_calendar_select_one_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_select_one_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalBaseShellSidebar *cal_shell_sidebar; ESourceSelector *selector; ESource *primary; @@ -472,16 +512,19 @@ action_calendar_select_one_cb (GtkAction *action, } static void -action_calendar_view_cb (GtkRadioAction *action, - GtkRadioAction *current, - ECalShellView *cal_shell_view) +action_calendar_view_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; ECalViewKind view_kind; const gchar *view_id; + e_ui_action_set_state (action, parameter); + shell_view = E_SHELL_VIEW (cal_shell_view); - view_kind = gtk_radio_action_get_current_value (action); + view_kind = g_variant_get_int32 (parameter); switch (view_kind) { case E_CAL_VIEW_KIND_DAY: @@ -515,30 +558,6 @@ action_calendar_view_cb (GtkRadioAction *action, e_shell_view_set_view_id (shell_view, view_id); } -static void -action_calendar_preview_cb (GtkRadioAction *action, - GtkRadioAction *current, - ECalShellView *cal_shell_view) -{ - GtkOrientation orientation; - EYearView *year_view; - - year_view = E_YEAR_VIEW (cal_shell_view->priv->views[E_CAL_VIEW_KIND_YEAR].calendar_view); - - switch (gtk_radio_action_get_current_value (action)) { - case 0: - orientation = GTK_ORIENTATION_VERTICAL; - break; - case 1: - orientation = GTK_ORIENTATION_HORIZONTAL; - break; - default: - g_return_if_reached (); - } - - e_year_view_set_preview_orientation (year_view, orientation); -} - static void cal_shell_view_transfer_selected (ECalShellView *cal_shell_view, gboolean is_move) @@ -614,23 +633,31 @@ cal_shell_view_transfer_selected (ECalShellView *cal_shell_view, } static void -action_event_copy_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + cal_shell_view_transfer_selected (cal_shell_view, FALSE); } static void -action_event_move_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_move_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + cal_shell_view_transfer_selected (cal_shell_view, TRUE); } static void -action_event_delegate_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_delegate_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ESourceRegistry *registry; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; @@ -723,9 +750,11 @@ action_event_delegate_cb (GtkAction *action, } static void -action_event_delete_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; @@ -736,9 +765,11 @@ action_event_delete_cb (GtkAction *action, } static void -action_event_delete_occurrence_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_delete_occurrence_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; @@ -749,9 +780,11 @@ action_event_delete_occurrence_cb (GtkAction *action, } static void -action_event_delete_occurrence_this_and_future_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_delete_occurrence_this_and_future_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; @@ -762,9 +795,11 @@ action_event_delete_occurrence_this_and_future_cb (GtkAction *action, } static void -action_event_forward_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; ECalendarViewSelectionData *sel_data; @@ -795,9 +830,11 @@ action_event_forward_cb (GtkAction *action, } static void -action_event_popup_new_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; const gchar *action_name; @@ -806,9 +843,9 @@ action_event_popup_new_cb (GtkAction *action, cal_shell_content = cal_shell_view->priv->cal_shell_content; calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content); - action_name = gtk_action_get_name (action); - is_all_day = g_strcmp0 (action_name, "event-popup-all-day-new") == 0; - is_meeting = g_strcmp0 (action_name, "event-popup-meeting-new") == 0; + action_name = g_action_get_name (G_ACTION (action)); + is_all_day = g_strcmp0 (action_name, "event-all-day-new") == 0; + is_meeting = g_strcmp0 (action_name, "event-meeting-new") == 0; e_calendar_view_new_appointment (calendar_view, (is_all_day ? E_NEW_APPOINTMENT_FLAG_ALL_DAY : 0) | @@ -817,9 +854,11 @@ action_event_popup_new_cb (GtkAction *action, } static void -action_event_popup_rsvp_response_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_rsvp_response_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; ECalendarViewSelectionData *sel_data; @@ -834,16 +873,16 @@ action_event_popup_rsvp_response_cb (GtkAction *action, cal_shell_content = cal_shell_view->priv->cal_shell_content; calendar_view = e_cal_shell_content_get_current_calendar_view (cal_shell_content); - action_name = gtk_action_get_name (action); + action_name = g_action_get_name (G_ACTION (action)); - if (g_strcmp0 (action_name, "event-popup-rsvp-accept") == 0 || - g_strcmp0 (action_name, "event-popup-rsvp-accept-1") == 0) + if (g_strcmp0 (action_name, "event-rsvp-accept") == 0 || + g_strcmp0 (action_name, "event-rsvp-accept-1") == 0) partstat = I_CAL_PARTSTAT_ACCEPTED; - else if (g_strcmp0 (action_name, "event-popup-rsvp-decline") == 0 || - g_strcmp0 (action_name, "event-popup-rsvp-decline-1") == 0) + else if (g_strcmp0 (action_name, "event-rsvp-decline") == 0 || + g_strcmp0 (action_name, "event-rsvp-decline-1") == 0) partstat = I_CAL_PARTSTAT_DECLINED; - else if (g_strcmp0 (action_name, "event-popup-rsvp-tentative") == 0 || - g_strcmp0 (action_name, "event-popup-rsvp-tentative-1") == 0) + else if (g_strcmp0 (action_name, "event-rsvp-tentative") == 0 || + g_strcmp0 (action_name, "event-rsvp-tentative-1") == 0) partstat = I_CAL_PARTSTAT_TENTATIVE; else { g_warning ("%s: Do not know what to do with '%s'", G_STRFUNC, action_name); @@ -920,9 +959,11 @@ make_movable_thread (EAlertSinkThreadJobData *job_data, } static void -action_event_occurrence_movable_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_occurrence_movable_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalModel *model; ECalendarView *calendar_view; @@ -1013,9 +1054,11 @@ action_event_occurrence_movable_cb (GtkAction *action, } static void -action_event_open_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *view; @@ -1026,9 +1069,11 @@ action_event_open_cb (GtkAction *action, } static void -action_event_edit_as_new_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_edit_as_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; ECalendarViewSelectionData *sel_data; @@ -1064,9 +1109,11 @@ action_event_edit_as_new_cb (GtkAction *action, } static void -action_event_print_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalendarView *calendar_view; ECalendarViewSelectionData *sel_data; @@ -1134,23 +1181,31 @@ cal_shell_view_actions_reply (ECalShellView *cal_shell_view, } static void -action_event_reply_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_reply_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + cal_shell_view_actions_reply (cal_shell_view, FALSE); } static void -action_event_reply_all_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_reply_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + cal_shell_view_actions_reply (cal_shell_view, TRUE); } static void -action_event_save_as_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -1255,16 +1310,21 @@ edit_event_as (ECalShellView *cal_shell_view, } static void -action_event_schedule_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_schedule_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + edit_event_as (cal_shell_view, TRUE); } static void -quit_calendar_cb (GtkAction *action, - ECalShellView *cal_shell_view) +quit_calendar_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; GdkWindow *window; @@ -1284,833 +1344,593 @@ quit_calendar_cb (GtkAction *action, } static void -action_event_schedule_appointment_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_event_schedule_appointment_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + edit_event_as (cal_shell_view, FALSE); } static void -action_calendar_show_tag_vpane_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_show_tag_vpane_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; + g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view)); - e_cal_shell_content_set_show_tag_vpane (cal_shell_view->priv->cal_shell_content, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); + e_cal_shell_content_set_show_tag_vpane (cal_shell_view->priv->cal_shell_content, e_ui_action_get_active (action)); } -static GtkActionEntry calendar_entries[] = { - - { "calendar-copy", - "edit-copy", - N_("_Copy…"), - "c", - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_copy_cb) }, - - { "calendar-delete", - "edit-delete", - N_("D_elete Calendar"), - NULL, - N_("Delete the selected calendar"), - G_CALLBACK (action_calendar_delete_cb) }, - - { "calendar-go-back", - "go-previous", - N_("Previous"), - "Page_Up", - N_("Go Back"), - G_CALLBACK (action_calendar_go_back_cb) }, - - { "calendar-go-forward", - "go-next", - N_("Next"), - "Page_Down", - N_("Go Forward"), - G_CALLBACK (action_calendar_go_forward_cb) }, - - { "calendar-go-today", - "go-today", - N_("Select _Today"), - "t", - N_("Select today"), - G_CALLBACK (action_calendar_go_today_cb) }, - - { "calendar-jump-to", - "go-jump", - N_("Select _Date"), - "g", - N_("Select a specific date"), - G_CALLBACK (action_calendar_jump_to_cb) }, - - { "calendar-manage-groups", - NULL, - N_("_Manage Calendar groups…"), - NULL, - N_("Manage Calendar groups order and visibility"), - G_CALLBACK (action_calendar_manage_groups_cb) }, - - { "calendar-new", - "x-office-calendar", - N_("_New Calendar"), - NULL, - N_("Create a new calendar"), - G_CALLBACK (action_calendar_new_cb) }, - - { "calendar-properties", - "document-properties", - N_("_Properties"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_properties_cb) }, - - { "calendar-purge", - NULL, - N_("Purg_e"), - "e", - N_("Purge old appointments and meetings"), - G_CALLBACK (action_calendar_purge_cb) }, - - { "calendar-refresh", - "view-refresh", - N_("Re_fresh"), - NULL, - N_("Refresh the selected calendar"), - G_CALLBACK (action_calendar_refresh_cb) }, - - { "calendar-refresh-backend", - "view-refresh", - N_("Re_fresh list of account calendars"), - NULL, - NULL, - G_CALLBACK (action_calendar_refresh_backend_cb) }, - - { "calendar-rename", - NULL, - N_("_Rename…"), - "F2", - N_("Rename the selected calendar"), - G_CALLBACK (action_calendar_rename_cb) }, - - { "calendar-search-next", - "go-next", - N_("Find _Next"), - "n", - N_("Find next occurrence of the current search string"), - G_CALLBACK (action_calendar_search_next_cb) }, - - { "calendar-search-prev", - "go-previous", - N_("Find _Previous"), - "p", - N_("Find previous occurrence of the current search string"), - G_CALLBACK (action_calendar_search_prev_cb) }, - - { "calendar-search-stop", - "process-stop", - N_("Stop _Running Search"), - NULL, - N_("Stop currently running search"), - G_CALLBACK (action_calendar_search_stop_cb) }, - - { "calendar-select-all", - "stock_check-filled", - N_("Sho_w All Calendars"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_select_all_cb) }, - - { "calendar-select-one", - "stock_check-filled", - N_("Show _Only This Calendar"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_select_one_cb) }, - - { "event-copy", - NULL, - N_("Cop_y to Calendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_copy_cb) }, - - { "event-delegate", - NULL, - N_("_Delegate Meeting…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_delegate_cb) }, - - { "event-delete", - "edit-delete", - N_("_Delete"), - "d", - N_("Delete selected events"), - G_CALLBACK (action_event_delete_cb) }, - - { "event-delete-occurrence", - "edit-delete", - N_("Delete This _Occurrence"), - NULL, - N_("Delete this occurrence"), - G_CALLBACK (action_event_delete_occurrence_cb) }, - - { "event-delete-occurrence-this-and-future", - "edit-delete", - N_("Delete This and F_uture Occurrences"), - NULL, - N_("Delete this and any future occurrences"), - G_CALLBACK (action_event_delete_occurrence_this_and_future_cb) }, - - { "event-delete-occurrence-all", - "edit-delete", - N_("Delete All Occ_urrences"), - NULL, - N_("Delete all occurrences"), - G_CALLBACK (action_event_delete_cb) }, - - { "event-edit-as-new", - NULL, - N_("Edit as Ne_w…"), - NULL, - N_("Edit the selected event as new"), - G_CALLBACK (action_event_edit_as_new_cb) }, - - { "event-popup-all-day-new", - "stock_new-24h-appointment", - N_("New All Day _Event…"), - NULL, - N_("Create a new all day event"), - G_CALLBACK (action_event_popup_new_cb) }, - - { "event-forward", - "mail-forward", - N_("_Forward as iCalendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_forward_cb) }, - - { "event-popup-meeting-new", - "stock_people", - N_("New _Meeting…"), - NULL, - N_("Create a new meeting"), - G_CALLBACK (action_event_popup_new_cb) }, - - { "event-popup-rsvp-submenu", - NULL, - N_("Send _RSVP"), - NULL, - N_("Send a meeting response"), - NULL }, - - { "event-popup-rsvp-accept", - NULL, - N_("_Accept"), - NULL, - N_("Accept meeting request"), - G_CALLBACK (action_event_popup_rsvp_response_cb) }, - - { "event-popup-rsvp-accept-1", - NULL, - N_("A_ccept this instance"), - NULL, - N_("Accept meeting request for selected instance only"), - G_CALLBACK (action_event_popup_rsvp_response_cb) }, - - { "event-popup-rsvp-decline", - NULL, - N_("_Decline"), - NULL, - N_("Decline meeting request"), - G_CALLBACK (action_event_popup_rsvp_response_cb) }, - - { "event-popup-rsvp-decline-1", - NULL, - N_("D_ecline this instance"), - NULL, - N_("Decline meeting request for selected instance only"), - G_CALLBACK (action_event_popup_rsvp_response_cb) }, - - { "event-popup-rsvp-tentative", - NULL, - N_("_Tentatively accept"), - NULL, - N_("Tentatively accept meeting request"), - G_CALLBACK (action_event_popup_rsvp_response_cb) }, - - { "event-popup-rsvp-tentative-1", - NULL, - N_("Te_ntatively accept this instance"), - NULL, - N_("Tentatively accept meeting request for selected instance only"), - G_CALLBACK (action_event_popup_rsvp_response_cb) }, - - { "event-move", - NULL, - N_("Mo_ve to Calendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_move_cb) }, - - { "event-popup-new", - "appointment-new", - N_("New _Appointment…"), - NULL, - N_("Create a new appointment"), - G_CALLBACK (action_event_popup_new_cb) }, - - { "event-occurrence-movable", - NULL, - N_("Make this Occurrence _Movable"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_occurrence_movable_cb) }, - - { "event-open", - "document-open", - N_("_Open…"), - "o", - N_("Edit the selected event"), - G_CALLBACK (action_event_open_cb) }, - - { "event-reply", - "mail-reply-sender", - N_("_Reply"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_reply_cb) }, - - { "event-reply-all", - "mail-reply-all", - N_("Reply to _All"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_reply_all_cb) }, - - { "event-schedule", - NULL, - N_("_Schedule Meeting…"), - NULL, - N_("Converts an appointment to a meeting"), - G_CALLBACK (action_event_schedule_cb) }, - - { "event-schedule-appointment", - NULL, - N_("Conv_ert to Appointment…"), - NULL, - N_("Converts a meeting to an appointment"), - G_CALLBACK (action_event_schedule_appointment_cb) }, - - { "quit-calendar", - "window-close", - N_("Quit"), - "w", - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (quit_calendar_cb) }, - - /*** Menus ***/ - - { "calendar-actions-menu", - NULL, - N_("_Actions"), - NULL, - NULL, - NULL }, - - { "calendar-preview-menu", - NULL, - N_("_Preview"), - NULL, - NULL, - NULL } -}; - -static EPopupActionEntry calendar_popup_entries[] = { - - /* FIXME No equivalent main menu items for the any of the calendar - * popup menu items and for many of the event popup menu items. - * This is an accessibility issue. */ - - { "calendar-popup-copy", - NULL, - "calendar-copy" }, - - { "calendar-popup-delete", - N_("_Delete"), - "calendar-delete" }, - - { "calendar-popup-go-today", - NULL, - "calendar-go-today" }, - - { "calendar-popup-jump-to", - NULL, - "calendar-jump-to" }, - - { "calendar-popup-manage-groups", - N_("_Manage groups…"), - "calendar-manage-groups" }, - - { "calendar-popup-properties", - NULL, - "calendar-properties" }, - - { "calendar-popup-refresh", - NULL, - "calendar-refresh" }, - - { "calendar-popup-refresh-backend", - NULL, - "calendar-refresh-backend" }, - - { "calendar-popup-rename", - NULL, - "calendar-rename" }, - - { "calendar-popup-select-all", - NULL, - "calendar-select-all" }, - - { "calendar-popup-select-one", - NULL, - "calendar-select-one" }, - - { "event-popup-copy", - NULL, - "event-copy" }, - - { "event-popup-delegate", - NULL, - "event-delegate" }, - - { "event-popup-delete", - NULL, - "event-delete" }, - - { "event-popup-delete-occurrence", - NULL, - "event-delete-occurrence" }, - - { "event-popup-delete-occurrence-this-and-future", - NULL, - "event-delete-occurrence-this-and-future" }, - - { "event-popup-delete-occurrence-all", - NULL, - "event-delete-occurrence-all" }, - - { "event-popup-edit-as-new", - NULL, - "event-edit-as-new" }, - - { "event-popup-forward", - NULL, - "event-forward" }, - - { "event-popup-move", - NULL, - "event-move" }, - - { "event-popup-occurrence-movable", - NULL, - "event-occurrence-movable" }, - - { "event-popup-open", - NULL, - "event-open" }, - - { "event-popup-reply", - NULL, - "event-reply" }, - - { "event-popup-reply-all", - NULL, - "event-reply-all" }, - - { "event-popup-schedule", - NULL, - "event-schedule" }, - - { "event-popup-schedule-appointment", - NULL, - "event-schedule-appointment" } -}; - -static GtkToggleActionEntry calendar_toggle_entries[] = { - - { "calendar-preview", - NULL, - N_("Show Event _Preview"), - NULL, - N_("Show event preview pane"), - NULL, /* Handled by property bindings */ - TRUE }, - - { "calendar-show-tag-vpane", - NULL, - N_("Show T_asks and Memos pane"), - NULL, - N_("Show Tasks and Memos pane"), - G_CALLBACK (action_calendar_show_tag_vpane_cb), - TRUE } -}; - -static GtkRadioActionEntry calendar_view_entries[] = { - - /* This action represents the initial calendar view. - * It should not be visible in the UI, nor should it be - * possible to switch to it from another calendar view. */ - { "calendar-view-initial", - NULL, - NULL, - NULL, - NULL, - BOGUS_INITIAL_VALUE }, - - { "calendar-view-day", - "view-calendar-day", - N_("Day"), - "y", - N_("Show one day"), - E_CAL_VIEW_KIND_DAY }, - - { "calendar-view-list", - "view-calendar-list", - N_("List"), - "l", - N_("Show as list"), - E_CAL_VIEW_KIND_LIST }, - - { "calendar-view-month", - "view-calendar-month", - N_("Month"), - "m", - N_("Show one month"), - E_CAL_VIEW_KIND_MONTH }, - - { "calendar-view-week", - "view-calendar-week", - N_("Week"), - "k", - N_("Show one week"), - E_CAL_VIEW_KIND_WEEK }, - - { "calendar-view-workweek", - "view-calendar-workweek", - N_("Work Week"), - "j", - N_("Show one work week"), - E_CAL_VIEW_KIND_WORKWEEK }, - - { "calendar-view-year", - "view-calendar-year", - N_("Year"), - NULL, - N_("Show as year"), - E_CAL_VIEW_KIND_YEAR } -}; - -static GtkRadioActionEntry calendar_preview_entries[] = { - - /* This action represents the initial active preview. - * It should not be visible in the UI, nor should it be - * possible to switch to it from another shell view. */ - { "calendar-preview-initial", - NULL, - NULL, - NULL, - NULL, - BOGUS_INITIAL_VALUE }, - - { "calendar-preview-horizontal", - NULL, - N_("_Horizontal View"), - NULL, - N_("Show event preview below the calendar"), - 0 }, - - { "calendar-preview-vertical", - NULL, - N_("_Vertical View"), - NULL, - N_("Show event preview alongside the calendar"), - 1 } -}; - -static GtkRadioActionEntry calendar_filter_entries[] = { - - { "calendar-filter-active-appointments", - NULL, - N_("Active Appointments"), - NULL, - NULL, /* XXX Add a tooltip! */ - CALENDAR_FILTER_ACTIVE_APPOINTMENTS }, - - { "calendar-filter-any-category", - NULL, - N_("Any Category"), - NULL, - NULL, /* XXX Add a tooltip! */ - CALENDAR_FILTER_ANY_CATEGORY }, - - { "calendar-filter-next-7-days-appointments", - NULL, - N_("Next 7 Days’ Appointments"), - NULL, - NULL, /* XXX Add a tooltip! */ - CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS }, - - { "calendar-filter-occurs-less-than-5-times", - NULL, - N_("Occurs Less Than 5 Times"), - NULL, - NULL, /* XXX Add a tooltip! */ - CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES }, - - { "calendar-filter-unmatched", - NULL, - N_("Without Category"), - NULL, - N_("Show events with no category set"), - CALENDAR_FILTER_UNMATCHED } -}; - -static GtkRadioActionEntry calendar_search_entries[] = { - - { "calendar-search-advanced-hidden", - NULL, - N_("Advanced Search"), - NULL, - NULL, - CALENDAR_SEARCH_ADVANCED }, - - { "calendar-search-any-field-contains", - NULL, - N_("Any field contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - CALENDAR_SEARCH_ANY_FIELD_CONTAINS }, - - { "calendar-search-description-contains", - NULL, - N_("Description contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - CALENDAR_SEARCH_DESCRIPTION_CONTAINS }, - - { "calendar-search-summary-contains", - NULL, - N_("Summary contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - CALENDAR_SEARCH_SUMMARY_CONTAINS } -}; - -static GtkActionEntry lockdown_printing_entries[] = { - - { "calendar-print", - "document-print", - N_("Print…"), - "p", - N_("Print this calendar"), - G_CALLBACK (action_calendar_print_cb) }, - - { "calendar-print-preview", - "document-print-preview", - N_("Pre_view…"), - NULL, - N_("Preview the calendar to be printed"), - G_CALLBACK (action_calendar_print_preview_cb) }, - - { "event-print", - "document-print", - N_("Print…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_print_cb) } -}; - -static EPopupActionEntry lockdown_printing_popup_entries[] = { - - { "event-popup-print", - NULL, - "event-print" } -}; - -static GtkActionEntry lockdown_save_to_disk_entries[] = { - - { "event-save-as", - "document-save-as", - N_("_Save as iCalendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_event_save_as_cb) }, -}; - -static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = { - - { "event-popup-save-as", - NULL, - "event-save-as" }, -}; - void -e_cal_shell_view_actions_init (ECalShellView *cal_shell_view) +e_cal_shell_view_actions_init (ECalShellView *self) { - ECalShellContent *cal_shell_content; + static const EUIActionEntry calendar_entries[] = { + + { "calendar-copy", + "edit-copy", + N_("_Copy…"), + NULL, + NULL, + action_calendar_copy_cb, NULL, NULL, NULL }, + + { "calendar-delete", + "edit-delete", + N_("D_elete Calendar"), + NULL, + N_("Delete the selected calendar"), + action_calendar_delete_cb, NULL, NULL, NULL }, + + { "calendar-go-back", + "go-previous", + N_("Previous"), + "Page_Up", + N_("Go Back"), + action_calendar_go_back_cb, NULL, NULL, NULL }, + + { "calendar-go-forward", + "go-next", + N_("Next"), + "Page_Down", + N_("Go Forward"), + action_calendar_go_forward_cb, NULL, NULL, NULL }, + + { "calendar-go-today", + "go-today", + N_("Select _Today"), + "t", + N_("Select today"), + action_calendar_go_today_cb, NULL, NULL, NULL }, + + { "calendar-jump-to", + "go-jump", + N_("Select _Date"), + "g", + N_("Select a specific date"), + action_calendar_jump_to_cb, NULL, NULL, NULL }, + + { "calendar-manage-groups", + NULL, + N_("_Manage Calendar groups…"), + NULL, + N_("Manage Calendar groups order and visibility"), + action_calendar_manage_groups_cb, NULL, NULL, NULL }, + + { "calendar-manage-groups-popup", + NULL, + N_("_Manage groups…"), + NULL, + N_("Manage Calendar groups order and visibility"), + action_calendar_manage_groups_cb, NULL, NULL, NULL }, + + { "calendar-new", + "x-office-calendar", + N_("_New Calendar"), + NULL, + N_("Create a new calendar"), + action_calendar_new_cb, NULL, NULL, NULL }, + + { "calendar-properties", + "document-properties", + N_("_Properties"), + NULL, + NULL, + action_calendar_properties_cb, NULL, NULL, NULL }, + + { "calendar-purge", + NULL, + N_("Purg_e"), + "e", + N_("Purge old appointments and meetings"), + action_calendar_purge_cb, NULL, NULL, NULL }, + + { "calendar-refresh", + "view-refresh", + N_("Re_fresh"), + NULL, + N_("Refresh the selected calendar"), + action_calendar_refresh_cb, NULL, NULL, NULL }, + + { "calendar-refresh-backend", + "view-refresh", + N_("Re_fresh list of account calendars"), + NULL, + NULL, + action_calendar_refresh_backend_cb, NULL, NULL, NULL }, + + { "calendar-rename", + NULL, + N_("_Rename…"), + NULL, + N_("Rename the selected calendar"), + action_calendar_rename_cb, NULL, NULL, NULL }, + + { "calendar-search-next", + "go-next", + N_("Find _Next"), + "n", + N_("Find next occurrence of the current search string"), + action_calendar_search_next_cb, NULL, NULL, NULL }, + + { "calendar-search-prev", + "go-previous", + N_("Find _Previous"), + "p", + N_("Find previous occurrence of the current search string"), + action_calendar_search_prev_cb, NULL, NULL, NULL }, + + { "calendar-search-stop", + "process-stop", + N_("Stop _Running Search"), + NULL, + N_("Stop currently running search"), + action_calendar_search_stop_cb, NULL, NULL, NULL }, + + { "calendar-select-all", + "stock_check-filled", + N_("Sho_w All Calendars"), + NULL, + NULL, + action_calendar_select_all_cb, NULL, NULL, NULL }, + + { "calendar-select-one", + "stock_check-filled", + N_("Show _Only This Calendar"), + NULL, + NULL, + action_calendar_select_one_cb, NULL, NULL, NULL }, + + { "event-copy", + NULL, + N_("Cop_y to Calendar…"), + NULL, + NULL, + action_event_copy_cb, NULL, NULL, NULL }, + + { "event-delegate", + NULL, + N_("_Delegate Meeting…"), + NULL, + NULL, + action_event_delegate_cb, NULL, NULL, NULL }, + + { "event-delete", + "edit-delete", + N_("_Delete"), + "d", + N_("Delete selected events"), + action_event_delete_cb, NULL, NULL, NULL }, + + { "event-delete-occurrence", + "edit-delete", + N_("Delete This _Occurrence"), + NULL, + N_("Delete this occurrence"), + action_event_delete_occurrence_cb, NULL, NULL, NULL }, + + { "event-delete-occurrence-this-and-future", + "edit-delete", + N_("Delete This and F_uture Occurrences"), + NULL, + N_("Delete this and any future occurrences"), + action_event_delete_occurrence_this_and_future_cb, NULL, NULL, NULL }, + + { "event-delete-occurrence-all", + "edit-delete", + N_("Delete All Occ_urrences"), + NULL, + N_("Delete all occurrences"), + action_event_delete_cb, NULL, NULL, NULL }, + + { "event-edit-as-new", + NULL, + N_("Edit as Ne_w…"), + NULL, + N_("Edit the selected event as new"), + action_event_edit_as_new_cb, NULL, NULL, NULL }, + + { "event-all-day-new", + "stock_new-24h-appointment", + N_("New All Day _Event…"), + NULL, + N_("Create a new all day event"), + action_event_new_cb, NULL, NULL, NULL }, + + { "event-forward", + "mail-forward", + N_("_Forward as iCalendar…"), + NULL, + NULL, + action_event_forward_cb, NULL, NULL, NULL }, + + { "event-meeting-new", + "stock_people", + N_("New _Meeting…"), + NULL, + N_("Create a new meeting"), + action_event_new_cb, NULL, NULL, NULL }, + + { "event-rsvp-accept", + NULL, + N_("_Accept"), + NULL, + N_("Accept meeting request"), + action_event_rsvp_response_cb, NULL, NULL, NULL }, + + { "event-rsvp-accept-1", + NULL, + N_("A_ccept this instance"), + NULL, + N_("Accept meeting request for selected instance only"), + action_event_rsvp_response_cb, NULL, NULL, NULL }, + + { "event-rsvp-decline", + NULL, + N_("_Decline"), + NULL, + N_("Decline meeting request"), + action_event_rsvp_response_cb, NULL, NULL, NULL }, + + { "event-rsvp-decline-1", + NULL, + N_("D_ecline this instance"), + NULL, + N_("Decline meeting request for selected instance only"), + action_event_rsvp_response_cb, NULL, NULL, NULL }, + + { "event-rsvp-tentative", + NULL, + N_("_Tentatively accept"), + NULL, + N_("Tentatively accept meeting request"), + action_event_rsvp_response_cb, NULL, NULL, NULL }, + + { "event-rsvp-tentative-1", + NULL, + N_("Te_ntatively accept this instance"), + NULL, + N_("Tentatively accept meeting request for selected instance only"), + action_event_rsvp_response_cb, NULL, NULL, NULL }, + + { "event-move", + NULL, + N_("Mo_ve to Calendar…"), + NULL, + NULL, + action_event_move_cb, NULL, NULL, NULL }, + + { "event-new", + "appointment-new", + N_("New _Appointment…"), + NULL, + N_("Create a new appointment"), + action_event_new_cb, NULL, NULL, NULL }, + + { "event-occurrence-movable", + NULL, + N_("Make this Occurrence _Movable"), + NULL, + NULL, + action_event_occurrence_movable_cb, NULL, NULL, NULL }, + + { "event-open", + "document-open", + N_("_Open…"), + "o", + N_("Edit the selected event"), + action_event_open_cb, NULL, NULL, NULL }, + + { "event-reply", + "mail-reply-sender", + N_("_Reply"), + NULL, + NULL, + action_event_reply_cb, NULL, NULL, NULL }, + + { "event-reply-all", + "mail-reply-all", + N_("Reply to _All"), + NULL, + NULL, + action_event_reply_all_cb, NULL, NULL, NULL }, + + { "event-schedule", + NULL, + N_("_Schedule Meeting…"), + NULL, + N_("Converts an appointment to a meeting"), + action_event_schedule_cb, NULL, NULL, NULL }, + + { "event-schedule-appointment", + NULL, + N_("Conv_ert to Appointment…"), + NULL, + N_("Converts a meeting to an appointment"), + action_event_schedule_appointment_cb, NULL, NULL, NULL }, + + { "quit-calendar", + "window-close", + N_("Quit"), + "w", + NULL, + quit_calendar_cb, NULL, NULL, NULL }, + + { "calendar-preview", + NULL, + N_("Event _Preview"), + NULL, + N_("Show event preview pane"), + NULL, NULL, "true", NULL }, /* Handled by property bindings */ + + { "calendar-show-tag-vpane", + NULL, + N_("Show T_asks and Memos pane"), + NULL, + N_("Show Tasks and Memos pane"), + action_calendar_show_tag_vpane_cb, NULL, "true", NULL }, + + /*** Menus ***/ + + { "calendar-actions-menu", NULL, N_("_Actions"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "calendar-preview-menu", NULL, N_("_Preview"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "event-rsvp-submenu", NULL, N_("Send _RSVP"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "ECalShellView::navigation-buttons", NULL, N_("Navigation buttons"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + + static const EUIActionEnumEntry calendar_view_entries[] = { + + { "calendar-view-day", + "view-calendar-day", + N_("Day"), + "y", + N_("Show one day"), + action_calendar_view_cb, E_CAL_VIEW_KIND_DAY }, + + { "calendar-view-list", + "view-calendar-list", + N_("List"), + "l", + N_("Show as list"), + action_calendar_view_cb, E_CAL_VIEW_KIND_LIST }, + + { "calendar-view-month", + "view-calendar-month", + N_("Month"), + "m", + N_("Show one month"), + action_calendar_view_cb, E_CAL_VIEW_KIND_MONTH }, + + { "calendar-view-week", + "view-calendar-week", + N_("Week"), + "k", + N_("Show one week"), + action_calendar_view_cb, E_CAL_VIEW_KIND_WEEK }, + + { "calendar-view-workweek", + "view-calendar-workweek", + N_("Work Week"), + "j", + N_("Show one work week"), + action_calendar_view_cb, E_CAL_VIEW_KIND_WORKWEEK }, + + { "calendar-view-year", + "view-calendar-year", + N_("Year"), + NULL, + N_("Show as year"), + action_calendar_view_cb, E_CAL_VIEW_KIND_YEAR } + }; + + static const EUIActionEnumEntry calendar_preview_entries[] = { + + { "calendar-preview-horizontal", + NULL, + N_("_Classic View"), + NULL, + N_("Show event preview below the calendar"), + NULL, 0 }, + + { "calendar-preview-vertical", + NULL, + N_("_Vertical View"), + NULL, + N_("Show event preview alongside the calendar"), + NULL, 1 } + }; + + static const EUIActionEnumEntry calendar_search_entries[] = { + + { "calendar-search-advanced-hidden", + NULL, + N_("Advanced Search"), + NULL, + NULL, + NULL, CALENDAR_SEARCH_ADVANCED }, + + { "calendar-search-any-field-contains", + NULL, + N_("Any field contains"), + NULL, + NULL, + NULL, CALENDAR_SEARCH_ANY_FIELD_CONTAINS }, + + { "calendar-search-description-contains", + NULL, + N_("Description contains"), + NULL, + NULL, + NULL, CALENDAR_SEARCH_DESCRIPTION_CONTAINS }, + + { "calendar-search-summary-contains", + NULL, + N_("Summary contains"), + NULL, + NULL, + NULL, CALENDAR_SEARCH_SUMMARY_CONTAINS } + }; + + static const EUIActionEntry lockdown_printing_entries[] = { + + { "calendar-print", + "document-print", + N_("Print…"), + "p", + N_("Print this calendar"), + action_calendar_print_cb, NULL, NULL, NULL }, + + { "calendar-print-preview", + "document-print-preview", + N_("Pre_view…"), + NULL, + N_("Preview the calendar to be printed"), + action_calendar_print_preview_cb, NULL, NULL, NULL }, + + { "event-print", + "document-print", + N_("Print…"), + NULL, + NULL, + action_event_print_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry lockdown_save_to_disk_entries[] = { + + { "event-save-as", + "document-save-as", + N_("_Save as iCalendar…"), + NULL, + NULL, + action_event_save_as_cb, NULL, NULL, NULL }, + }; + EShellView *shell_view; - EShellWindow *shell_window; - EShellSearchbar *searchbar; - GtkActionGroup *action_group; - GtkAction *action; - GSettings *settings; + EUIManager *ui_manager; - shell_view = E_SHELL_VIEW (cal_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - - cal_shell_content = cal_shell_view->priv->cal_shell_content; - searchbar = e_cal_shell_content_get_searchbar (cal_shell_content); + shell_view = E_SHELL_VIEW (self); + ui_manager = e_shell_view_get_ui_manager (shell_view); /* Calendar Actions */ - action_group = ACTION_GROUP (CALENDAR); - gtk_action_group_add_actions ( - action_group, calendar_entries, - G_N_ELEMENTS (calendar_entries), cal_shell_view); - e_action_group_add_popup_actions ( - action_group, calendar_popup_entries, - G_N_ELEMENTS (calendar_popup_entries)); - gtk_action_group_add_toggle_actions ( - action_group, calendar_toggle_entries, - G_N_ELEMENTS (calendar_toggle_entries), cal_shell_view); - gtk_action_group_add_radio_actions ( - action_group, calendar_view_entries, - G_N_ELEMENTS (calendar_view_entries), BOGUS_INITIAL_VALUE, - G_CALLBACK (action_calendar_view_cb), cal_shell_view); - gtk_action_group_add_radio_actions ( - action_group, calendar_preview_entries, - G_N_ELEMENTS (calendar_preview_entries), BOGUS_INITIAL_VALUE, - G_CALLBACK (action_calendar_preview_cb), cal_shell_view); - gtk_action_group_add_radio_actions ( - action_group, calendar_search_entries, - G_N_ELEMENTS (calendar_search_entries), - -1, NULL, NULL); - - /* Advanced Search Action */ - action = ACTION (CALENDAR_SEARCH_ADVANCED_HIDDEN); - gtk_action_set_visible (action, FALSE); - if (searchbar) - e_shell_searchbar_set_search_option ( - searchbar, GTK_RADIO_ACTION (action)); + e_ui_manager_add_actions (ui_manager, "calendar", NULL, + calendar_entries, G_N_ELEMENTS (calendar_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "calendar", NULL, + calendar_view_entries, G_N_ELEMENTS (calendar_view_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "calendar", NULL, + calendar_preview_entries, G_N_ELEMENTS (calendar_preview_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "calendar", NULL, + calendar_search_entries, G_N_ELEMENTS (calendar_search_entries), self); /* Lockdown Printing Actions */ - action_group = ACTION_GROUP (LOCKDOWN_PRINTING); - gtk_action_group_add_actions ( - action_group, lockdown_printing_entries, - G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view); - e_action_group_add_popup_actions ( - action_group, lockdown_printing_popup_entries, - G_N_ELEMENTS (lockdown_printing_popup_entries)); + e_ui_manager_add_actions (ui_manager, "lockdown-printing", NULL, + lockdown_printing_entries, G_N_ELEMENTS (lockdown_printing_entries), self); /* Lockdown Save-to-Disk Actions */ - action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK); - gtk_action_group_add_actions ( - action_group, lockdown_save_to_disk_entries, - G_N_ELEMENTS (lockdown_save_to_disk_entries), cal_shell_view); - e_action_group_add_popup_actions ( - action_group, lockdown_save_to_disk_popup_entries, - G_N_ELEMENTS (lockdown_save_to_disk_popup_entries)); - - settings = e_util_ref_settings ("org.gnome.evolution.calendar"); - - g_settings_bind ( - settings, "year-layout", - ACTION (CALENDAR_PREVIEW_VERTICAL), "current-value", - G_SETTINGS_BIND_DEFAULT); - - g_clear_object (&settings); - - /* Fine tuning. */ - - action = ACTION (CALENDAR_GO_TODAY); - gtk_action_set_short_label (action, _("Today")); - - action = ACTION (CALENDAR_JUMP_TO); - gtk_action_set_short_label (action, _("Go To")); - - action = ACTION (CALENDAR_VIEW_DAY); - gtk_action_set_is_important (action, TRUE); - - action = ACTION (CALENDAR_VIEW_LIST); - gtk_action_set_is_important (action, TRUE); - - action = ACTION (CALENDAR_VIEW_MONTH); - gtk_action_set_is_important (action, TRUE); - - action = ACTION (CALENDAR_VIEW_WEEK); - gtk_action_set_is_important (action, TRUE); - - action = ACTION (CALENDAR_VIEW_WORKWEEK); - gtk_action_set_is_important (action, TRUE); - - action = ACTION (CALENDAR_SHOW_TAG_VPANE); - g_settings_bind ( - cal_shell_view->priv->settings, "show-tag-vpane", - action, "active", - G_SETTINGS_BIND_GET); - - action = ACTION (CALENDAR_VIEW_YEAR); - gtk_action_set_is_important (action, TRUE); - - g_settings_bind ( - cal_shell_view->priv->settings, "year-show-preview", - ACTION (CALENDAR_PREVIEW), "active", - G_SETTINGS_BIND_DEFAULT); + e_ui_manager_add_actions (ui_manager, "lockdown-save-to-disk", NULL, + lockdown_save_to_disk_entries, G_N_ELEMENTS (lockdown_save_to_disk_entries), self); e_binding_bind_property ( ACTION (CALENDAR_PREVIEW), "active", - cal_shell_view->priv->views[E_CAL_VIEW_KIND_YEAR].calendar_view, "preview-visible", - G_BINDING_BIDIRECTIONAL | + ACTION (CALENDAR_PREVIEW_VERTICAL), "sensitive", G_BINDING_SYNC_CREATE); - /* Initialize the memo and task pad actions. */ - e_cal_shell_view_memopad_actions_init (cal_shell_view); - e_cal_shell_view_taskpad_actions_init (cal_shell_view); + e_binding_bind_property ( + ACTION (CALENDAR_PREVIEW), "active", + ACTION (CALENDAR_PREVIEW_HORIZONTAL), "sensitive", + G_BINDING_SYNC_CREATE); } void e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view) { + static const EUIActionEnumEntry calendar_filter_entries[] = { + + { "calendar-filter-active-appointments", + NULL, + N_("Active Appointments"), + NULL, + NULL, + NULL, CALENDAR_FILTER_ACTIVE_APPOINTMENTS }, + + { "calendar-filter-any-category", + NULL, + N_("Any Category"), + NULL, + NULL, + NULL, CALENDAR_FILTER_ANY_CATEGORY }, + + { "calendar-filter-next-7-days-appointments", + NULL, + N_("Next 7 Days’ Appointments"), + NULL, + NULL, + NULL, CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS }, + + { "calendar-filter-occurs-less-than-5-times", + NULL, + N_("Occurs Less Than 5 Times"), + NULL, + NULL, + NULL, CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES }, + + { "calendar-filter-unmatched", + NULL, + N_("Without Category"), + NULL, + N_("Show events with no category set"), + NULL, CALENDAR_FILTER_UNMATCHED } + }; + ECalShellContent *cal_shell_content; EShellView *shell_view; - EShellWindow *shell_window; EShellSearchbar *searchbar; EActionComboBox *combo_box; - GtkActionGroup *action_group; - GtkRadioAction *radio_action; + EUIActionGroup *action_group; + EUIAction *action; GList *list, *iter; - GSList *group; + GPtrArray *radio_group; gint ii; shell_view = E_SHELL_VIEW (cal_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - action_group = ACTION_GROUP (CALENDAR_FILTER); - e_action_group_remove_all_actions (action_group); + action_group = e_ui_manager_get_action_group (e_shell_view_get_ui_manager (shell_view), "calendar-filter"); + e_ui_action_group_remove_all (action_group); /* Add the standard filter actions. No callback is needed * because changes in the EActionComboBox are detected and * handled by EShellSearchbar. */ - gtk_action_group_add_radio_actions ( - action_group, calendar_filter_entries, - G_N_ELEMENTS (calendar_filter_entries), - CALENDAR_FILTER_ANY_CATEGORY, NULL, NULL); + e_ui_manager_add_actions_enum (e_shell_view_get_ui_manager (shell_view), + e_ui_action_group_get_name (action_group), NULL, + calendar_filter_entries, G_N_ELEMENTS (calendar_filter_entries), NULL); - /* Retrieve the radio group from an action we just added. */ - list = gtk_action_group_list_actions (action_group); - radio_action = GTK_RADIO_ACTION (list->data); - group = gtk_radio_action_get_group (radio_action); - g_list_free (list); + radio_group = g_ptr_array_new (); + + for (ii = 0; ii < G_N_ELEMENTS (calendar_filter_entries); ii++) { + action = e_ui_action_group_get_action (action_group, calendar_filter_entries[ii].name); + e_ui_action_set_radio_group (action, radio_group); + } /* Build the category actions. */ @@ -2118,14 +1938,14 @@ e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view) for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) { const gchar *category_name = iter->data; gchar *filename; - GtkAction *action; - gchar *action_name; + gchar action_name[128]; - action_name = g_strdup_printf ( - "calendar-filter-category-%d", ii); - radio_action = gtk_radio_action_new ( - action_name, category_name, NULL, NULL, ii); - g_free (action_name); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "calendar-filter-category-%d", ii) < sizeof (action_name)); + + action = e_ui_action_new (e_ui_action_group_get_name (action_group), action_name, NULL); + e_ui_action_set_label (action, category_name); + e_ui_action_set_state (action, g_variant_new_int32 (ii)); + e_ui_action_set_radio_group (action, radio_group); /* Convert the category icon file to a themed icon name. */ filename = e_categories_dup_icon_file_for (category_name); @@ -2139,21 +1959,16 @@ e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view) if ((cp = strrchr (basename, '.')) != NULL) *cp = '\0'; - g_object_set ( - radio_action, "icon-name", basename, NULL); + e_ui_action_set_icon_name (action, basename); g_free (basename); } g_free (filename); - gtk_radio_action_set_group (radio_action, group); - group = gtk_radio_action_get_group (radio_action); + e_ui_action_group_add (action_group, action); - /* The action group takes ownership of the action. */ - action = GTK_ACTION (radio_action); - gtk_action_group_add_action (action_group, action); - g_object_unref (radio_action); + g_object_unref (action); } g_list_free_full (list, g_free); @@ -2165,7 +1980,7 @@ e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view) e_shell_view_block_execute_search (shell_view); /* Use any action in the group; doesn't matter which. */ - e_action_combo_box_set_action (combo_box, radio_action); + e_action_combo_box_set_action (combo_box, action); ii = CALENDAR_FILTER_UNMATCHED; e_action_combo_box_add_separator_after (combo_box, ii); @@ -2175,4 +1990,6 @@ e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view) e_shell_view_unblock_execute_search (shell_view); } + + g_ptr_array_unref (radio_group); } diff --git a/src/modules/calendar/e-cal-shell-view-actions.h b/src/modules/calendar/e-cal-shell-view-actions.h index 1529a9545b..d51280418e 100644 --- a/src/modules/calendar/e-cal-shell-view-actions.h +++ b/src/modules/calendar/e-cal-shell-view-actions.h @@ -21,176 +21,170 @@ #ifndef E_CAL_SHELL_VIEW_ACTIONS_H #define E_CAL_SHELL_VIEW_ACTIONS_H -#include +#include /* Calendar Actions */ -#define E_SHELL_WINDOW_ACTION_CALENDAR_COPY(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-copy") -#define E_SHELL_WINDOW_ACTION_CALENDAR_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-delete") -#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_BACK(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-go-back") -#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-go-forward") -#define E_SHELL_WINDOW_ACTION_CALENDAR_GO_TODAY(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-go-today") -#define E_SHELL_WINDOW_ACTION_CALENDAR_JUMP_TO(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-jump-to") -#define E_SHELL_WINDOW_ACTION_CALENDAR_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-new") -#define E_SHELL_WINDOW_ACTION_CALENDAR_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-preview") -#define E_SHELL_WINDOW_ACTION_CALENDAR_PREVIEW_MENU(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-preview-menu") -#define E_SHELL_WINDOW_ACTION_CALENDAR_PREVIEW_HORIZONTAL(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-preview-horizontal") -#define E_SHELL_WINDOW_ACTION_CALENDAR_PREVIEW_VERTICAL(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-preview-vertical") -#define E_SHELL_WINDOW_ACTION_CALENDAR_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-print") -#define E_SHELL_WINDOW_ACTION_CALENDAR_PRINT_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-print-preview") -#define E_SHELL_WINDOW_ACTION_CALENDAR_PROPERTIES(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-properties") -#define E_SHELL_WINDOW_ACTION_CALENDAR_PURGE(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-purge") -#define E_SHELL_WINDOW_ACTION_CALENDAR_REFRESH(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-refresh") -#define E_SHELL_WINDOW_ACTION_CALENDAR_REFRESH_BACKEND(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-refresh-backend") -#define E_SHELL_WINDOW_ACTION_CALENDAR_RENAME(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-rename") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_PREV(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-search-prev") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_NEXT(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-search-next") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_STOP(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-search-stop") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SELECT_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-select-all") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SELECT_ONE(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-select-one") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SHOW_TAG_VPANE(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-show-tag-vpane") -#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_DAY(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-view-day") -#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_LIST(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-view-list") -#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_MONTH(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-view-month") -#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_WEEK(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-view-week") -#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_WORKWEEK(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-view-workweek") -#define E_SHELL_WINDOW_ACTION_CALENDAR_VIEW_YEAR(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-view-year") +#define E_SHELL_VIEW_ACTION_CALENDAR_COPY(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-copy") +#define E_SHELL_VIEW_ACTION_CALENDAR_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-delete") +#define E_SHELL_VIEW_ACTION_CALENDAR_GO_BACK(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-go-back") +#define E_SHELL_VIEW_ACTION_CALENDAR_GO_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-go-forward") +#define E_SHELL_VIEW_ACTION_CALENDAR_GO_TODAY(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-go-today") +#define E_SHELL_VIEW_ACTION_CALENDAR_JUMP_TO(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-jump-to") +#define E_SHELL_VIEW_ACTION_CALENDAR_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-new") +#define E_SHELL_VIEW_ACTION_CALENDAR_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-preview") +#define E_SHELL_VIEW_ACTION_CALENDAR_PREVIEW_MENU(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-preview-menu") +#define E_SHELL_VIEW_ACTION_CALENDAR_PREVIEW_HORIZONTAL(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-preview-horizontal") +#define E_SHELL_VIEW_ACTION_CALENDAR_PREVIEW_VERTICAL(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-preview-vertical") +#define E_SHELL_VIEW_ACTION_CALENDAR_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-print") +#define E_SHELL_VIEW_ACTION_CALENDAR_PRINT_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-print-preview") +#define E_SHELL_VIEW_ACTION_CALENDAR_PROPERTIES(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-properties") +#define E_SHELL_VIEW_ACTION_CALENDAR_PURGE(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-purge") +#define E_SHELL_VIEW_ACTION_CALENDAR_REFRESH(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-refresh") +#define E_SHELL_VIEW_ACTION_CALENDAR_REFRESH_BACKEND(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-refresh-backend") +#define E_SHELL_VIEW_ACTION_CALENDAR_RENAME(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-rename") +#define E_SHELL_VIEW_ACTION_CALENDAR_SEARCH_PREV(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-search-prev") +#define E_SHELL_VIEW_ACTION_CALENDAR_SEARCH_NEXT(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-search-next") +#define E_SHELL_VIEW_ACTION_CALENDAR_SEARCH_STOP(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-search-stop") +#define E_SHELL_VIEW_ACTION_CALENDAR_SELECT_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-select-all") +#define E_SHELL_VIEW_ACTION_CALENDAR_SELECT_ONE(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-select-one") +#define E_SHELL_VIEW_ACTION_CALENDAR_SHOW_TAG_VPANE(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-show-tag-vpane") +#define E_SHELL_VIEW_ACTION_CALENDAR_VIEW_DAY(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-view-day") +#define E_SHELL_VIEW_ACTION_CALENDAR_VIEW_LIST(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-view-list") +#define E_SHELL_VIEW_ACTION_CALENDAR_VIEW_MONTH(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-view-month") +#define E_SHELL_VIEW_ACTION_CALENDAR_VIEW_WEEK(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-view-week") +#define E_SHELL_VIEW_ACTION_CALENDAR_VIEW_WORKWEEK(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-view-workweek") +#define E_SHELL_VIEW_ACTION_CALENDAR_VIEW_YEAR(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-view-year") /* Event Actions */ -#define E_SHELL_WINDOW_ACTION_EVENT_DELEGATE(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-delegate") -#define E_SHELL_WINDOW_ACTION_EVENT_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-delete") -#define E_SHELL_WINDOW_ACTION_EVENT_DELETE_OCCURRENCE(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-delete-occurrence") -#define E_SHELL_WINDOW_ACTION_EVENT_DELETE_OCCURRENCE_THIS_AND_FUTURE(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-delete-occurrence-this-and-future") -#define E_SHELL_WINDOW_ACTION_EVENT_DELETE_OCCURRENCE_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-delete-occurrence-all") -#define E_SHELL_WINDOW_ACTION_EVENT_EDIT_AS_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-edit-as-new") -#define E_SHELL_WINDOW_ACTION_EVENT_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-forward") -#define E_SHELL_WINDOW_ACTION_EVENT_OPEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-open") -#define E_SHELL_WINDOW_ACTION_EVENT_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-print") -#define E_SHELL_WINDOW_ACTION_EVENT_SAVE_AS(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-save-as") -#define E_SHELL_WINDOW_ACTION_EVENT_SCHEDULE(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-schedule") -#define E_SHELL_WINDOW_ACTION_EVENT_SCHEDULE_APPOINTMENT(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-schedule-appointment") -#define E_SHELL_WINDOW_ACTION_EVENT_REPLY(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-reply") -#define E_SHELL_WINDOW_ACTION_EVENT_REPLY_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-reply-all") -#define E_SHELL_WINDOW_ACTION_EVENT_OCCURRENCE_MOVABLE(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-occurrence-movable") -#define E_SHELL_WINDOW_ACTION_EVENT_POPUP_MEETING_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-popup-meeting-new") -#define E_SHELL_WINDOW_ACTION_EVENT_POPUP_RSVP_SUBMENU(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-popup-rsvp-submenu") -#define E_SHELL_WINDOW_ACTION_EVENT_POPUP_RSVP_ACCEPT(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-popup-rsvp-accept") -#define E_SHELL_WINDOW_ACTION_EVENT_POPUP_RSVP_ACCEPT_1(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-popup-rsvp-accept-1") -#define E_SHELL_WINDOW_ACTION_EVENT_POPUP_RSVP_DECLINE(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-popup-rsvp-decline") -#define E_SHELL_WINDOW_ACTION_EVENT_POPUP_RSVP_DECLINE_1(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-popup-rsvp-decline-1") -#define E_SHELL_WINDOW_ACTION_EVENT_POPUP_RSVP_TENTATIVE(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-popup-rsvp-tentative") -#define E_SHELL_WINDOW_ACTION_EVENT_POPUP_RSVP_TENTATIVE_1(window) \ - E_SHELL_WINDOW_ACTION ((window), "event-popup-rsvp-tentative-1") +#define E_SHELL_VIEW_ACTION_EVENT_DELEGATE(view) \ + E_SHELL_VIEW_ACTION ((view), "event-delegate") +#define E_SHELL_VIEW_ACTION_EVENT_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "event-delete") +#define E_SHELL_VIEW_ACTION_EVENT_DELETE_OCCURRENCE(view) \ + E_SHELL_VIEW_ACTION ((view), "event-delete-occurrence") +#define E_SHELL_VIEW_ACTION_EVENT_DELETE_OCCURRENCE_THIS_AND_FUTURE(view) \ + E_SHELL_VIEW_ACTION ((view), "event-delete-occurrence-this-and-future") +#define E_SHELL_VIEW_ACTION_EVENT_DELETE_OCCURRENCE_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "event-delete-occurrence-all") +#define E_SHELL_VIEW_ACTION_EVENT_EDIT_AS_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "event-edit-as-new") +#define E_SHELL_VIEW_ACTION_EVENT_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "event-forward") +#define E_SHELL_VIEW_ACTION_EVENT_OPEN(view) \ + E_SHELL_VIEW_ACTION ((view), "event-open") +#define E_SHELL_VIEW_ACTION_EVENT_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "event-print") +#define E_SHELL_VIEW_ACTION_EVENT_SAVE_AS(view) \ + E_SHELL_VIEW_ACTION ((view), "event-save-as") +#define E_SHELL_VIEW_ACTION_EVENT_SCHEDULE(view) \ + E_SHELL_VIEW_ACTION ((view), "event-schedule") +#define E_SHELL_VIEW_ACTION_EVENT_SCHEDULE_APPOINTMENT(view) \ + E_SHELL_VIEW_ACTION ((view), "event-schedule-appointment") +#define E_SHELL_VIEW_ACTION_EVENT_REPLY(view) \ + E_SHELL_VIEW_ACTION ((view), "event-reply") +#define E_SHELL_VIEW_ACTION_EVENT_REPLY_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "event-reply-all") +#define E_SHELL_VIEW_ACTION_EVENT_OCCURRENCE_MOVABLE(view) \ + E_SHELL_VIEW_ACTION ((view), "event-occurrence-movable") +#define E_SHELL_VIEW_ACTION_EVENT_MEETING_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "event-meeting-new") +#define E_SHELL_VIEW_ACTION_EVENT_RSVP_SUBMENU(view) \ + E_SHELL_VIEW_ACTION ((view), "event-rsvp-submenu") +#define E_SHELL_VIEW_ACTION_EVENT_RSVP_ACCEPT(view) \ + E_SHELL_VIEW_ACTION ((view), "event-rsvp-accept") +#define E_SHELL_VIEW_ACTION_EVENT_RSVP_ACCEPT_1(view) \ + E_SHELL_VIEW_ACTION ((view), "event-rsvp-accept-1") +#define E_SHELL_VIEW_ACTION_EVENT_RSVP_DECLINE(view) \ + E_SHELL_VIEW_ACTION ((view), "event-rsvp-decline") +#define E_SHELL_VIEW_ACTION_EVENT_RSVP_DECLINE_1(view) \ + E_SHELL_VIEW_ACTION ((view), "event-rsvp-decline-1") +#define E_SHELL_VIEW_ACTION_EVENT_RSVP_TENTATIVE(view) \ + E_SHELL_VIEW_ACTION ((view), "event-rsvp-tentative") +#define E_SHELL_VIEW_ACTION_EVENT_RSVP_TENTATIVE_1(view) \ + E_SHELL_VIEW_ACTION ((view), "event-rsvp-tentative-1") /* Memo Pad Actions */ -#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-forward") -#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-new") -#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_OPEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-open") -#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_OPEN_URL(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-open-url") -#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-print") -#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_SAVE_AS(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-save-as") +#define E_SHELL_VIEW_ACTION_CALENDAR_MEMOPAD_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-memopad-forward") +#define E_SHELL_VIEW_ACTION_CALENDAR_MEMOPAD_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-memopad-new") +#define E_SHELL_VIEW_ACTION_CALENDAR_MEMOPAD_OPEN(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-memopad-open") +#define E_SHELL_VIEW_ACTION_CALENDAR_MEMOPAD_OPEN_URL(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-memopad-open-url") +#define E_SHELL_VIEW_ACTION_CALENDAR_MEMOPAD_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-memopad-print") +#define E_SHELL_VIEW_ACTION_CALENDAR_MEMOPAD_SAVE_AS(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-memopad-save-as") /* Task Pad Actions */ -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_ASSIGN(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-assign") -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-forward") -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_MARK_COMPLETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-mark-complete") -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_MARK_INCOMPLETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-mark-incomplete") -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-new") -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_OPEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-open") -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_OPEN_URL(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-open-url") -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-print") -#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_SAVE_AS(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-save-as") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_ASSIGN(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-assign") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-forward") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_MARK_COMPLETE(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-mark-complete") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_MARK_INCOMPLETE(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-mark-incomplete") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-new") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_OPEN(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-open") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_OPEN_URL(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-open-url") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-print") +#define E_SHELL_VIEW_ACTION_CALENDAR_TASKPAD_SAVE_AS(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-taskpad-save-as") /* Calendar Query Actions */ -#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_ACTIVE_APPOINTMENTS(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-filter-active-appointments") -#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_ANY_CATEGORY(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-filter-any-category") -#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-filter-next-7-days-appointments") -#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-filter-occurs-less-than-5-times") -#define E_SHELL_WINDOW_ACTION_CALENDAR_FILTER_UNMATCHED(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-filter-unmatched") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_ADVANCED_HIDDEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-search-advanced-hidden") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_ANY_FIELD_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-search-any-field-contains") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_DESCRIPTION_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-search-description-contains") -#define E_SHELL_WINDOW_ACTION_CALENDAR_SEARCH_SUMMARY_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "calendar-search-summary-contains") - -/* Action Groups */ -#define E_SHELL_WINDOW_ACTION_GROUP_CALENDAR(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "calendar") -#define E_SHELL_WINDOW_ACTION_GROUP_CALENDAR_FILTER(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "calendar-filter") +#define E_SHELL_VIEW_ACTION_CALENDAR_FILTER_ACTIVE_APPOINTMENTS(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-filter-active-appointments") +#define E_SHELL_VIEW_ACTION_CALENDAR_FILTER_ANY_CATEGORY(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-filter-any-category") +#define E_SHELL_VIEW_ACTION_CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-filter-next-7-days-appointments") +#define E_SHELL_VIEW_ACTION_CALENDAR_FILTER_OCCURS_LESS_THAN_5_TIMES(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-filter-occurs-less-than-5-times") +#define E_SHELL_VIEW_ACTION_CALENDAR_FILTER_UNMATCHED(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-filter-unmatched") +#define E_SHELL_VIEW_ACTION_CALENDAR_SEARCH_ADVANCED_HIDDEN(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-search-advanced-hidden") +#define E_SHELL_VIEW_ACTION_CALENDAR_SEARCH_ANY_FIELD_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-search-any-field-contains") +#define E_SHELL_VIEW_ACTION_CALENDAR_SEARCH_DESCRIPTION_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-search-description-contains") +#define E_SHELL_VIEW_ACTION_CALENDAR_SEARCH_SUMMARY_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "calendar-search-summary-contains") #endif /* E_CAL_SHELL_VIEW_ACTIONS_H */ diff --git a/src/modules/calendar/e-cal-shell-view-memopad.c b/src/modules/calendar/e-cal-shell-view-memopad.c index 5d2da6fce9..611201ad8d 100644 --- a/src/modules/calendar/e-cal-shell-view-memopad.c +++ b/src/modules/calendar/e-cal-shell-view-memopad.c @@ -28,9 +28,11 @@ /* Much of this file is based on e-memo-shell-view-actions.c. */ static void -action_calendar_memopad_forward_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_memopad_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; EMemoTable *memo_table; ECalModelComponent *comp_data; @@ -57,9 +59,11 @@ action_calendar_memopad_forward_cb (GtkAction *action, } static void -action_calendar_memopad_new_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_memopad_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ECalShellContent *cal_shell_content; @@ -83,9 +87,11 @@ action_calendar_memopad_new_cb (GtkAction *action, } static void -action_calendar_memopad_open_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_memopad_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; EMemoTable *memo_table; ECalModelComponent *comp_data; @@ -104,9 +110,11 @@ action_calendar_memopad_open_cb (GtkAction *action, } static void -action_calendar_memopad_open_url_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_memopad_open_url_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ECalShellContent *cal_shell_content; @@ -137,9 +145,11 @@ action_calendar_memopad_open_url_cb (GtkAction *action, } static void -action_calendar_memopad_print_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_memopad_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; EMemoTable *memo_table; ECalModelComponent *comp_data; @@ -169,9 +179,11 @@ action_calendar_memopad_print_cb (GtkAction *action, } static void -action_calendar_memopad_save_as_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_memopad_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -231,101 +243,92 @@ action_calendar_memopad_save_as_cb (GtkAction *action, g_object_unref (file); } -static GtkActionEntry calendar_memopad_entries[] = { - - { "calendar-memopad-forward", - "mail-forward", - N_("_Forward as iCalendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_memopad_forward_cb) }, - - { "calendar-memopad-new", - "stock_insert-note", - N_("New _Memo"), - NULL, - N_("Create a new memo"), - G_CALLBACK (action_calendar_memopad_new_cb) }, - - { "calendar-memopad-open", - "document-open", - N_("_Open Memo"), - "o", - N_("View the selected memo"), - G_CALLBACK (action_calendar_memopad_open_cb) }, - - { "calendar-memopad-open-url", - "applications-internet", - N_("Open _Web Page"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_memopad_open_url_cb) }, -}; - -static GtkActionEntry lockdown_printing_entries[] = { - - { "calendar-memopad-print", - "document-print", - N_("Print…"), - NULL, - N_("Print the selected memo"), - G_CALLBACK (action_calendar_memopad_print_cb) } -}; - -static GtkActionEntry lockdown_save_to_disk_entries[] = { - - { "calendar-memopad-save-as", - "document-save-as", - N_("_Save as iCalendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_memopad_save_as_cb) } -}; - void -e_cal_shell_view_memopad_actions_init (ECalShellView *cal_shell_view) +e_cal_shell_view_memopad_actions_init (ECalShellView *self) { - EShellView *shell_view; - EShellWindow *shell_window; - GtkActionGroup *action_group; + static const EUIActionEntry calendar_memopad_entries[] = { - shell_view = E_SHELL_VIEW (cal_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); + { "calendar-memopad-forward", + "mail-forward", + N_("_Forward as iCalendar…"), + NULL, + NULL, + action_calendar_memopad_forward_cb, NULL, NULL, NULL }, + + { "calendar-memopad-new", + "stock_insert-note", + N_("New _Memo"), + NULL, + N_("Create a new memo"), + action_calendar_memopad_new_cb, NULL, NULL, NULL }, + + { "calendar-memopad-open", + "document-open", + N_("_Open Memo"), + "o", + N_("View the selected memo"), + action_calendar_memopad_open_cb, NULL, NULL, NULL }, + + { "calendar-memopad-open-url", + "applications-internet", + N_("Open _Web Page"), + NULL, + NULL, + action_calendar_memopad_open_url_cb, NULL, NULL, NULL }, + }; + + static const EUIActionEntry lockdown_printing_entries[] = { + + { "calendar-memopad-print", + "document-print", + N_("Print…"), + NULL, + N_("Print the selected memo"), + action_calendar_memopad_print_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry lockdown_save_to_disk_entries[] = { + + { "calendar-memopad-save-as", + "document-save-as", + N_("_Save as iCalendar…"), + NULL, + NULL, + action_calendar_memopad_save_as_cb, NULL, NULL, NULL } + }; + + EShellView *shell_view; + EUIManager *ui_manager; + + shell_view = E_SHELL_VIEW (self); + ui_manager = e_shell_view_get_ui_manager (shell_view); /* Calendar Actions */ - action_group = ACTION_GROUP (CALENDAR); - gtk_action_group_add_actions ( - action_group, calendar_memopad_entries, - G_N_ELEMENTS (calendar_memopad_entries), cal_shell_view); + e_ui_manager_add_actions (ui_manager, "calendar", NULL, + calendar_memopad_entries, G_N_ELEMENTS (calendar_memopad_entries), self); /* Lockdown Printing Actions */ - action_group = ACTION_GROUP (LOCKDOWN_PRINTING); - gtk_action_group_add_actions ( - action_group, lockdown_printing_entries, - G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view); + e_ui_manager_add_actions (ui_manager, "lockdown-printing", NULL, + lockdown_printing_entries, G_N_ELEMENTS (lockdown_printing_entries), self); /* Lockdown Save-to-Disk Actions */ - action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK); - gtk_action_group_add_actions ( - action_group, lockdown_save_to_disk_entries, - G_N_ELEMENTS (lockdown_save_to_disk_entries), cal_shell_view); + e_ui_manager_add_actions (ui_manager, "lockdown-save-to-disk", NULL, + lockdown_save_to_disk_entries, G_N_ELEMENTS (lockdown_save_to_disk_entries), self); } void e_cal_shell_view_memopad_actions_update (ECalShellView *cal_shell_view) { ECalShellContent *cal_shell_content; - EShellWindow *shell_window; EShellView *shell_view; EMemoTable *memo_table; - GtkAction *action; + EUIAction *action; GSList *list, *iter; gboolean has_url = FALSE; gboolean sensitive; gint n_selected; shell_view = E_SHELL_VIEW (cal_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); cal_shell_content = cal_shell_view->priv->cal_shell_content; memo_table = e_cal_shell_content_get_memo_table (cal_shell_content); @@ -342,23 +345,23 @@ e_cal_shell_view_memopad_actions_update (ECalShellView *cal_shell_view) action = ACTION (CALENDAR_MEMOPAD_FORWARD); sensitive = (n_selected == 1); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_MEMOPAD_OPEN); sensitive = (n_selected == 1); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_MEMOPAD_OPEN_URL); sensitive = (n_selected == 1) && has_url; - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_MEMOPAD_PRINT); sensitive = (n_selected == 1); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_MEMOPAD_SAVE_AS); sensitive = (n_selected == 1); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); } void diff --git a/src/modules/calendar/e-cal-shell-view-private.c b/src/modules/calendar/e-cal-shell-view-private.c index 0efaa6cd00..027d2444bd 100644 --- a/src/modules/calendar/e-cal-shell-view-private.c +++ b/src/modules/calendar/e-cal-shell-view-private.c @@ -21,7 +21,8 @@ #include "evolution-config.h" #include "e-util/e-util-private.h" -#include +#include "calendar/gui/e-cal-ops.h" +#include "calendar/gui/e-year-view.h" #include "e-cal-shell-view-private.h" @@ -83,9 +84,9 @@ cal_shell_view_popup_event_cb (EShellView *shell_view, g_slist_free_full (selected, e_calendar_view_selection_data_free); if (n_selected <= 0) - widget_path = "/calendar-empty-popup"; + widget_path = "calendar-empty-popup"; else - widget_path = "/calendar-event-popup"; + widget_path = "calendar-event-popup"; e_cal_base_shell_view_show_popup_menu (shell_view, widget_path, button_event, NULL); } @@ -95,7 +96,7 @@ cal_shell_view_selector_popup_event_cb (EShellView *shell_view, ESource *clicked_source, GdkEvent *button_event) { - e_cal_base_shell_view_show_popup_menu (shell_view, "/calendar-popup", button_event, clicked_source); + e_cal_base_shell_view_show_popup_menu (shell_view, "calendar-popup", button_event, clicked_source); return TRUE; } @@ -106,7 +107,7 @@ cal_shell_view_memopad_popup_event_cb (EShellView *shell_view, { e_cal_shell_view_memopad_actions_update (E_CAL_SHELL_VIEW (shell_view)); - e_cal_base_shell_view_show_popup_menu (shell_view, "/calendar-memopad-popup", button_event, NULL); + e_cal_base_shell_view_show_popup_menu (shell_view, "calendar-memopad-popup", button_event, NULL); } static void @@ -115,7 +116,7 @@ cal_shell_view_taskpad_popup_event_cb (EShellView *shell_view, { e_cal_shell_view_taskpad_actions_update (E_CAL_SHELL_VIEW (shell_view)); - e_cal_base_shell_view_show_popup_menu (shell_view, "/calendar-taskpad-popup", button_event, NULL); + e_cal_base_shell_view_show_popup_menu (shell_view, "calendar-taskpad-popup", button_event, NULL); } static void @@ -307,55 +308,6 @@ cal_shell_view_taskpad_settings_changed_cb (GSettings *settings, } } -static void -cal_shell_view_update_header_bar (ECalShellView *cal_shell_view) -{ - const gchar *items[] = { - "/main-toolbar/calendar-go-back", - "/main-toolbar/calendar-go-today", - "/main-toolbar/calendar-go-forward", - "/main-toolbar/calendar-go-forward-separator" - }; - EShellWindow *shell_window; - EShellView *shell_view; - EShellHeaderBar *shell_headerbar = NULL; - GtkWidget *widget; - GtkAction *action; - gint ii; - - shell_view = E_SHELL_VIEW (cal_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - widget = gtk_window_get_titlebar (GTK_WINDOW (shell_window)); - if (E_IS_SHELL_HEADER_BAR (widget)) - shell_headerbar = E_SHELL_HEADER_BAR (widget); - - if (shell_headerbar) - e_shell_header_bar_clear (shell_headerbar, "e-cal-shell-view"); - - if (!e_util_get_use_header_bar () || - !e_shell_view_is_active (shell_view)) - return; - - action = ACTION (CALENDAR_GO_BACK); - widget = e_header_bar_button_new (NULL, action); - gtk_widget_set_name (widget, "e-cal-shell-view-buttons"); - gtk_widget_show (widget); - - action = ACTION (CALENDAR_GO_TODAY); - e_header_bar_button_add_action (E_HEADER_BAR_BUTTON (widget), NULL, action); - - action = ACTION (CALENDAR_GO_FORWARD); - e_header_bar_button_add_action (E_HEADER_BAR_BUTTON (widget), NULL, action); - - e_header_bar_pack_end (E_HEADER_BAR (shell_headerbar), widget, 0); - - for (ii = 0; ii < G_N_ELEMENTS (items); ii++) { - widget = e_shell_window_get_managed_widget (shell_window, items[ii]); - if (widget) - gtk_widget_destroy (widget); - } -} - void e_cal_shell_view_private_init (ECalShellView *cal_shell_view) { @@ -410,6 +362,36 @@ init_timezone_monitors (ECalShellView *view) } } +static void +cal_shell_view_task_view_notify_state_cb (GObject *object, + GParamSpec *param, + gpointer user_data) +{ + GAction *action = G_ACTION (object); + ECalShellView *cal_shell_view = user_data; + EYearView *year_view; + GtkOrientation orientation; + GVariant *state; + + year_view = E_YEAR_VIEW (cal_shell_view->priv->views[E_CAL_VIEW_KIND_YEAR].calendar_view); + + state = g_action_get_state (action); + + switch (g_variant_get_int32 (state)) { + case 0: + orientation = GTK_ORIENTATION_VERTICAL; + break; + case 1: + orientation = GTK_ORIENTATION_HORIZONTAL; + break; + default: + g_return_if_reached (); + } + + e_year_view_set_preview_orientation (year_view, orientation); + g_clear_pointer (&state, g_variant_unref); +} + void e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view) { @@ -420,7 +402,10 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view) EShellWindow *shell_window; EShellView *shell_view; EShell *shell; + EShellSearchbar *searchbar; ECalendar *calendar; + EUIAction *action; + GSettings *settings; gulong handler_id; gint ii; @@ -431,9 +416,6 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view) shell_window = e_shell_view_get_shell_window (shell_view); shell = e_shell_window_get_shell (shell_window); - e_shell_window_add_action_group_full (shell_window, "calendar", "calendar"); - e_shell_window_add_action_group_full (shell_window, "calendar-filter", "calendar"); - /* Cache these to avoid lots of awkward casting. */ priv->cal_shell_backend = E_CAL_SHELL_BACKEND (g_object_ref (shell_backend)); priv->cal_shell_content = E_CAL_SHELL_CONTENT (g_object_ref (shell_content)); @@ -446,12 +428,6 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view) priv->client_cache = e_shell_get_client_cache (shell); g_object_ref (priv->client_cache); - g_signal_connect_object ( - cal_shell_view, "toggled", - G_CALLBACK (cal_shell_view_update_header_bar), - NULL, - G_CONNECT_AFTER); - handler_id = g_signal_connect ( priv->client_cache, "backend-error", G_CALLBACK (cal_shell_view_backend_error_cb), @@ -582,9 +558,57 @@ e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view) G_CALLBACK (cal_shell_view_taskpad_settings_changed_cb), cal_shell_view); init_timezone_monitors (cal_shell_view); - e_cal_shell_view_actions_init (cal_shell_view); + + /* Advanced Search Action */ + action = ACTION (CALENDAR_SEARCH_ADVANCED_HIDDEN); + e_ui_action_set_visible (action, FALSE); + searchbar = e_cal_shell_content_get_searchbar (cal_shell_view->priv->cal_shell_content); + e_shell_searchbar_set_search_option (searchbar, action); + + e_binding_bind_property ( + ACTION (CALENDAR_PREVIEW), "active", + cal_shell_view->priv->views[E_CAL_VIEW_KIND_YEAR].calendar_view, "preview-visible", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + e_cal_shell_view_update_sidebar (cal_shell_view); e_cal_shell_view_update_search_filter (cal_shell_view); + + settings = e_util_ref_settings ("org.gnome.evolution.calendar"); + + g_settings_bind ( + settings, "show-tag-vpane", + ACTION (CALENDAR_SHOW_TAG_VPANE), "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY); + + action = ACTION (CALENDAR_PREVIEW); + + g_settings_bind ( + settings, "year-show-preview", + action, "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + e_binding_bind_property ( + action, "active", + priv->views[E_CAL_VIEW_KIND_YEAR].calendar_view, "preview-visible", + G_BINDING_SYNC_CREATE); + + action = ACTION (CALENDAR_PREVIEW_VERTICAL); + + g_settings_bind_with_mapping ( + settings, "year-layout", + action, "state", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY, + e_shell_view_util_layout_to_state_cb, + e_shell_view_util_state_to_layout_cb, NULL, NULL); + + g_clear_object (&settings); + + g_signal_connect_object (action, "notify::state", + G_CALLBACK (cal_shell_view_task_view_notify_state_cb), cal_shell_view, 0); + + /* to propagate the loaded state */ + cal_shell_view_task_view_notify_state_cb (G_OBJECT (action), NULL, cal_shell_view); } void diff --git a/src/modules/calendar/e-cal-shell-view-private.h b/src/modules/calendar/e-cal-shell-view-private.h index b867115d3f..bfb7a3fdce 100644 --- a/src/modules/calendar/e-cal-shell-view-private.h +++ b/src/modules/calendar/e-cal-shell-view-private.h @@ -28,7 +28,6 @@ #include -#include #include #include @@ -46,11 +45,9 @@ #include "e-cal-shell-content.h" #include "e-cal-shell-view-actions.h" -/* Shorthand, requires a variable named "shell_window". */ +/* Shorthand, requires a variable named "shell_view". */ #define ACTION(name) \ - (E_SHELL_WINDOW_ACTION_##name (shell_window)) -#define ACTION_GROUP(name) \ - (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window)) + (E_SHELL_VIEW_ACTION_##name (shell_view)) #define CHECK_NB 5 diff --git a/src/modules/calendar/e-cal-shell-view-taskpad.c b/src/modules/calendar/e-cal-shell-view-taskpad.c index 0f495a7eac..04d8e040d6 100644 --- a/src/modules/calendar/e-cal-shell-view-taskpad.c +++ b/src/modules/calendar/e-cal-shell-view-taskpad.c @@ -28,9 +28,11 @@ /* Much of this file is based on e-task-shell-view-actions.c. */ static void -action_calendar_taskpad_assign_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_assign_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalModelComponent *comp_data; ECalModel *model; @@ -57,9 +59,11 @@ action_calendar_taskpad_assign_cb (GtkAction *action, } static void -action_calendar_taskpad_forward_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalModelComponent *comp_data; ETaskTable *task_table; @@ -86,9 +90,11 @@ action_calendar_taskpad_forward_cb (GtkAction *action, } static void -action_calendar_taskpad_mark_complete_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_mark_complete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ETaskTable *task_table; ECalModel *model; @@ -109,9 +115,11 @@ action_calendar_taskpad_mark_complete_cb (GtkAction *action, } static void -action_calendar_taskpad_mark_incomplete_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_mark_incomplete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ETaskTable *task_table; ECalModel *model; @@ -132,9 +140,11 @@ action_calendar_taskpad_mark_incomplete_cb (GtkAction *action, } static void -action_calendar_taskpad_new_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ECalShellContent *cal_shell_content; @@ -158,9 +168,11 @@ action_calendar_taskpad_new_cb (GtkAction *action, } static void -action_calendar_taskpad_open_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalModelComponent *comp_data; ETaskTable *task_table; @@ -179,9 +191,11 @@ action_calendar_taskpad_open_cb (GtkAction *action, } static void -action_calendar_taskpad_open_url_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_open_url_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ECalShellContent *cal_shell_content; @@ -211,9 +225,11 @@ action_calendar_taskpad_open_url_cb (GtkAction *action, } static void -action_calendar_taskpad_print_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; ECalShellContent *cal_shell_content; ECalModelComponent *comp_data; ETaskTable *task_table; @@ -243,9 +259,11 @@ action_calendar_taskpad_print_cb (GtkAction *action, } static void -action_calendar_taskpad_save_as_cb (GtkAction *action, - ECalShellView *cal_shell_view) +action_calendar_taskpad_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECalShellView *cal_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -304,115 +322,107 @@ action_calendar_taskpad_save_as_cb (GtkAction *action, g_object_unref (file); } -static GtkActionEntry calendar_taskpad_entries[] = { - - { "calendar-taskpad-assign", - "stock_task-assigned-to", - N_("_Assign Task"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_taskpad_assign_cb) }, - - { "calendar-taskpad-forward", - "mail-forward", - N_("_Forward as iCalendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_taskpad_forward_cb) }, - - { "calendar-taskpad-mark-complete", - NULL, - N_("_Mark as Complete"), - NULL, - N_("Mark selected tasks as complete"), - G_CALLBACK (action_calendar_taskpad_mark_complete_cb) }, - - { "calendar-taskpad-mark-incomplete", - NULL, - N_("_Mark as Incomplete"), - NULL, - N_("Mark selected tasks as incomplete"), - G_CALLBACK (action_calendar_taskpad_mark_incomplete_cb) }, - - { "calendar-taskpad-new", - "stock_task", - N_("New _Task"), - NULL, - N_("Create a new task"), - G_CALLBACK (action_calendar_taskpad_new_cb) }, - - { "calendar-taskpad-open", - "document-open", - N_("_Open Task"), - "o", - N_("View the selected task"), - G_CALLBACK (action_calendar_taskpad_open_cb) }, - - { "calendar-taskpad-open-url", - "applications-internet", - N_("Open _Web Page"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_taskpad_open_url_cb) }, -}; - -static GtkActionEntry lockdown_printing_entries[] = { - - { "calendar-taskpad-print", - "document-print", - N_("Print…"), - NULL, - N_("Print the selected task"), - G_CALLBACK (action_calendar_taskpad_print_cb) } -}; - -static GtkActionEntry lockdown_save_to_disk_entries[] = { - - { "calendar-taskpad-save-as", - "document-save-as", - N_("_Save as iCalendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_taskpad_save_as_cb) } -}; - void -e_cal_shell_view_taskpad_actions_init (ECalShellView *cal_shell_view) +e_cal_shell_view_taskpad_actions_init (ECalShellView *self) { - EShellView *shell_view; - EShellWindow *shell_window; - GtkActionGroup *action_group; + static const EUIActionEntry calendar_taskpad_entries[] = { - shell_view = E_SHELL_VIEW (cal_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); + { "calendar-taskpad-assign", + "stock_task-assigned-to", + N_("_Assign Task"), + NULL, + NULL, + action_calendar_taskpad_assign_cb, NULL, NULL, NULL }, + + { "calendar-taskpad-forward", + "mail-forward", + N_("_Forward as iCalendar…"), + NULL, + NULL, + action_calendar_taskpad_forward_cb, NULL, NULL, NULL }, + + { "calendar-taskpad-mark-complete", + NULL, + N_("_Mark as Complete"), + NULL, + N_("Mark selected tasks as complete"), + action_calendar_taskpad_mark_complete_cb, NULL, NULL, NULL }, + + { "calendar-taskpad-mark-incomplete", + NULL, + N_("_Mark as Incomplete"), + NULL, + N_("Mark selected tasks as incomplete"), + action_calendar_taskpad_mark_incomplete_cb, NULL, NULL, NULL }, + + { "calendar-taskpad-new", + "stock_task", + N_("New _Task"), + NULL, + N_("Create a new task"), + action_calendar_taskpad_new_cb, NULL, NULL, NULL }, + + { "calendar-taskpad-open", + "document-open", + N_("_Open Task"), + "o", + N_("View the selected task"), + action_calendar_taskpad_open_cb, NULL, NULL, NULL }, + + { "calendar-taskpad-open-url", + "applications-internet", + N_("Open _Web Page"), + NULL, + NULL, + action_calendar_taskpad_open_url_cb, NULL, NULL, NULL }, + }; + + static const EUIActionEntry lockdown_printing_entries[] = { + + { "calendar-taskpad-print", + "document-print", + N_("Print…"), + NULL, + N_("Print the selected task"), + action_calendar_taskpad_print_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry lockdown_save_to_disk_entries[] = { + + { "calendar-taskpad-save-as", + "document-save-as", + N_("_Save as iCalendar…"), + NULL, + NULL, + action_calendar_taskpad_save_as_cb, NULL, NULL, NULL } + }; + + EShellView *shell_view; + EUIManager *ui_manager; + + shell_view = E_SHELL_VIEW (self); + ui_manager = e_shell_view_get_ui_manager (shell_view); /* Calendar Actions */ - action_group = ACTION_GROUP (CALENDAR); - gtk_action_group_add_actions ( - action_group, calendar_taskpad_entries, - G_N_ELEMENTS (calendar_taskpad_entries), cal_shell_view); + e_ui_manager_add_actions (ui_manager, "calendar", NULL, + calendar_taskpad_entries, G_N_ELEMENTS (calendar_taskpad_entries), self); /* Lockdown Printing Actions */ - action_group = ACTION_GROUP (LOCKDOWN_PRINTING); - gtk_action_group_add_actions ( - action_group, lockdown_printing_entries, - G_N_ELEMENTS (lockdown_printing_entries), cal_shell_view); + e_ui_manager_add_actions (ui_manager, "lockdown-printing", NULL, + lockdown_printing_entries, G_N_ELEMENTS (lockdown_printing_entries), self); /* Lockdown Save-to-Disk Actions */ - action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK); - gtk_action_group_add_actions ( - action_group, lockdown_save_to_disk_entries, - G_N_ELEMENTS (lockdown_save_to_disk_entries), cal_shell_view); + e_ui_manager_add_actions (ui_manager, "lockdown-save-to-disk", NULL, + lockdown_save_to_disk_entries, G_N_ELEMENTS (lockdown_save_to_disk_entries), self); } void e_cal_shell_view_taskpad_actions_update (ECalShellView *cal_shell_view) { ECalShellContent *cal_shell_content; - EShellWindow *shell_window; EShellView *shell_view; ETaskTable *task_table; - GtkAction *action; + EUIAction *action; GSList *list, *iter; gboolean assignable = TRUE; gboolean editable = TRUE; @@ -423,7 +433,6 @@ e_cal_shell_view_taskpad_actions_update (ECalShellView *cal_shell_view) gint n_incomplete = 0; shell_view = E_SHELL_VIEW (cal_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); cal_shell_content = cal_shell_view->priv->cal_shell_content; task_table = e_cal_shell_content_get_task_table (cal_shell_content); @@ -458,35 +467,35 @@ e_cal_shell_view_taskpad_actions_update (ECalShellView *cal_shell_view) action = ACTION (CALENDAR_TASKPAD_ASSIGN); sensitive = (n_selected == 1) && editable && assignable; - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_TASKPAD_FORWARD); sensitive = (n_selected == 1); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_TASKPAD_MARK_COMPLETE); sensitive = (n_selected > 0) && editable && (n_incomplete > 0); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_TASKPAD_MARK_INCOMPLETE); sensitive = (n_selected > 0) && editable && (n_complete > 0); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_TASKPAD_OPEN); sensitive = (n_selected == 1); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_TASKPAD_OPEN_URL); sensitive = (n_selected == 1) && has_url; - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_TASKPAD_PRINT); sensitive = (n_selected == 1); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (CALENDAR_TASKPAD_SAVE_AS); sensitive = (n_selected == 1); - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); } void diff --git a/src/modules/calendar/e-cal-shell-view.c b/src/modules/calendar/e-cal-shell-view.c index 2141df062d..6b8557e7de 100644 --- a/src/modules/calendar/e-cal-shell-view.c +++ b/src/modules/calendar/e-cal-shell-view.c @@ -32,14 +32,24 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (ECalShellView, e_cal_shell_view, E_TYPE_CAL_BASE_SHELL_VIEW, 0, G_ADD_PRIVATE_DYNAMIC (ECalShellView)) +static void +cal_shell_view_action_button_clicked_cb (GtkButton *button, + gpointer user_data) +{ + GAction *action = user_data; + + g_action_activate (action, NULL); +} + static void cal_shell_view_add_action_button (GtkBox *box, - GtkAction *action) + EUIAction *action, + EUIManager *ui_manager) { GtkWidget *button, *icon; button = gtk_button_new (); - icon = gtk_action_create_icon (action, GTK_ICON_SIZE_MENU); + icon = gtk_image_new_from_icon_name (e_ui_action_get_icon_name (action), GTK_ICON_SIZE_MENU); gtk_image_set_pixel_size (GTK_IMAGE (icon), 16); gtk_button_set_image (GTK_BUTTON (button), icon); gtk_box_pack_start (box, button, FALSE, FALSE, 0); @@ -60,9 +70,9 @@ cal_shell_view_add_action_button (GtkBox *box, button, "tooltip-text", G_BINDING_SYNC_CREATE); - g_signal_connect_swapped ( + g_signal_connect_object ( button, "clicked", - G_CALLBACK (gtk_action_activate), action); + G_CALLBACK (cal_shell_view_action_button_clicked_cb), action, 0); } static void @@ -82,16 +92,16 @@ cal_shell_view_execute_search (EShellView *shell_view) { ECalShellContent *cal_shell_content; ECalBaseShellSidebar *cal_shell_sidebar; - EShellWindow *shell_window; EShellContent *shell_content; EShellSidebar *shell_sidebar; EShellSearchbar *searchbar; EActionComboBox *combo_box; ECalendar *calendar; ECalDataModel *data_model; - GtkRadioAction *action; + EUIAction *action; ICalTimezone *timezone; ICalTime *current_time; + GVariant *state; time_t start_range; time_t end_range; time_t now_time; @@ -102,7 +112,6 @@ cal_shell_view_execute_search (EShellView *shell_view) e_cal_shell_view_search_stop (E_CAL_SHELL_VIEW (shell_view)); - shell_window = e_shell_view_get_shell_window (shell_view); shell_content = e_shell_view_get_shell_content (shell_view); shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); @@ -117,8 +126,10 @@ cal_shell_view_execute_search (EShellView *shell_view) now_time = time_day_begin (i_cal_time_as_timet (current_time)); g_clear_object (¤t_time); - action = GTK_RADIO_ACTION (ACTION (CALENDAR_SEARCH_ANY_FIELD_CONTAINS)); - value = gtk_radio_action_get_current_value (action); + action = ACTION (CALENDAR_SEARCH_ANY_FIELD_CONTAINS); + state = g_action_get_state (G_ACTION (action)); + value = g_variant_get_int32 (state); + g_clear_pointer (&state, g_variant_unref); if (value == CALENDAR_SEARCH_ADVANCED) { query = e_shell_view_get_search_query (shell_view); @@ -222,8 +233,8 @@ cal_shell_view_execute_search (EShellView *shell_view) if (range_search) { /* Switch to list view and hide the date navigator. */ - action = GTK_RADIO_ACTION (ACTION (CALENDAR_VIEW_LIST)); - gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); + action = ACTION (CALENDAR_VIEW_LIST); + e_ui_action_set_active (action, TRUE); gtk_widget_hide (GTK_WIDGET (calendar)); } else { ECalViewKind view_kind; @@ -253,7 +264,6 @@ cal_shell_view_update_actions (EShellView *shell_view) ECalShellContent *cal_shell_content; EShellContent *shell_content; EShellSidebar *shell_sidebar; - EShellWindow *shell_window; EShell *shell; ESource *source; ESourceRegistry *registry; @@ -261,7 +271,7 @@ cal_shell_view_update_actions (EShellView *shell_view) EMemoTable *memo_table; ETaskTable *task_table; ECalDataModel *data_model; - GtkAction *action; + EUIAction *action; gchar *data_filter; gboolean is_searching; gboolean is_list_view; @@ -293,8 +303,7 @@ cal_shell_view_update_actions (EShellView *shell_view) /* Chain up to parent's update_actions() method. */ E_SHELL_VIEW_CLASS (e_cal_shell_view_parent_class)->update_actions (shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - shell = e_shell_window_get_shell (shell_window); + shell = e_shell_window_get_shell (e_shell_view_get_shell_window (shell_view)); registry = e_shell_get_registry (shell); source = e_source_registry_ref_default_mail_identity (registry); @@ -367,57 +376,57 @@ cal_shell_view_update_actions (EShellView *shell_view) action = ACTION (CALENDAR_SELECT_ALL); sensitive = clicked_source_is_primary && !all_sources_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_SELECT_ONE); sensitive = clicked_source_is_primary; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_COPY); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_DELETE); sensitive = primary_source_is_removable || primary_source_is_remote_deletable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_PRINT); sensitive = TRUE; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_PRINT_PREVIEW); sensitive = TRUE; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_PROPERTIES); sensitive = clicked_source_is_primary && primary_source_is_writable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_REFRESH); sensitive = clicked_source_is_primary && refresh_supported; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_REFRESH_BACKEND); sensitive = clicked_source_is_collection; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_RENAME); sensitive = clicked_source_is_primary && primary_source_is_writable && !primary_source_in_collection; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (CALENDAR_SEARCH_PREV); - gtk_action_set_sensitive (action, is_searching && !is_list_view); + e_ui_action_set_sensitive (action, is_searching && !is_list_view); action = ACTION (CALENDAR_SEARCH_NEXT); - gtk_action_set_sensitive (action, is_searching && !is_list_view); + e_ui_action_set_sensitive (action, is_searching && !is_list_view); action = ACTION (CALENDAR_SEARCH_STOP); sensitive = is_searching && self->priv->searching_activity != NULL; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_DELEGATE); sensitive = @@ -425,21 +434,21 @@ cal_shell_view_update_actions (EShellView *shell_view) selection_is_editable && selection_can_delegate && selection_is_meeting; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_DELETE); sensitive = any_events_selected && selection_is_editable && !selection_is_recurring; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_DELETE_OCCURRENCE); sensitive = any_events_selected && selection_is_editable && selection_is_recurring; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_DELETE_OCCURRENCE_THIS_AND_FUTURE); sensitive = @@ -447,18 +456,18 @@ cal_shell_view_update_actions (EShellView *shell_view) selection_is_editable && selection_is_recurring && this_and_future_supported; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_DELETE_OCCURRENCE_ALL); sensitive = any_events_selected && selection_is_editable && selection_is_recurring; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_FORWARD); sensitive = single_event_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_OCCURRENCE_MOVABLE); sensitive = @@ -466,62 +475,62 @@ cal_shell_view_update_actions (EShellView *shell_view) selection_is_editable && selection_is_recurring && selection_is_instance; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_OPEN); sensitive = single_event_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_EDIT_AS_NEW); sensitive = single_event_selected && !selection_is_instance; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_PRINT); sensitive = single_event_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_SAVE_AS); sensitive = single_event_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_SCHEDULE); sensitive = single_event_selected && selection_is_editable && !selection_is_meeting; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_SCHEDULE_APPOINTMENT); sensitive = single_event_selected && selection_is_editable && selection_is_meeting; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_REPLY); sensitive = single_event_selected && selection_is_meeting; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (EVENT_REPLY_ALL); sensitive = single_event_selected && selection_is_meeting; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); - action = ACTION (EVENT_POPUP_MEETING_NEW); - gtk_action_set_visible (action, has_mail_identity); + action = ACTION (EVENT_MEETING_NEW); + e_ui_action_set_visible (action, has_mail_identity); - action = ACTION (EVENT_POPUP_RSVP_SUBMENU); - gtk_action_set_visible (action, selection_is_attendee); + action = ACTION (EVENT_RSVP_SUBMENU); + e_ui_action_set_visible (action, selection_is_attendee); sensitive = selection_is_instance || selection_is_recurring; - gtk_action_set_visible (ACTION (EVENT_POPUP_RSVP_ACCEPT_1), sensitive); - gtk_action_set_visible (ACTION (EVENT_POPUP_RSVP_DECLINE_1), sensitive); - gtk_action_set_visible (ACTION (EVENT_POPUP_RSVP_TENTATIVE_1), sensitive); + e_ui_action_set_visible (ACTION (EVENT_RSVP_ACCEPT_1), sensitive); + e_ui_action_set_visible (ACTION (EVENT_RSVP_DECLINE_1), sensitive); + e_ui_action_set_visible (ACTION (EVENT_RSVP_TENTATIVE_1), sensitive); - gtk_action_set_sensitive (ACTION (CALENDAR_GO_BACK), !is_list_view); - gtk_action_set_sensitive (ACTION (CALENDAR_GO_FORWARD), !is_list_view); - gtk_action_set_sensitive (ACTION (CALENDAR_GO_TODAY), !is_list_view); - gtk_action_set_sensitive (ACTION (CALENDAR_JUMP_TO), !is_list_view); + e_ui_action_set_sensitive (ACTION (CALENDAR_GO_BACK), !is_list_view); + e_ui_action_set_sensitive (ACTION (CALENDAR_GO_FORWARD), !is_list_view); + e_ui_action_set_sensitive (ACTION (CALENDAR_GO_TODAY), !is_list_view); + e_ui_action_set_sensitive (ACTION (CALENDAR_JUMP_TO), !is_list_view); if ((cal_view && e_calendar_view_is_editing (cal_view)) || e_table_is_editing (E_TABLE (memo_table)) || @@ -529,26 +538,99 @@ cal_shell_view_update_actions (EShellView *shell_view) EFocusTracker *focus_tracker; /* disable all clipboard actions, if any of the views is in editing mode */ - focus_tracker = e_shell_window_get_focus_tracker (shell_window); + focus_tracker = e_shell_window_get_focus_tracker (e_shell_view_get_shell_window (shell_view)); action = e_focus_tracker_get_cut_clipboard_action (focus_tracker); if (action) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_copy_clipboard_action (focus_tracker); if (action) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_paste_clipboard_action (focus_tracker); if (action) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); action = e_focus_tracker_get_delete_selection_action (focus_tracker); if (action) - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); } } +static gboolean +e_cal_shell_view_ui_manager_create_item_cb (EUIManager *manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + ECalShellView *self = user_data; + const gchar *name; + + g_return_val_if_fail (E_IS_CAL_SHELL_VIEW (self), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "ECalShellView::")) + return FALSE; + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (for_kind == E_UI_ELEMENT_KIND_MENU) { + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + if (is_action ("ECalShellView::navigation-buttons")) { + EShellView *shell_view; + GtkWidget *widget; + EUIAction *btn_action; + + shell_view = E_SHELL_VIEW (self); + + btn_action = ACTION (CALENDAR_GO_BACK); + widget = e_header_bar_button_new (NULL, btn_action, manager); + + btn_action = ACTION (CALENDAR_GO_TODAY); + e_header_bar_button_add_action (E_HEADER_BAR_BUTTON (widget), NULL, btn_action); + + btn_action = ACTION (CALENDAR_GO_FORWARD); + e_header_bar_button_add_action (E_HEADER_BAR_BUTTON (widget), NULL, btn_action); + + gtk_widget_show (widget); + + *out_item = G_OBJECT (widget); + } else { + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + #undef is_action + + return TRUE; +} + +static void +cal_shell_view_init_ui_data (EShellView *shell_view) +{ + ECalShellView *cal_shell_view; + + g_return_if_fail (E_IS_CAL_SHELL_VIEW (shell_view)); + + cal_shell_view = E_CAL_SHELL_VIEW (shell_view); + + g_signal_connect_object (e_shell_view_get_ui_manager (shell_view), "create-item", + G_CALLBACK (e_cal_shell_view_ui_manager_create_item_cb), cal_shell_view, 0); + + e_cal_shell_view_actions_init (cal_shell_view); + e_cal_shell_view_memopad_actions_init (cal_shell_view); + e_cal_shell_view_taskpad_actions_init (cal_shell_view); +} + static void cal_shell_view_dispose (GObject *object) { @@ -576,33 +658,33 @@ cal_shell_view_constructed (GObject *object) EShellSearchbar *searchbar; ECalShellView *cal_shell_view; ECalShellContent *cal_shell_content; + EUIManager *ui_manager; GtkWidget *container; GtkWidget *widget; gulong handler_id; - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_cal_shell_view_parent_class)->constructed (object); - cal_shell_view = E_CAL_SHELL_VIEW (object); - e_cal_shell_view_private_constructed (cal_shell_view); - shell_view = E_SHELL_VIEW (cal_shell_view); shell_window = e_shell_view_get_shell_window (shell_view); shell = e_shell_window_get_shell (shell_window); + ui_manager = e_shell_view_get_ui_manager (shell_view); + + e_ui_manager_freeze (ui_manager); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_cal_shell_view_parent_class)->constructed (object); + + e_cal_shell_view_private_constructed (cal_shell_view); cal_shell_content = cal_shell_view->priv->cal_shell_content; searchbar = e_cal_shell_content_get_searchbar (cal_shell_content); container = e_shell_searchbar_get_search_box (searchbar); widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_style_context_add_class ( - gtk_widget_get_style_context (widget), "linked"); - cal_shell_view_add_action_button ( - GTK_BOX (widget), ACTION (CALENDAR_SEARCH_PREV)); - cal_shell_view_add_action_button ( - GTK_BOX (widget), ACTION (CALENDAR_SEARCH_NEXT)); - cal_shell_view_add_action_button ( - GTK_BOX (widget), ACTION (CALENDAR_SEARCH_STOP)); + gtk_style_context_add_class (gtk_widget_get_style_context (widget), "linked"); + cal_shell_view_add_action_button (GTK_BOX (widget), ACTION (CALENDAR_SEARCH_PREV), ui_manager); + cal_shell_view_add_action_button (GTK_BOX (widget), ACTION (CALENDAR_SEARCH_NEXT), ui_manager); + cal_shell_view_add_action_button (GTK_BOX (widget), ACTION (CALENDAR_SEARCH_STOP), ui_manager); gtk_container_add (GTK_CONTAINER (container), widget); gtk_widget_show (widget); @@ -613,6 +695,8 @@ cal_shell_view_constructed (GObject *object) cal_shell_view->priv->shell = g_object_ref (shell); cal_shell_view->priv->prepare_for_quit_handler_id = handler_id; + + e_ui_manager_thaw (ui_manager); } static void @@ -630,14 +714,14 @@ e_cal_shell_view_class_init (ECalShellViewClass *class) shell_view_class = E_SHELL_VIEW_CLASS (class); shell_view_class->label = _("Calendar"); shell_view_class->icon_name = "x-office-calendar"; - shell_view_class->ui_definition = "evolution-calendars.ui"; + shell_view_class->ui_definition = "evolution-calendars.eui"; shell_view_class->ui_manager_id = "org.gnome.evolution.calendars"; - shell_view_class->search_options = "/calendar-search-options"; shell_view_class->search_rules = "caltypes.xml"; shell_view_class->new_shell_content = e_cal_shell_content_new; shell_view_class->new_shell_sidebar = e_cal_base_shell_sidebar_new; shell_view_class->execute_search = cal_shell_view_execute_search; shell_view_class->update_actions = cal_shell_view_update_actions; + shell_view_class->init_ui_data = cal_shell_view_init_ui_data; cal_base_shell_view_class = E_CAL_BASE_SHELL_VIEW_CLASS (class); cal_base_shell_view_class->source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS; diff --git a/src/modules/calendar/e-memo-shell-backend.c b/src/modules/calendar/e-memo-shell-backend.c index 5cea7c8953..79b2ce4221 100644 --- a/src/modules/calendar/e-memo-shell-backend.c +++ b/src/modules/calendar/e-memo-shell-backend.c @@ -37,9 +37,11 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (EMemoShellBackend, e_memo_shell_backend, E_TYPE_ G_ADD_PRIVATE_DYNAMIC (EMemoShellBackend)) static void -action_memo_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_memo_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShellView *shell_view; ESource *selected_source = NULL; @@ -55,45 +57,22 @@ action_memo_new_cb (GtkAction *action, e_cal_ops_new_component_editor (shell_window, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, selected_source ? e_source_get_uid (selected_source) : NULL, - g_strcmp0 (gtk_action_get_name (action), "memo-shared-new") == 0); + g_strcmp0 (g_action_get_name (G_ACTION (action)), "memo-shared-new") == 0 || + g_strcmp0 (g_action_get_name (G_ACTION (action)), "new-menu-memo-shared-new") == 0); g_clear_object (&selected_source); } static void -action_memo_list_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_memo_list_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; + e_cal_base_shell_backend_util_new_source (shell_window, E_CAL_CLIENT_SOURCE_TYPE_MEMOS); } -static GtkActionEntry item_entries[] = { - - { "memo-new", - "stock_insert-note", - NC_("New", "Mem_o"), - "o", - N_("Create a new memo"), - G_CALLBACK (action_memo_new_cb) }, - - { "memo-shared-new", - "stock_insert-note", - NC_("New", "_Shared Memo"), - "u", - N_("Create a new shared memo"), - G_CALLBACK (action_memo_new_cb) } -}; - -static GtkActionEntry source_entries[] = { - - { "memo-list-new", - "stock_notes", - NC_("New", "Memo Li_st"), - NULL, - N_("Create a new memo list"), - G_CALLBACK (action_memo_list_new_cb) } -}; - static gboolean e_memo_shell_backend_handle_uri (EShellBackend *shell_backend, const gchar *uri) @@ -108,6 +87,31 @@ e_memo_shell_backend_handle_uri (EShellBackend *shell_backend, static void e_memo_shell_backend_class_init (EMemoShellBackendClass *class) { + static const EUIActionEntry item_entries[] = { + { "new-menu-memo-new", + "stock_insert-note", + NC_("New", "Mem_o"), + "o", + N_("Create a new memo"), + action_memo_new_cb, NULL, NULL }, + + { "new-menu-memo-shared-new", + "stock_insert-note", + NC_("New", "_Shared Memo"), + "u", + N_("Create a new shared memo"), + action_memo_new_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry source_entries[] = { + { "new-menu-memo-list-new", + "stock_notes", + NC_("New", "Memo Li_st"), + NULL, + N_("Create a new memo list"), + action_memo_list_new_cb, NULL, NULL, NULL } + }; + EShellBackendClass *shell_backend_class; ECalBaseShellBackendClass *cal_base_shell_backend_class; diff --git a/src/modules/calendar/e-memo-shell-view-actions.c b/src/modules/calendar/e-memo-shell-view-actions.c index cd6dd5a3fc..4b81fc08da 100644 --- a/src/modules/calendar/e-memo-shell-view-actions.c +++ b/src/modules/calendar/e-memo-shell-view-actions.c @@ -28,9 +28,11 @@ #include "e-cal-shell-view.h" static void -action_memo_delete_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EMemoShellContent *memo_shell_content; EMemoTable *memo_table; @@ -41,9 +43,11 @@ action_memo_delete_cb (GtkAction *action, } static void -action_memo_find_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_find_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EMemoShellContent *memo_shell_content; EPreviewPane *preview_pane; @@ -54,9 +58,11 @@ action_memo_find_cb (GtkAction *action, } static void -action_memo_forward_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EMemoShellContent *memo_shell_content; EMemoTable *memo_table; ECalModelComponent *comp_data; @@ -86,16 +92,21 @@ action_memo_forward_cb (GtkAction *action, } static void -action_memo_list_copy_cb (GtkAction *action, - EShellView *shell_view) +action_memo_list_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; + e_cal_base_shell_view_copy_calendar (shell_view); } static void -action_memo_list_delete_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; ECalBaseShellSidebar *memo_shell_sidebar; EShellWindow *shell_window; EShellView *shell_view; @@ -135,9 +146,11 @@ action_memo_list_delete_cb (GtkAction *action, } static void -action_memo_list_manage_groups_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_manage_groups_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EShellView *shell_view; ESourceSelector *selector; @@ -150,9 +163,11 @@ action_memo_list_manage_groups_cb (GtkAction *action, } static void -action_memo_list_new_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -177,7 +192,7 @@ action_memo_list_new_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title (GTK_WINDOW (dialog), _("New Memo List")); @@ -186,9 +201,11 @@ action_memo_list_new_cb (GtkAction *action, } static void -action_memo_list_print_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EMemoShellContent *memo_shell_content; EMemoTable *memo_table; @@ -201,9 +218,11 @@ action_memo_list_print_cb (GtkAction *action, } static void -action_memo_list_print_preview_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_print_preview_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EMemoShellContent *memo_shell_content; EMemoTable *memo_table; @@ -216,9 +235,11 @@ action_memo_list_print_preview_cb (GtkAction *action, } static void -action_memo_list_properties_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_properties_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ECalBaseShellSidebar *memo_shell_sidebar; @@ -249,7 +270,7 @@ action_memo_list_properties_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title (GTK_WINDOW (dialog), _("Memo List Properties")); @@ -258,9 +279,11 @@ action_memo_list_properties_cb (GtkAction *action, } static void -action_memo_list_refresh_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_refresh_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; ECalBaseShellSidebar *memo_shell_sidebar; ESourceSelector *selector; EClient *client = NULL; @@ -288,9 +311,11 @@ action_memo_list_refresh_cb (GtkAction *action, } static void -action_memo_list_refresh_backend_cb (GtkAction *action, - EShellView *shell_view) +action_memo_list_refresh_backend_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; ESource *source; g_return_if_fail (E_IS_MEMO_SHELL_VIEW (shell_view)); @@ -302,9 +327,11 @@ action_memo_list_refresh_backend_cb (GtkAction *action, } static void -action_memo_list_rename_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_rename_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; ECalBaseShellSidebar *memo_shell_sidebar; ESourceSelector *selector; @@ -315,9 +342,11 @@ action_memo_list_rename_cb (GtkAction *action, } static void -action_memo_list_select_all_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_select_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; ECalBaseShellSidebar *memo_shell_sidebar; ESourceSelector *selector; @@ -328,9 +357,11 @@ action_memo_list_select_all_cb (GtkAction *action, } static void -action_memo_list_select_one_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_list_select_one_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; ECalBaseShellSidebar *memo_shell_sidebar; ESourceSelector *selector; ESource *primary; @@ -347,9 +378,11 @@ action_memo_list_select_one_cb (GtkAction *action, } static void -action_memo_new_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; EMemoShellContent *memo_shell_content; @@ -379,9 +412,11 @@ action_memo_new_cb (GtkAction *action, } static void -action_memo_open_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EMemoShellContent *memo_shell_content; EMemoTable *memo_table; ECalModelComponent *comp_data; @@ -400,9 +435,11 @@ action_memo_open_cb (GtkAction *action, } static void -action_memo_open_url_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_open_url_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; EMemoShellContent *memo_shell_content; @@ -434,21 +471,11 @@ action_memo_open_url_cb (GtkAction *action, } static void -action_memo_preview_cb (GtkToggleAction *action, - EMemoShellView *memo_shell_view) -{ - EMemoShellContent *memo_shell_content; - gboolean visible; - - memo_shell_content = memo_shell_view->priv->memo_shell_content; - visible = gtk_toggle_action_get_active (action); - e_memo_shell_content_set_preview_visible (memo_shell_content, visible); -} - -static void -action_memo_print_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EMemoShellContent *memo_shell_content; EMemoTable *memo_table; ECalModelComponent *comp_data; @@ -478,9 +505,11 @@ action_memo_print_cb (GtkAction *action, } static void -action_memo_save_as_cb (GtkAction *action, - EMemoShellView *memo_shell_view) +action_memo_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMemoShellView *memo_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -540,423 +569,245 @@ action_memo_save_as_cb (GtkAction *action, g_object_unref (file); } -static void -action_memo_view_cb (GtkRadioAction *action, - GtkRadioAction *current, - EMemoShellView *memo_shell_view) -{ - EMemoShellContent *memo_shell_content; - GtkOrientable *orientable; - GtkOrientation orientation; - - memo_shell_content = memo_shell_view->priv->memo_shell_content; - orientable = GTK_ORIENTABLE (memo_shell_content); - - switch (gtk_radio_action_get_current_value (action)) { - case 0: - orientation = GTK_ORIENTATION_VERTICAL; - break; - case 1: - orientation = GTK_ORIENTATION_HORIZONTAL; - break; - default: - g_return_if_reached (); - } - - gtk_orientable_set_orientation (orientable, orientation); -} - -static GtkActionEntry memo_entries[] = { - - { "memo-delete", - "edit-delete", - N_("_Delete Memo"), - NULL, - N_("Delete selected memos"), - G_CALLBACK (action_memo_delete_cb) }, - - { "memo-find", - "edit-find", - N_("_Find in Memo…"), - "f", - N_("Search for text in the displayed memo"), - G_CALLBACK (action_memo_find_cb) }, - - { "memo-forward", - "mail-forward", - N_("_Forward as iCalendar…"), - "f", - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_memo_forward_cb) }, - - { "memo-list-copy", - "edit-copy", - N_("_Copy…"), - "c", - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_memo_list_copy_cb) }, - - { "memo-list-delete", - "edit-delete", - N_("D_elete Memo List"), - NULL, - N_("Delete the selected memo list"), - G_CALLBACK (action_memo_list_delete_cb) }, - - { "memo-list-manage-groups", - NULL, - N_("_Manage Memo List groups…"), - NULL, - N_("Manage Memo List groups order and visibility"), - G_CALLBACK (action_memo_list_manage_groups_cb) }, - - { "memo-list-new", - "stock_notes", - N_("_New Memo List"), - NULL, - N_("Create a new memo list"), - G_CALLBACK (action_memo_list_new_cb) }, - - { "memo-list-properties", - "document-properties", - N_("_Properties"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_memo_list_properties_cb) }, - - { "memo-list-refresh", - "view-refresh", - N_("Re_fresh"), - NULL, - N_("Refresh the selected memo list"), - G_CALLBACK (action_memo_list_refresh_cb) }, - - { "memo-list-refresh-backend", - "view-refresh", - N_("Re_fresh list of account memo lists"), - NULL, - NULL, - G_CALLBACK (action_memo_list_refresh_backend_cb) }, - - { "memo-list-rename", - NULL, - N_("_Rename…"), - "F2", - N_("Rename the selected memo list"), - G_CALLBACK (action_memo_list_rename_cb) }, - - { "memo-list-select-one", - "stock_check-filled", - N_("Show _Only This Memo List"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_memo_list_select_one_cb) }, - - { "memo-list-select-all", - "stock_check-filled", - N_("Sho_w All Memo Lists"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_memo_list_select_all_cb) }, - - { "memo-new", - "stock_insert-note", - N_("New _Memo"), - NULL, - N_("Create a new memo"), - G_CALLBACK (action_memo_new_cb) }, - - { "memo-open", - "document-open", - N_("_Open Memo"), - "o", - N_("View the selected memo"), - G_CALLBACK (action_memo_open_cb) }, - - { "memo-open-url", - "applications-internet", - N_("Open _Web Page"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_memo_open_url_cb) }, - - /*** Menus ***/ - - { "memo-preview-menu", - NULL, - N_("_Preview"), - NULL, - NULL, - NULL } -}; - -static EPopupActionEntry memo_popup_entries[] = { - - { "memo-list-popup-copy", - NULL, - "memo-list-copy" }, - - { "memo-list-popup-delete", - N_("_Delete"), - "memo-list-delete" }, - - { "memo-list-popup-manage-groups", - N_("_Manage groups…"), - "memo-list-manage-groups" }, - - { "memo-list-popup-properties", - NULL, - "memo-list-properties" }, - - { "memo-list-popup-refresh", - NULL, - "memo-list-refresh" }, - - { "memo-list-popup-refresh-backend", - NULL, - "memo-list-refresh-backend" }, - - { "memo-list-popup-rename", - NULL, - "memo-list-rename" }, - - { "memo-list-popup-select-all", - NULL, - "memo-list-select-all" }, - - { "memo-list-popup-select-one", - NULL, - "memo-list-select-one" }, - - { "memo-popup-forward", - NULL, - "memo-forward" }, - - { "memo-popup-open", - NULL, - "memo-open" }, - - { "memo-popup-open-url", - NULL, - "memo-open-url" } -}; - -static GtkToggleActionEntry memo_toggle_entries[] = { - - { "memo-preview", - NULL, - N_("Memo _Preview"), - "m", - N_("Show memo preview pane"), - G_CALLBACK (action_memo_preview_cb), - TRUE } -}; - -static GtkRadioActionEntry memo_view_entries[] = { - - /* This action represents the initial active memo view. - * It should not be visible in the UI, nor should it be - * possible to switch to it from another shell view. */ - { "memo-view-initial", - NULL, - NULL, - NULL, - NULL, - -1 }, - - { "memo-view-classic", - NULL, - N_("_Classic View"), - NULL, - N_("Show memo preview below the memo list"), - 0 }, - - { "memo-view-vertical", - NULL, - N_("_Vertical View"), - NULL, - N_("Show memo preview alongside the memo list"), - 1 } -}; - -static GtkRadioActionEntry memo_filter_entries[] = { - - { "memo-filter-any-category", - NULL, - N_("Any Category"), - NULL, - NULL, - MEMO_FILTER_ANY_CATEGORY }, - - { "memo-filter-unmatched", - NULL, - N_("Without Category"), - NULL, - N_("Show memos with no category set"), - MEMO_FILTER_UNMATCHED } -}; - -static GtkRadioActionEntry memo_search_entries[] = { - - { "memo-search-advanced-hidden", - NULL, - N_("Advanced Search"), - NULL, - NULL, - MEMO_SEARCH_ADVANCED }, - - { "memo-search-any-field-contains", - NULL, - N_("Any field contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - MEMO_SEARCH_ANY_FIELD_CONTAINS }, - - { "memo-search-description-contains", - NULL, - N_("Description contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - MEMO_SEARCH_DESCRIPTION_CONTAINS }, - - { "memo-search-summary-contains", - NULL, - N_("Summary contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - MEMO_SEARCH_SUMMARY_CONTAINS } -}; - -static GtkActionEntry lockdown_printing_entries[] = { - - { "memo-list-print", - "document-print", - N_("Print…"), - "p", - N_("Print the list of memos"), - G_CALLBACK (action_memo_list_print_cb) }, - - { "memo-list-print-preview", - "document-print-preview", - N_("Pre_view…"), - NULL, - N_("Preview the list of memos to be printed"), - G_CALLBACK (action_memo_list_print_preview_cb) }, - - { "memo-print", - "document-print", - N_("Print…"), - NULL, - N_("Print the selected memo"), - G_CALLBACK (action_memo_print_cb) } -}; - -static EPopupActionEntry lockdown_printing_popup_entries[] = { - - { "memo-popup-print", - NULL, - "memo-print" } -}; - -static GtkActionEntry lockdown_save_to_disk_entries[] = { - - { "memo-save-as", - "document-save-as", - N_("_Save as iCalendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_memo_save_as_cb) }, -}; - -static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = { - - { "memo-popup-save-as", - NULL, - "memo-save-as" } -}; - void -e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view) +e_memo_shell_view_actions_init (EMemoShellView *self) { - EMemoShellContent *memo_shell_content; + static const EUIActionEntry memo_entries[] = { + + { "memo-delete", + "edit-delete", + N_("_Delete Memo"), + NULL, + N_("Delete selected memos"), + action_memo_delete_cb, NULL, NULL, NULL }, + + { "memo-find", + "edit-find", + N_("_Find in Memo…"), + "f", + N_("Search for text in the displayed memo"), + action_memo_find_cb, NULL, NULL, NULL }, + + { "memo-forward", + "mail-forward", + N_("_Forward as iCalendar…"), + "f", + NULL, + action_memo_forward_cb, NULL, NULL, NULL }, + + { "memo-list-copy", + "edit-copy", + N_("_Copy…"), + NULL, + NULL, + action_memo_list_copy_cb, NULL, NULL, NULL }, + + { "memo-list-delete", + "edit-delete", + N_("D_elete Memo List"), + NULL, + N_("Delete the selected memo list"), + action_memo_list_delete_cb, NULL, NULL, NULL }, + + { "memo-list-manage-groups", + NULL, + N_("_Manage Memo List groups…"), + NULL, + N_("Manage Memo List groups order and visibility"), + action_memo_list_manage_groups_cb, NULL, NULL, NULL }, + + { "memo-list-manage-groups-popup", + NULL, + N_("_Manage groups…"), + NULL, + N_("Manage Memo List groups order and visibility"), + action_memo_list_manage_groups_cb, NULL, NULL, NULL }, + + { "memo-list-new", + "stock_notes", + N_("_New Memo List"), + NULL, + N_("Create a new memo list"), + action_memo_list_new_cb, NULL, NULL, NULL }, + + { "memo-list-properties", + "document-properties", + N_("_Properties"), + NULL, + NULL, + action_memo_list_properties_cb, NULL, NULL, NULL }, + + { "memo-list-refresh", + "view-refresh", + N_("Re_fresh"), + NULL, + N_("Refresh the selected memo list"), + action_memo_list_refresh_cb, NULL, NULL, NULL }, + + { "memo-list-refresh-backend", + "view-refresh", + N_("Re_fresh list of account memo lists"), + NULL, + NULL, + action_memo_list_refresh_backend_cb, NULL, NULL, NULL }, + + { "memo-list-rename", + NULL, + N_("_Rename…"), + NULL, + N_("Rename the selected memo list"), + action_memo_list_rename_cb, NULL, NULL, NULL }, + + { "memo-list-select-one", + "stock_check-filled", + N_("Show _Only This Memo List"), + NULL, + NULL, + action_memo_list_select_one_cb, NULL, NULL, NULL }, + + { "memo-list-select-all", + "stock_check-filled", + N_("Sho_w All Memo Lists"), + NULL, + NULL, + action_memo_list_select_all_cb, NULL, NULL, NULL }, + + { "memo-new", + "stock_insert-note", + N_("New _Memo"), + NULL, + N_("Create a new memo"), + action_memo_new_cb, NULL, NULL, NULL }, + + { "memo-open", + "document-open", + N_("_Open Memo"), + "o", + N_("View the selected memo"), + action_memo_open_cb, NULL, NULL, NULL }, + + { "memo-open-url", + "applications-internet", + N_("Open _Web Page"), + NULL, + NULL, + action_memo_open_url_cb, NULL, NULL, NULL }, + + { "memo-preview", + NULL, + N_("Memo _Preview"), + "m", + N_("Show memo preview pane"), + NULL, NULL, "true", NULL }, + + /*** Menus ***/ + + { "memo-preview-menu", NULL, N_("_Preview"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + + static const EUIActionEnumEntry memo_view_entries[] = { + + { "memo-view-classic", + NULL, + N_("_Classic View"), + NULL, + N_("Show memo preview below the memo list"), + NULL, 0 }, + + { "memo-view-vertical", + NULL, + N_("_Vertical View"), + NULL, + N_("Show memo preview alongside the memo list"), + NULL, 1 } + }; + + static const EUIActionEnumEntry memo_search_entries[] = { + + { "memo-search-advanced-hidden", + NULL, + N_("Advanced Search"), + NULL, + NULL, + NULL, MEMO_SEARCH_ADVANCED }, + + { "memo-search-any-field-contains", + NULL, + N_("Any field contains"), + NULL, + NULL, + NULL, MEMO_SEARCH_ANY_FIELD_CONTAINS }, + + { "memo-search-description-contains", + NULL, + N_("Description contains"), + NULL, + NULL, + NULL, MEMO_SEARCH_DESCRIPTION_CONTAINS }, + + { "memo-search-summary-contains", + NULL, + N_("Summary contains"), + NULL, + NULL, + NULL, MEMO_SEARCH_SUMMARY_CONTAINS } + }; + + static const EUIActionEntry lockdown_printing_entries[] = { + + { "memo-list-print", + "document-print", + N_("Print…"), + "p", + N_("Print the list of memos"), + action_memo_list_print_cb, NULL, NULL, NULL }, + + { "memo-list-print-preview", + "document-print-preview", + N_("Pre_view…"), + NULL, + N_("Preview the list of memos to be printed"), + action_memo_list_print_preview_cb, NULL, NULL, NULL }, + + { "memo-print", + "document-print", + N_("Print…"), + NULL, + N_("Print the selected memo"), + action_memo_print_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry lockdown_save_to_disk_entries[] = { + + { "memo-save-as", + "document-save-as", + N_("_Save as iCalendar…"), + NULL, + NULL, + action_memo_save_as_cb, NULL, NULL, NULL }, + }; + EShellView *shell_view; - EShellWindow *shell_window; - EShellSearchbar *searchbar; - EPreviewPane *preview_pane; - EWebView *web_view; - GtkActionGroup *action_group; - GSettings *memo_settings; - GtkAction *action; + EUIManager *ui_manager; - shell_view = E_SHELL_VIEW (memo_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - - memo_shell_content = memo_shell_view->priv->memo_shell_content; - searchbar = e_memo_shell_content_get_searchbar (memo_shell_content); - preview_pane = e_memo_shell_content_get_preview_pane (memo_shell_content); - web_view = e_preview_pane_get_web_view (preview_pane); + shell_view = E_SHELL_VIEW (self); + ui_manager = e_shell_view_get_ui_manager (shell_view); /* Memo Actions */ - action_group = ACTION_GROUP (MEMOS); - gtk_action_group_add_actions ( - action_group, memo_entries, - G_N_ELEMENTS (memo_entries), memo_shell_view); - e_action_group_add_popup_actions ( - action_group, memo_popup_entries, - G_N_ELEMENTS (memo_popup_entries)); - gtk_action_group_add_toggle_actions ( - action_group, memo_toggle_entries, - G_N_ELEMENTS (memo_toggle_entries), memo_shell_view); - gtk_action_group_add_radio_actions ( - action_group, memo_view_entries, - G_N_ELEMENTS (memo_view_entries), -1, - G_CALLBACK (action_memo_view_cb), memo_shell_view); - gtk_action_group_add_radio_actions ( - action_group, memo_search_entries, - G_N_ELEMENTS (memo_search_entries), - -1, NULL, NULL); - - /* Advanced Search Action */ - action = ACTION (MEMO_SEARCH_ADVANCED_HIDDEN); - gtk_action_set_visible (action, FALSE); - e_shell_searchbar_set_search_option ( - searchbar, GTK_RADIO_ACTION (action)); + e_ui_manager_add_actions (ui_manager, "memos", NULL, + memo_entries, G_N_ELEMENTS (memo_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "tasks", NULL, + memo_view_entries, G_N_ELEMENTS (memo_view_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "tasks", NULL, + memo_search_entries, G_N_ELEMENTS (memo_search_entries), self); /* Lockdown Printing Actions */ - action_group = ACTION_GROUP (LOCKDOWN_PRINTING); - gtk_action_group_add_actions ( - action_group, lockdown_printing_entries, - G_N_ELEMENTS (lockdown_printing_entries), - memo_shell_view); - e_action_group_add_popup_actions ( - action_group, lockdown_printing_popup_entries, - G_N_ELEMENTS (lockdown_printing_popup_entries)); + e_ui_manager_add_actions (ui_manager, "lockdown-printing", NULL, + lockdown_printing_entries, G_N_ELEMENTS (lockdown_printing_entries), self); /* Lockdown Save-to-Disk Actions */ - action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK); - gtk_action_group_add_actions ( - action_group, lockdown_save_to_disk_entries, - G_N_ELEMENTS (lockdown_save_to_disk_entries), - memo_shell_view); - e_action_group_add_popup_actions ( - action_group, lockdown_save_to_disk_popup_entries, - G_N_ELEMENTS (lockdown_save_to_disk_popup_entries)); - - /* Bind GObject properties to settings keys. */ - - memo_settings = e_util_ref_settings ("org.gnome.evolution.calendar"); - - g_settings_bind ( - memo_settings, "show-memo-preview", - ACTION (MEMO_PREVIEW), "active", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - memo_settings, "memo-layout", - ACTION (MEMO_VIEW_VERTICAL), "current-value", - G_SETTINGS_BIND_DEFAULT); - - g_object_unref (memo_settings); + e_ui_manager_add_actions (ui_manager, "lockdown-save-to-disk", NULL, + lockdown_save_to_disk_entries, G_N_ELEMENTS (lockdown_save_to_disk_entries), self); /* Fine tuning. */ @@ -969,60 +820,70 @@ e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view) ACTION (MEMO_PREVIEW), "active", ACTION (MEMO_VIEW_VERTICAL), "sensitive", G_BINDING_SYNC_CREATE); - - e_web_view_set_open_proxy (web_view, ACTION (MEMO_OPEN)); - e_web_view_set_print_proxy (web_view, ACTION (MEMO_PRINT)); - e_web_view_set_save_as_proxy (web_view, ACTION (MEMO_SAVE_AS)); } void e_memo_shell_view_update_search_filter (EMemoShellView *memo_shell_view) { + static const EUIActionEnumEntry memo_filter_entries[] = { + + { "memo-filter-any-category", + NULL, + N_("Any Category"), + NULL, + NULL, + NULL, MEMO_FILTER_ANY_CATEGORY }, + + { "memo-filter-unmatched", + NULL, + N_("Without Category"), + NULL, + N_("Show memos with no category set"), + NULL, MEMO_FILTER_UNMATCHED } + }; + EMemoShellContent *memo_shell_content; EShellView *shell_view; - EShellWindow *shell_window; EShellSearchbar *searchbar; EActionComboBox *combo_box; - GtkActionGroup *action_group; - GtkRadioAction *radio_action; + EUIActionGroup *action_group; + EUIAction *action; GList *list, *iter; - GSList *group; + GPtrArray *radio_group; gint ii; shell_view = E_SHELL_VIEW (memo_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - action_group = ACTION_GROUP (MEMOS_FILTER); - e_action_group_remove_all_actions (action_group); + action_group = e_ui_manager_get_action_group (e_shell_view_get_ui_manager (shell_view), "memos-filter"); + e_ui_action_group_remove_all (action_group); /* Add the standard filter actions. No callback is needed * because changes in the EActionComboBox are detected and * handled by EShellSearchbar. */ - gtk_action_group_add_radio_actions ( - action_group, memo_filter_entries, - G_N_ELEMENTS (memo_filter_entries), - MEMO_FILTER_ANY_CATEGORY, NULL, NULL); + e_ui_manager_add_actions_enum (e_shell_view_get_ui_manager (shell_view), + e_ui_action_group_get_name (action_group), NULL, + memo_filter_entries, G_N_ELEMENTS (memo_filter_entries), NULL); - /* Retrieve the radio group from an action we just added. */ - list = gtk_action_group_list_actions (action_group); - radio_action = GTK_RADIO_ACTION (list->data); - group = gtk_radio_action_get_group (radio_action); - g_list_free (list); + radio_group = g_ptr_array_new (); + for (ii = 0; ii < G_N_ELEMENTS (memo_filter_entries); ii++) { + action = e_ui_action_group_get_action (action_group, memo_filter_entries[ii].name); + e_ui_action_set_radio_group (action, radio_group); + } /* Build the category actions. */ list = e_util_dup_searchable_categories (); for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) { const gchar *category_name = iter->data; gchar *filename; - GtkAction *action; - gchar *action_name; + gchar action_name[128]; - action_name = g_strdup_printf ( - "memo-filter-category-%d", ii); - radio_action = gtk_radio_action_new ( - action_name, category_name, NULL, NULL, ii); - g_free (action_name); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "memo-filter-category-%d", ii) < sizeof (action_name)); + + action = e_ui_action_new (e_ui_action_group_get_name (action_group), action_name, NULL); + e_ui_action_set_label (action, category_name); + e_ui_action_set_state (action, g_variant_new_int32 (ii)); + e_ui_action_set_radio_group (action, radio_group); /* Convert the category icon file to a themed icon name. */ filename = e_categories_dup_icon_file_for (category_name); @@ -1036,21 +897,16 @@ e_memo_shell_view_update_search_filter (EMemoShellView *memo_shell_view) if ((cp = strrchr (basename, '.')) != NULL) *cp = '\0'; - g_object_set ( - radio_action, "icon-name", basename, NULL); + e_ui_action_set_icon_name (action, basename); g_free (basename); } g_free (filename); - gtk_radio_action_set_group (radio_action, group); - group = gtk_radio_action_get_group (radio_action); + e_ui_action_group_add (action_group, action); - /* The action group takes ownership of the action. */ - action = GTK_ACTION (radio_action); - gtk_action_group_add_action (action_group, action); - g_object_unref (radio_action); + g_object_unref (action); } g_list_free_full (list, g_free); @@ -1061,10 +917,12 @@ e_memo_shell_view_update_search_filter (EMemoShellView *memo_shell_view) e_shell_view_block_execute_search (shell_view); /* Use any action in the group; doesn't matter which. */ - e_action_combo_box_set_action (combo_box, radio_action); + e_action_combo_box_set_action (combo_box, action); ii = MEMO_FILTER_UNMATCHED; e_action_combo_box_add_separator_after (combo_box, ii); e_shell_view_unblock_execute_search (shell_view); + + g_ptr_array_unref (radio_group); } diff --git a/src/modules/calendar/e-memo-shell-view-actions.h b/src/modules/calendar/e-memo-shell-view-actions.h index 8128c86577..82c5a06f93 100644 --- a/src/modules/calendar/e-memo-shell-view-actions.h +++ b/src/modules/calendar/e-memo-shell-view-actions.h @@ -21,74 +21,68 @@ #ifndef E_MEMO_SHELL_VIEW_ACTIONS_H #define E_MEMO_SHELL_VIEW_ACTIONS_H -#include +#include /* Memo Actions */ -#define E_SHELL_WINDOW_ACTION_MEMO_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-delete") -#define E_SHELL_WINDOW_ACTION_MEMO_FIND(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-find") -#define E_SHELL_WINDOW_ACTION_MEMO_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-forward") -#define E_SHELL_WINDOW_ACTION_MEMO_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-new") -#define E_SHELL_WINDOW_ACTION_MEMO_OPEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-open") -#define E_SHELL_WINDOW_ACTION_MEMO_OPEN_URL(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-open-url") -#define E_SHELL_WINDOW_ACTION_MEMO_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-preview") -#define E_SHELL_WINDOW_ACTION_MEMO_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-print") -#define E_SHELL_WINDOW_ACTION_MEMO_SAVE_AS(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-save-as") -#define E_SHELL_WINDOW_ACTION_MEMO_VIEW_CLASSIC(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-view-classic") -#define E_SHELL_WINDOW_ACTION_MEMO_VIEW_VERTICAL(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-view-vertical") +#define E_SHELL_VIEW_ACTION_MEMO_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-delete") +#define E_SHELL_VIEW_ACTION_MEMO_FIND(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-find") +#define E_SHELL_VIEW_ACTION_MEMO_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-forward") +#define E_SHELL_VIEW_ACTION_MEMO_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-new") +#define E_SHELL_VIEW_ACTION_MEMO_OPEN(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-open") +#define E_SHELL_VIEW_ACTION_MEMO_OPEN_URL(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-open-url") +#define E_SHELL_VIEW_ACTION_MEMO_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-preview") +#define E_SHELL_VIEW_ACTION_MEMO_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-print") +#define E_SHELL_VIEW_ACTION_MEMO_SAVE_AS(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-save-as") +#define E_SHELL_VIEW_ACTION_MEMO_VIEW_CLASSIC(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-view-classic") +#define E_SHELL_VIEW_ACTION_MEMO_VIEW_VERTICAL(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-view-vertical") /* Memo List Actions */ -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_COPY(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-copy") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-delete") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-new") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-print") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PRINT_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-print-preview") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_PROPERTIES(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-properties") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_REFRESH(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-refresh") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_REFRESH_BACKEND(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-refresh-backend") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_RENAME(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-rename") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_SELECT_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-select-all") -#define E_SHELL_WINDOW_ACTION_MEMO_LIST_SELECT_ONE(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-list-select-one") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_COPY(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-copy") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-delete") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-new") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-print") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_PRINT_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-print-preview") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_PROPERTIES(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-properties") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_REFRESH(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-refresh") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_REFRESH_BACKEND(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-refresh-backend") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_RENAME(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-rename") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_SELECT_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-select-all") +#define E_SHELL_VIEW_ACTION_MEMO_LIST_SELECT_ONE(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-list-select-one") /* Memo Query Actions */ -#define E_SHELL_WINDOW_ACTION_MEMO_FILTER_ANY_CATEGORY(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-filter-any-category") -#define E_SHELL_WINDOW_ACTION_MEMO_FILTER_UNMATCHED(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-filter-unmatched") -#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_ADVANCED_HIDDEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-search-advanced-hidden") -#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_ANY_FIELD_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-search-any-field-contains") -#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_DESCRIPTION_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-search-description-contains") -#define E_SHELL_WINDOW_ACTION_MEMO_SEARCH_SUMMARY_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "memo-search-summary-contains") - -/* Action Groups */ -#define E_SHELL_WINDOW_ACTION_GROUP_MEMOS(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "memos") -#define E_SHELL_WINDOW_ACTION_GROUP_MEMOS_FILTER(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "memos-filter") +#define E_SHELL_VIEW_ACTION_MEMO_FILTER_ANY_CATEGORY(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-filter-any-category") +#define E_SHELL_VIEW_ACTION_MEMO_FILTER_UNMATCHED(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-filter-unmatched") +#define E_SHELL_VIEW_ACTION_MEMO_SEARCH_ADVANCED_HIDDEN(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-search-advanced-hidden") +#define E_SHELL_VIEW_ACTION_MEMO_SEARCH_ANY_FIELD_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-search-any-field-contains") +#define E_SHELL_VIEW_ACTION_MEMO_SEARCH_DESCRIPTION_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-search-description-contains") +#define E_SHELL_VIEW_ACTION_MEMO_SEARCH_SUMMARY_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "memo-search-summary-contains") #endif /* E_MEMO_SHELL_VIEW_ACTIONS_H */ diff --git a/src/modules/calendar/e-memo-shell-view-private.c b/src/modules/calendar/e-memo-shell-view-private.c index f6ba77c598..b33a854fa2 100644 --- a/src/modules/calendar/e-memo-shell-view-private.c +++ b/src/modules/calendar/e-memo-shell-view-private.c @@ -29,7 +29,7 @@ static void memo_shell_view_table_popup_event_cb (EShellView *shell_view, GdkEvent *button_event) { - e_cal_base_shell_view_show_popup_menu (shell_view, "/memo-popup", button_event, NULL); + e_cal_base_shell_view_show_popup_menu (shell_view, "memo-popup", button_event, NULL); } static gboolean @@ -37,7 +37,7 @@ memo_shell_view_selector_popup_event_cb (EShellView *shell_view, ESource *clicked_source, GdkEvent *button_event) { - e_cal_base_shell_view_show_popup_menu (shell_view, "/memo-list-popup", button_event, clicked_source); + e_cal_base_shell_view_show_popup_menu (shell_view, "memo-list-popup", button_event, clicked_source); return TRUE; } @@ -86,6 +86,37 @@ memo_shell_view_notify_view_id_cb (EShellView *shell_view) gal_view_instance_set_current_view_id (view_instance, view_id); } +static void +memo_shell_view_task_view_notify_state_cb (GObject *object, + GParamSpec *param, + gpointer user_data) +{ + GAction *action = G_ACTION (object); + EMemoShellView *memo_shell_view = user_data; + EMemoShellContent *memo_shell_content; + GtkOrientable *orientable; + GtkOrientation orientation; + GVariant *state; + + memo_shell_content = memo_shell_view->priv->memo_shell_content; + orientable = GTK_ORIENTABLE (memo_shell_content); + state = g_action_get_state (action); + + switch (g_variant_get_int32 (state)) { + case 0: + orientation = GTK_ORIENTATION_VERTICAL; + break; + case 1: + orientation = GTK_ORIENTATION_HORIZONTAL; + break; + default: + g_return_if_reached (); + } + + gtk_orientable_set_orientation (orientable, orientation); + g_clear_pointer (&state, g_variant_unref); +} + void e_memo_shell_view_private_init (EMemoShellView *memo_shell_view) { @@ -104,6 +135,11 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view) EShellWindow *shell_window; EShellView *shell_view; EShell *shell; + EShellSearchbar *searchbar; + EPreviewPane *preview_pane; + EWebView *web_view; + EUIAction *action; + GSettings *settings; gulong handler_id; shell_view = E_SHELL_VIEW (memo_shell_view); @@ -113,9 +149,6 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view) shell_window = e_shell_view_get_shell_window (shell_view); shell = e_shell_window_get_shell (shell_window); - e_shell_window_add_action_group_full (shell_window, "memos", "memos"); - e_shell_window_add_action_group_full (shell_window, "memos-filter", "memos"); - /* Cache these to avoid lots of awkward casting. */ priv->memo_shell_backend = E_MEMO_SHELL_BACKEND (g_object_ref (shell_backend)); priv->memo_shell_content = E_MEMO_SHELL_CONTENT (g_object_ref (shell_content)); @@ -213,9 +246,53 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view) (GHookFunc) e_memo_shell_view_update_search_filter, memo_shell_view); - e_memo_shell_view_actions_init (memo_shell_view); + preview_pane = e_memo_shell_content_get_preview_pane (memo_shell_view->priv->memo_shell_content); + web_view = e_preview_pane_get_web_view (preview_pane); + e_web_view_set_open_proxy (web_view, ACTION (MEMO_OPEN)); + e_web_view_set_print_proxy (web_view, ACTION (MEMO_PRINT)); + e_web_view_set_save_as_proxy (web_view, ACTION (MEMO_SAVE_AS)); + + /* Advanced Search Action */ + action = ACTION (MEMO_SEARCH_ADVANCED_HIDDEN); + e_ui_action_set_visible (action, FALSE); + searchbar = e_memo_shell_content_get_searchbar (memo_shell_view->priv->memo_shell_content); + e_shell_searchbar_set_search_option (searchbar, action); + e_memo_shell_view_update_sidebar (memo_shell_view); e_memo_shell_view_update_search_filter (memo_shell_view); + + /* Bind GObject properties to settings keys. */ + + settings = e_util_ref_settings ("org.gnome.evolution.calendar"); + + action = ACTION (MEMO_PREVIEW); + + g_settings_bind ( + settings, "show-memo-preview", + action, "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + e_binding_bind_property ( + action, "active", + priv->memo_shell_content, "preview-visible", + G_BINDING_SYNC_CREATE); + + action = ACTION (MEMO_VIEW_VERTICAL); + + g_settings_bind_with_mapping ( + settings, "memo-layout", + action, "state", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY, + e_shell_view_util_layout_to_state_cb, + e_shell_view_util_state_to_layout_cb, NULL, NULL); + + g_object_unref (settings); + + g_signal_connect_object (action, "notify::state", + G_CALLBACK (memo_shell_view_task_view_notify_state_cb), memo_shell_view, 0); + + /* to propagate the loaded state */ + memo_shell_view_task_view_notify_state_cb (G_OBJECT (action), NULL, memo_shell_view); } void diff --git a/src/modules/calendar/e-memo-shell-view-private.h b/src/modules/calendar/e-memo-shell-view-private.h index 7685d57e15..bb74c25def 100644 --- a/src/modules/calendar/e-memo-shell-view-private.h +++ b/src/modules/calendar/e-memo-shell-view-private.h @@ -38,11 +38,9 @@ #include "e-memo-shell-content.h" #include "e-memo-shell-view-actions.h" -/* Shorthand, requires a variable named "shell_window". */ +/* Shorthand, requires a variable named "shell_view". */ #define ACTION(name) \ - (E_SHELL_WINDOW_ACTION_##name (shell_window)) -#define ACTION_GROUP(name) \ - (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window)) + (E_SHELL_VIEW_ACTION_##name (shell_view)) G_BEGIN_DECLS diff --git a/src/modules/calendar/e-memo-shell-view.c b/src/modules/calendar/e-memo-shell-view.c index c2f18e9597..ecb75d4151 100644 --- a/src/modules/calendar/e-memo-shell-view.c +++ b/src/modules/calendar/e-memo-shell-view.c @@ -30,29 +30,30 @@ static void memo_shell_view_execute_search (EShellView *shell_view) { EMemoShellContent *memo_shell_content; - EShellWindow *shell_window; EShellContent *shell_content; EShellSearchbar *searchbar; EActionComboBox *combo_box; - GtkRadioAction *action; + EUIAction *action; ECalComponentPreview *memo_preview; EPreviewPane *preview_pane; EMemoTable *memo_table; EWebView *web_view; ECalModel *model; ECalDataModel *data_model; + GVariant *state; gchar *query; gchar *temp; gint value; shell_content = e_shell_view_get_shell_content (shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content); searchbar = e_memo_shell_content_get_searchbar (memo_shell_content); - action = GTK_RADIO_ACTION (ACTION (MEMO_SEARCH_ANY_FIELD_CONTAINS)); - value = gtk_radio_action_get_current_value (action); + action = ACTION (MEMO_SEARCH_ANY_FIELD_CONTAINS); + state = g_action_get_state (G_ACTION (action)); + value = g_variant_get_int32 (state); + g_clear_pointer (&state, g_variant_unref); if (value == MEMO_SEARCH_ADVANCED) { query = e_shell_view_get_search_query (shell_view); @@ -149,8 +150,7 @@ memo_shell_view_update_actions (EShellView *shell_view) { EShellContent *shell_content; EShellSidebar *shell_sidebar; - EShellWindow *shell_window; - GtkAction *action; + EUIAction *action; const gchar *label; gboolean sensitive; guint32 state; @@ -175,8 +175,6 @@ memo_shell_view_update_actions (EShellView *shell_view) E_SHELL_VIEW_CLASS (e_memo_shell_view_parent_class)-> update_actions (shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - shell_content = e_shell_view_get_shell_content (shell_view); state = e_shell_content_check_state (shell_content); @@ -215,80 +213,88 @@ memo_shell_view_update_actions (EShellView *shell_view) action = ACTION (MEMO_LIST_SELECT_ALL); sensitive = clicked_source_is_primary && !all_sources_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_SELECT_ONE); sensitive = clicked_source_is_primary; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_DELETE); sensitive = any_memos_selected && sources_are_editable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); if (multiple_memos_selected) label = _("Delete Memos"); else label = _("Delete Memo"); - gtk_action_set_label (action, label); + e_ui_action_set_label (action, label); action = ACTION (MEMO_FIND); sensitive = single_memo_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_FORWARD); sensitive = single_memo_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_COPY); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_DELETE); sensitive = primary_source_is_removable || primary_source_is_remote_deletable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_PRINT); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_PRINT_PREVIEW); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_PROPERTIES); sensitive = clicked_source_is_primary && primary_source_is_writable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_REFRESH); sensitive = clicked_source_is_primary && refresh_supported; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_REFRESH_BACKEND); sensitive = clicked_source_is_collection; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_LIST_RENAME); sensitive = clicked_source_is_primary && ( primary_source_is_writable && !primary_source_in_collection); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_OPEN); sensitive = single_memo_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_OPEN_URL); sensitive = single_memo_selected && selection_has_url; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_PRINT); sensitive = single_memo_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MEMO_SAVE_AS); sensitive = single_memo_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); +} + +static void +memo_shell_view_init_ui_data (EShellView *shell_view) +{ + g_return_if_fail (E_IS_MEMO_SHELL_VIEW (shell_view)); + + e_memo_shell_view_actions_init (E_MEMO_SHELL_VIEW (shell_view)); } static void @@ -312,10 +318,18 @@ memo_shell_view_finalize (GObject *object) static void memo_shell_view_constructed (GObject *object) { + EUIManager *ui_manager; + + ui_manager = e_shell_view_get_ui_manager (E_SHELL_VIEW (object)); + + e_ui_manager_freeze (ui_manager); + /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_memo_shell_view_parent_class)->constructed (object); e_memo_shell_view_private_constructed (E_MEMO_SHELL_VIEW (object)); + + e_ui_manager_thaw (ui_manager); } static void @@ -333,14 +347,14 @@ e_memo_shell_view_class_init (EMemoShellViewClass *class) shell_view_class = E_SHELL_VIEW_CLASS (class); shell_view_class->label = _("Memos"); shell_view_class->icon_name = "evolution-memos"; - shell_view_class->ui_definition = "evolution-memos.ui"; + shell_view_class->ui_definition = "evolution-memos.eui"; shell_view_class->ui_manager_id = "org.gnome.evolution.memos"; - shell_view_class->search_options = "/memo-search-options"; shell_view_class->search_rules = "memotypes.xml"; shell_view_class->new_shell_content = e_memo_shell_content_new; shell_view_class->new_shell_sidebar = e_cal_base_shell_sidebar_new; shell_view_class->execute_search = memo_shell_view_execute_search; shell_view_class->update_actions = memo_shell_view_update_actions; + shell_view_class->init_ui_data = memo_shell_view_init_ui_data; cal_base_shell_view_class = E_CAL_BASE_SHELL_VIEW_CLASS (class); cal_base_shell_view_class->source_type = E_CAL_CLIENT_SOURCE_TYPE_MEMOS; diff --git a/src/modules/calendar/e-task-shell-backend.c b/src/modules/calendar/e-task-shell-backend.c index be26eebb93..28a521e707 100644 --- a/src/modules/calendar/e-task-shell-backend.c +++ b/src/modules/calendar/e-task-shell-backend.c @@ -35,9 +35,11 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (ETaskShellBackend, e_task_shell_backend, E_TYPE_ G_ADD_PRIVATE_DYNAMIC (ETaskShellBackend)) static void -action_task_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_task_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShellView *shell_view; ESource *selected_source = NULL; @@ -53,45 +55,22 @@ action_task_new_cb (GtkAction *action, e_cal_ops_new_component_editor (shell_window, E_CAL_CLIENT_SOURCE_TYPE_TASKS, selected_source ? e_source_get_uid (selected_source) : NULL, - g_strcmp0 (gtk_action_get_name (action), "task-assigned-new") == 0); + g_strcmp0 (g_action_get_name (G_ACTION (action)), "task-assigned-new") == 0 || + g_strcmp0 (g_action_get_name (G_ACTION (action)), "new-menu-task-assigned-new") == 0 ); g_clear_object (&selected_source); } static void -action_task_list_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_task_list_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; + e_cal_base_shell_backend_util_new_source (shell_window, E_CAL_CLIENT_SOURCE_TYPE_TASKS); } -static GtkActionEntry item_entries[] = { - - { "task-new", - "stock_task", - NC_("New", "_Task"), - "t", - N_("Create a new task"), - G_CALLBACK (action_task_new_cb) }, - - { "task-assigned-new", - "stock_task-assigned-to", - NC_("New", "Assigne_d Task"), - "i", - N_("Create a new assigned task"), - G_CALLBACK (action_task_new_cb) } -}; - -static GtkActionEntry source_entries[] = { - - { "task-list-new", - "stock_todo", - NC_("New", "Tas_k List"), - NULL, - N_("Create a new task list"), - G_CALLBACK (action_task_list_new_cb) } -}; - static gboolean e_task_shell_backend_handle_uri (EShellBackend *shell_backend, const gchar *uri) @@ -106,6 +85,31 @@ e_task_shell_backend_handle_uri (EShellBackend *shell_backend, static void e_task_shell_backend_class_init (ETaskShellBackendClass *class) { + static const EUIActionEntry item_entries[] = { + { "new-menu-task-new", + "stock_task", + NC_("New", "_Task"), + "t", + N_("Create a new task"), + action_task_new_cb, NULL, NULL, NULL }, + + { "new-menu-task-assigned-new", + "stock_task-assigned-to", + NC_("New", "Assigne_d Task"), + "i", + N_("Create a new assigned task"), + action_task_new_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry source_entries[] = { + { "new-menu-task-list-new", + "stock_todo", + NC_("New", "Tas_k List"), + NULL, + N_("Create a new task list"), + action_task_list_new_cb, NULL, NULL, NULL } + }; + EShellBackendClass *shell_backend_class; ECalBaseShellBackendClass *cal_base_shell_backend_class; diff --git a/src/modules/calendar/e-task-shell-view-actions.c b/src/modules/calendar/e-task-shell-view-actions.c index 97ef06be89..6a6ea99e1b 100644 --- a/src/modules/calendar/e-task-shell-view-actions.c +++ b/src/modules/calendar/e-task-shell-view-actions.c @@ -29,9 +29,11 @@ #include "e-cal-shell-view.h" static void -action_task_assign_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_assign_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ECalModelComponent *comp_data; ETaskTable *task_table; @@ -52,9 +54,11 @@ action_task_assign_cb (GtkAction *action, } static void -action_task_bulk_edit_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_bulk_edit_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ETaskTable *task_table; GtkWidget *bulk_edit; @@ -74,9 +78,11 @@ action_task_bulk_edit_cb (GtkAction *action, } static void -action_task_delete_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ETaskTable *task_table; @@ -87,9 +93,11 @@ action_task_delete_cb (GtkAction *action, } static void -action_task_find_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_find_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; EPreviewPane *preview_pane; @@ -100,9 +108,11 @@ action_task_find_cb (GtkAction *action, } static void -action_task_forward_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ECalModelComponent *comp_data; ETaskTable *task_table; @@ -132,16 +142,21 @@ action_task_forward_cb (GtkAction *action, } static void -action_task_list_copy_cb (GtkAction *action, - EShellView *shell_view) +action_task_list_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; + e_cal_base_shell_view_copy_calendar (shell_view); } static void -action_task_list_delete_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ECalBaseShellSidebar *task_shell_sidebar; EShellWindow *shell_window; EShellView *shell_view; @@ -181,9 +196,11 @@ action_task_list_delete_cb (GtkAction *action, } static void -action_task_list_manage_groups_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_manage_groups_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; EShellView *shell_view; ESourceSelector *selector; @@ -197,9 +214,11 @@ action_task_list_manage_groups_cb (GtkAction *action, static void -action_task_list_new_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -224,7 +243,7 @@ action_task_list_new_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title (GTK_WINDOW (dialog), _("New Task List")); @@ -233,9 +252,11 @@ action_task_list_new_cb (GtkAction *action, } static void -action_task_list_print_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ETaskTable *task_table; @@ -248,9 +269,11 @@ action_task_list_print_cb (GtkAction *action, } static void -action_task_list_print_preview_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_print_preview_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ETaskTable *task_table; @@ -263,9 +286,11 @@ action_task_list_print_preview_cb (GtkAction *action, } static void -action_task_list_properties_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_properties_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ECalBaseShellSidebar *task_shell_sidebar; @@ -296,7 +321,7 @@ action_task_list_properties_cb (GtkAction *action, gtk_window_set_transient_for ( GTK_WINDOW (dialog), GTK_WINDOW (shell_window)); - icon_name = gtk_action_get_icon_name (action); + icon_name = e_ui_action_get_icon_name (action); gtk_window_set_icon_name (GTK_WINDOW (dialog), icon_name); gtk_window_set_title (GTK_WINDOW (dialog), _("Task List Properties")); @@ -305,9 +330,11 @@ action_task_list_properties_cb (GtkAction *action, } static void -action_task_list_refresh_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_refresh_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ECalBaseShellSidebar *task_shell_sidebar; ESourceSelector *selector; EClient *client = NULL; @@ -335,9 +362,11 @@ action_task_list_refresh_cb (GtkAction *action, } static void -action_task_list_refresh_backend_cb (GtkAction *action, - EShellView *shell_view) +action_task_list_refresh_backend_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; ESource *source; g_return_if_fail (E_IS_TASK_SHELL_VIEW (shell_view)); @@ -349,9 +378,11 @@ action_task_list_refresh_backend_cb (GtkAction *action, } static void -action_task_list_rename_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_rename_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ECalBaseShellSidebar *task_shell_sidebar; ESourceSelector *selector; @@ -362,9 +393,11 @@ action_task_list_rename_cb (GtkAction *action, } static void -action_task_list_select_all_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_select_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ECalBaseShellSidebar *task_shell_sidebar; ESourceSelector *selector; @@ -375,9 +408,11 @@ action_task_list_select_all_cb (GtkAction *action, } static void -action_task_list_select_one_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_list_select_one_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ECalBaseShellSidebar *task_shell_sidebar; ESourceSelector *selector; ESource *primary; @@ -394,9 +429,11 @@ action_task_list_select_one_cb (GtkAction *action, } static void -action_task_mark_complete_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_mark_complete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ETaskTable *task_table; ECalModel *model; @@ -417,9 +454,11 @@ action_task_mark_complete_cb (GtkAction *action, } static void -action_task_mark_incomplete_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_mark_incomplete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ETaskTable *task_table; ECalModel *model; @@ -440,9 +479,11 @@ action_task_mark_incomplete_cb (GtkAction *action, } static void -action_task_new_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ETaskShellContent *task_shell_content; @@ -472,9 +513,11 @@ action_task_new_cb (GtkAction *action, } static void -action_task_open_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_open_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ECalModelComponent *comp_data; ETaskTable *task_table; @@ -493,9 +536,11 @@ action_task_open_cb (GtkAction *action, } static void -action_task_open_url_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_open_url_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; ETaskShellContent *task_shell_content; @@ -526,21 +571,11 @@ action_task_open_url_cb (GtkAction *action, } static void -action_task_preview_cb (GtkToggleAction *action, - ETaskShellView *task_shell_view) -{ - ETaskShellContent *task_shell_content; - gboolean visible; - - task_shell_content = task_shell_view->priv->task_shell_content; - visible = gtk_toggle_action_get_active (action); - e_task_shell_content_set_preview_visible (task_shell_content, visible); -} - -static void -action_task_print_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_print_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; ETaskShellContent *task_shell_content; ECalModelComponent *comp_data; ECalComponent *comp; @@ -570,9 +605,11 @@ action_task_print_cb (GtkAction *action, } static void -action_task_purge_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_purge_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; GtkWidget *content_area; @@ -620,9 +657,11 @@ purge: } static void -action_task_save_as_cb (GtkAction *action, - ETaskShellView *task_shell_view) +action_task_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ETaskShellView *task_shell_view = user_data; EShell *shell; EShellView *shell_view; EShellWindow *shell_window; @@ -682,540 +721,281 @@ action_task_save_as_cb (GtkAction *action, g_object_unref (file); } -static void -action_task_view_cb (GtkRadioAction *action, - GtkRadioAction *current, - ETaskShellView *task_shell_view) -{ - ETaskShellContent *task_shell_content; - GtkOrientable *orientable; - GtkOrientation orientation; - - task_shell_content = task_shell_view->priv->task_shell_content; - orientable = GTK_ORIENTABLE (task_shell_content); - - switch (gtk_radio_action_get_current_value (action)) { - case 0: - orientation = GTK_ORIENTATION_VERTICAL; - break; - case 1: - orientation = GTK_ORIENTATION_HORIZONTAL; - break; - default: - g_return_if_reached (); - } - - gtk_orientable_set_orientation (orientable, orientation); -} - -static GtkActionEntry task_entries[] = { - - { "task-assign", - "stock_task-assigned-to", - N_("_Assign Task"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_task_assign_cb) }, - - { "task-bulk-edit", - NULL, - N_("_Bulk Edit…"), - "b", - N_("Edit selected tasks in a bulk"), - G_CALLBACK (action_task_bulk_edit_cb) }, - - { "task-delete", - "edit-delete", - N_("_Delete Task"), - NULL, - N_("Delete selected tasks"), - G_CALLBACK (action_task_delete_cb) }, - - { "task-find", - "edit-find", - N_("_Find in Task…"), - "f", - N_("Search for text in the displayed task"), - G_CALLBACK (action_task_find_cb) }, - - { "task-forward", - "mail-forward", - N_("_Forward as iCalendar…"), - "f", - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_task_forward_cb) }, - - { "task-list-copy", - "edit-copy", - N_("_Copy…"), - "c", - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_task_list_copy_cb) }, - - { "task-list-delete", - "edit-delete", - N_("D_elete Task List"), - NULL, - N_("Delete the selected task list"), - G_CALLBACK (action_task_list_delete_cb) }, - - { "task-list-manage-groups", - NULL, - N_("_Manage Task List groups…"), - NULL, - N_("Manage task list groups order and visibility"), - G_CALLBACK (action_task_list_manage_groups_cb) }, - - { "task-list-new", - "stock_todo", - N_("_New Task List"), - NULL, - N_("Create a new task list"), - G_CALLBACK (action_task_list_new_cb) }, - - { "task-list-properties", - "document-properties", - N_("_Properties"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_task_list_properties_cb) }, - - { "task-list-refresh", - "view-refresh", - N_("Re_fresh"), - NULL, - N_("Refresh the selected task list"), - G_CALLBACK (action_task_list_refresh_cb) }, - - { "task-list-refresh-backend", - "view-refresh", - N_("Re_fresh list of account task lists"), - NULL, - NULL, - G_CALLBACK (action_task_list_refresh_backend_cb) }, - - { "task-list-rename", - NULL, - N_("_Rename…"), - "F2", - N_("Rename the selected task list"), - G_CALLBACK (action_task_list_rename_cb) }, - - { "task-list-select-all", - "stock_check-filled", - N_("Sho_w All Task Lists"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_task_list_select_all_cb) }, - - { "task-list-select-one", - "stock_check-filled", - N_("Show _Only This Task List"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_task_list_select_one_cb) }, - - { "task-mark-complete", - NULL, - N_("_Mark as Complete"), - "k", - N_("Mark selected tasks as complete"), - G_CALLBACK (action_task_mark_complete_cb) }, - - { "task-mark-incomplete", - NULL, - N_("Mar_k as Incomplete"), - NULL, - N_("Mark selected tasks as incomplete"), - G_CALLBACK (action_task_mark_incomplete_cb) }, - - { "task-new", - "stock_task", - N_("New _Task"), - NULL, - N_("Create a new task"), - G_CALLBACK (action_task_new_cb) }, - - { "task-open", - "document-open", - N_("_Open Task"), - "o", - N_("View the selected task"), - G_CALLBACK (action_task_open_cb) }, - - { "task-open-url", - "applications-internet", - N_("Open _Web Page"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_task_open_url_cb) }, - - { "task-purge", - NULL, - N_("Purg_e"), - "e", - N_("Delete completed tasks"), - G_CALLBACK (action_task_purge_cb) }, - - /*** Menus ***/ - - { "task-actions-menu", - NULL, - N_("_Actions"), - NULL, - NULL, - NULL }, - - { "task-preview-menu", - NULL, - N_("_Preview"), - NULL, - NULL, - NULL } -}; - -static EPopupActionEntry task_popup_entries[] = { - - { "task-list-popup-copy", - NULL, - "task-list-copy" }, - - { "task-list-popup-delete", - N_("_Delete"), - "task-list-delete" }, - - { "task-list-popup-manage-groups", - N_("_Manage groups…"), - "task-list-manage-groups" }, - - { "task-list-popup-properties", - NULL, - "task-list-properties" }, - - { "task-list-popup-refresh", - NULL, - "task-list-refresh" }, - - { "task-list-popup-refresh-backend", - NULL, - "task-list-refresh-backend" }, - - { "task-list-popup-rename", - NULL, - "task-list-rename" }, - - { "task-list-popup-select-all", - NULL, - "task-list-select-all" }, - - { "task-list-popup-select-one", - NULL, - "task-list-select-one" }, - - { "task-popup-assign", - NULL, - "task-assign" }, - - { "task-popup-forward", - NULL, - "task-forward" }, - - { "task-popup-mark-complete", - NULL, - "task-mark-complete" }, - - { "task-popup-mark-incomplete", - NULL, - "task-mark-incomplete" }, - - { "task-popup-open", - NULL, - "task-open" }, - - { "task-popup-open-url", - NULL, - "task-open-url" } -}; - -static GtkToggleActionEntry task_toggle_entries[] = { - - { "task-preview", - NULL, - N_("Task _Preview"), - "m", - N_("Show task preview pane"), - G_CALLBACK (action_task_preview_cb), - TRUE } -}; - -static GtkRadioActionEntry task_view_entries[] = { - - /* This action represents the inital active memo view. - * It should not be visible in the UI, nor should it be - * possible to switch to it from another shell view. */ - { "task-view-initial", - NULL, - NULL, - NULL, - NULL, - -1 }, - - { "task-view-classic", - NULL, - N_("_Classic View"), - NULL, - N_("Show task preview below the task list"), - 0 }, - - { "task-view-vertical", - NULL, - N_("_Vertical View"), - NULL, - N_("Show task preview alongside the task list"), - 1 } -}; - -static GtkRadioActionEntry task_filter_entries[] = { - - { "task-filter-active-tasks", - NULL, - N_("Active Tasks"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_FILTER_ACTIVE_TASKS }, - - { "task-filter-any-category", - NULL, - N_("Any Category"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_FILTER_ANY_CATEGORY }, - - { "task-filter-cancelled-tasks", - NULL, - N_("Cancelled Tasks"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_FILTER_CANCELLED_TASKS }, - - { "task-filter-completed-tasks", - NULL, - N_("Completed Tasks"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_FILTER_COMPLETED_TASKS }, - - { "task-filter-uncompleted-tasks", - NULL, - N_("Uncompleted Tasks"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_FILTER_UNCOMPLETED_TASKS }, - - { "task-filter-scheduled-tasks", - NULL, - N_("Scheduled Tasks"), - NULL, - N_("Show scheduled tasks, aka those with a Due date"), - TASK_FILTER_SCHEDULED_TASKS }, - - { "task-filter-next-7-days-tasks", - NULL, - N_("Next 7 Days’ Tasks"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_FILTER_NEXT_7_DAYS_TASKS }, - - { "task-filter-overdue-tasks", - NULL, - N_("Overdue Tasks"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_FILTER_OVERDUE_TASKS }, - - { "task-filter-tasks-with-attachments", - NULL, - N_("Tasks with Attachments"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_FILTER_TASKS_WITH_ATTACHMENTS }, - - { "task-filter-unmatched", - NULL, - N_("Without Category"), - NULL, - N_("Show tasks with no category set"), - TASK_FILTER_UNMATCHED }, - - { "task-filter-started", - NULL, - N_("Started Tasks"), - NULL, - N_("Filters for tasks that either do not have a start date or the start date is earlier than the time the filter is selected at"), - TASK_FILTER_STARTED } -}; - -static GtkRadioActionEntry task_search_entries[] = { - - { "task-search-advanced-hidden", - NULL, - N_("Advanced Search"), - NULL, - NULL, - TASK_SEARCH_ADVANCED }, - - { "task-search-any-field-contains", - NULL, - N_("Any field contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_SEARCH_ANY_FIELD_CONTAINS }, - - { "task-search-description-contains", - NULL, - N_("Description contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_SEARCH_DESCRIPTION_CONTAINS }, - - { "task-search-summary-contains", - NULL, - N_("Summary contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - TASK_SEARCH_SUMMARY_CONTAINS } -}; - -static GtkActionEntry lockdown_printing_entries[] = { - - { "task-list-print", - "document-print", - N_("Print…"), - "p", - N_("Print the list of tasks"), - G_CALLBACK (action_task_list_print_cb) }, - - { "task-list-print-preview", - "document-print-preview", - N_("Pre_view…"), - NULL, - N_("Preview the list of tasks to be printed"), - G_CALLBACK (action_task_list_print_preview_cb) }, - - { "task-print", - "document-print", - N_("Print…"), - NULL, - N_("Print the selected task"), - G_CALLBACK (action_task_print_cb) } -}; - -static EPopupActionEntry lockdown_printing_popup_entries[] = { - - { "task-popup-print", - NULL, - "task-print" } -}; - -static GtkActionEntry lockdown_save_to_disk_entries[] = { - - { "task-save-as", - "document-save-as", - N_("_Save as iCalendar…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_task_save_as_cb) } -}; - -static EPopupActionEntry lockdown_save_to_disk_popup_entries[] = { - - { "task-popup-save-as", - NULL, - "task-save-as" }, -}; - void -e_task_shell_view_actions_init (ETaskShellView *task_shell_view) +e_task_shell_view_actions_init (ETaskShellView *self) { - ETaskShellContent *task_shell_content; + static const EUIActionEntry task_entries[] = { + + { "task-assign", + "stock_task-assigned-to", + N_("_Assign Task"), + NULL, + NULL, + action_task_assign_cb, NULL, NULL, NULL }, + + { "task-bulk-edit", + NULL, + N_("_Bulk Edit…"), + "b", + N_("Edit selected tasks in a bulk"), + action_task_bulk_edit_cb, NULL, NULL, NULL }, + + { "task-delete", + "edit-delete", + N_("_Delete Task"), + NULL, + N_("Delete selected tasks"), + action_task_delete_cb, NULL, NULL, NULL }, + + { "task-find", + "edit-find", + N_("_Find in Task…"), + "f", + N_("Search for text in the displayed task"), + action_task_find_cb, NULL, NULL, NULL }, + + { "task-forward", + "mail-forward", + N_("_Forward as iCalendar…"), + "f", + NULL, + action_task_forward_cb, NULL, NULL, NULL }, + + { "task-list-copy", + "edit-copy", + N_("_Copy…"), + NULL, + NULL, + action_task_list_copy_cb, NULL, NULL, NULL }, + + { "task-list-delete", + "edit-delete", + N_("D_elete Task List"), + NULL, + N_("Delete the selected task list"), + action_task_list_delete_cb, NULL, NULL, NULL }, + + { "task-list-manage-groups", + NULL, + N_("_Manage Task List groups…"), + NULL, + N_("Manage task list groups order and visibility"), + action_task_list_manage_groups_cb, NULL, NULL, NULL }, + + { "task-list-manage-groups-popup", + NULL, + N_("_Manage groups…"), + NULL, + N_("Manage task list groups order and visibility"), + action_task_list_manage_groups_cb, NULL, NULL, NULL }, + + { "task-list-new", + "stock_todo", + N_("_New Task List"), + NULL, + N_("Create a new task list"), + action_task_list_new_cb, NULL, NULL, NULL }, + + { "task-list-properties", + "document-properties", + N_("_Properties"), + NULL, + NULL, + action_task_list_properties_cb, NULL, NULL, NULL }, + + { "task-list-refresh", + "view-refresh", + N_("Re_fresh"), + NULL, + N_("Refresh the selected task list"), + action_task_list_refresh_cb, NULL, NULL, NULL }, + + { "task-list-refresh-backend", + "view-refresh", + N_("Re_fresh list of account task lists"), + NULL, + NULL, + action_task_list_refresh_backend_cb, NULL, NULL, NULL }, + + { "task-list-rename", + NULL, + N_("_Rename…"), + NULL, + N_("Rename the selected task list"), + action_task_list_rename_cb, NULL, NULL, NULL }, + + { "task-list-select-all", + "stock_check-filled", + N_("Sho_w All Task Lists"), + NULL, + NULL, + action_task_list_select_all_cb, NULL, NULL, NULL }, + + { "task-list-select-one", + "stock_check-filled", + N_("Show _Only This Task List"), + NULL, + NULL, + action_task_list_select_one_cb, NULL, NULL, NULL }, + + { "task-mark-complete", + NULL, + N_("_Mark as Complete"), + "k", + N_("Mark selected tasks as complete"), + action_task_mark_complete_cb, NULL, NULL, NULL }, + + { "task-mark-incomplete", + NULL, + N_("Mar_k as Incomplete"), + NULL, + N_("Mark selected tasks as incomplete"), + action_task_mark_incomplete_cb, NULL, NULL, NULL }, + + { "task-new", + "stock_task", + N_("New _Task"), + NULL, + N_("Create a new task"), + action_task_new_cb, NULL, NULL, NULL }, + + { "task-open", + "document-open", + N_("_Open Task"), + "o", + N_("View the selected task"), + action_task_open_cb, NULL, NULL, NULL }, + + { "task-open-url", + "applications-internet", + N_("Open _Web Page"), + NULL, + NULL, + action_task_open_url_cb, NULL, NULL, NULL }, + + { "task-purge", + NULL, + N_("Purg_e"), + "e", + N_("Delete completed tasks"), + action_task_purge_cb, NULL, NULL, NULL }, + + { "task-preview", + NULL, + N_("Task _Preview"), + "m", + N_("Show task preview pane"), + NULL, NULL, "true", NULL }, + + /*** Menus ***/ + + { "task-actions-menu", NULL, N_("_Actions"), NULL, NULL, NULL }, + { "task-preview-menu", NULL, N_("_Preview"), NULL, NULL, NULL } + }; + + static const EUIActionEnumEntry task_view_entries[] = { + + { "task-view-classic", + NULL, + N_("_Classic View"), + NULL, + N_("Show task preview below the task list"), + NULL, 0 }, + + { "task-view-vertical", + NULL, + N_("_Vertical View"), + NULL, + N_("Show task preview alongside the task list"), + NULL, 1 } + }; + + static const EUIActionEnumEntry task_search_entries[] = { + + { "task-search-advanced-hidden", + NULL, + N_("Advanced Search"), + NULL, + NULL, + NULL, TASK_SEARCH_ADVANCED }, + + { "task-search-any-field-contains", + NULL, + N_("Any field contains"), + NULL, + NULL, + NULL, TASK_SEARCH_ANY_FIELD_CONTAINS }, + + { "task-search-description-contains", + NULL, + N_("Description contains"), + NULL, + NULL, + NULL, TASK_SEARCH_DESCRIPTION_CONTAINS }, + + { "task-search-summary-contains", + NULL, + N_("Summary contains"), + NULL, + NULL, + NULL, TASK_SEARCH_SUMMARY_CONTAINS } + }; + + static const EUIActionEntry lockdown_printing_entries[] = { + + { "task-list-print", + "document-print", + N_("Print…"), + "p", + N_("Print the list of tasks"), + action_task_list_print_cb, NULL, NULL, NULL }, + + { "task-list-print-preview", + "document-print-preview", + N_("Pre_view…"), + NULL, + N_("Preview the list of tasks to be printed"), + action_task_list_print_preview_cb, NULL, NULL, NULL }, + + { "task-print", + "document-print", + N_("Print…"), + NULL, + N_("Print the selected task"), + action_task_print_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry lockdown_save_to_disk_entries[] = { + + { "task-save-as", + "document-save-as", + N_("_Save as iCalendar…"), + NULL, + NULL, + action_task_save_as_cb, NULL, NULL, NULL } + }; + EShellView *shell_view; - EShellWindow *shell_window; - EShellSearchbar *searchbar; - EPreviewPane *preview_pane; - EWebView *web_view; - GtkActionGroup *action_group; - GSettings *settings; - GtkAction *action; + EUIManager *ui_manager; - shell_view = E_SHELL_VIEW (task_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - - task_shell_content = task_shell_view->priv->task_shell_content; - searchbar = e_task_shell_content_get_searchbar (task_shell_content); - preview_pane = e_task_shell_content_get_preview_pane (task_shell_content); - web_view = e_preview_pane_get_web_view (preview_pane); + shell_view = E_SHELL_VIEW (self); + ui_manager = e_shell_view_get_ui_manager (shell_view); /* Task Actions */ - action_group = ACTION_GROUP (TASKS); - gtk_action_group_add_actions ( - action_group, task_entries, - G_N_ELEMENTS (task_entries), task_shell_view); - e_action_group_add_popup_actions ( - action_group, task_popup_entries, - G_N_ELEMENTS (task_popup_entries)); - gtk_action_group_add_toggle_actions ( - action_group, task_toggle_entries, - G_N_ELEMENTS (task_toggle_entries), task_shell_view); - gtk_action_group_add_radio_actions ( - action_group, task_view_entries, - G_N_ELEMENTS (task_view_entries), -1, - G_CALLBACK (action_task_view_cb), task_shell_view); - gtk_action_group_add_radio_actions ( - action_group, task_search_entries, - G_N_ELEMENTS (task_search_entries), - -1, NULL, NULL); - - /* Advanced Search Action */ - action = ACTION (TASK_SEARCH_ADVANCED_HIDDEN); - gtk_action_set_visible (action, FALSE); - e_shell_searchbar_set_search_option ( - searchbar, GTK_RADIO_ACTION (action)); + e_ui_manager_add_actions (ui_manager, "tasks", NULL, + task_entries, G_N_ELEMENTS (task_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "tasks", NULL, + task_view_entries, G_N_ELEMENTS (task_view_entries), self); + e_ui_manager_add_actions_enum (ui_manager, "tasks", NULL, + task_search_entries, G_N_ELEMENTS (task_search_entries), self); /* Lockdown Printing Actions */ - action_group = ACTION_GROUP (LOCKDOWN_PRINTING); - gtk_action_group_add_actions ( - action_group, lockdown_printing_entries, - G_N_ELEMENTS (lockdown_printing_entries), - task_shell_view); - e_action_group_add_popup_actions ( - action_group, lockdown_printing_popup_entries, - G_N_ELEMENTS (lockdown_printing_popup_entries)); + e_ui_manager_add_actions (ui_manager, "lockdown-printing", NULL, + lockdown_printing_entries, G_N_ELEMENTS (lockdown_printing_entries), self); /* Lockdown Save-to-Disk Actions */ - action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK); - gtk_action_group_add_actions ( - action_group, lockdown_save_to_disk_entries, - G_N_ELEMENTS (lockdown_save_to_disk_entries), - task_shell_view); - e_action_group_add_popup_actions ( - action_group, lockdown_save_to_disk_popup_entries, - G_N_ELEMENTS (lockdown_save_to_disk_popup_entries)); - - /* Bind GObject properties to settings keys. */ - - settings = e_util_ref_settings ("org.gnome.evolution.calendar"); - - g_settings_bind ( - settings, "show-task-preview", - ACTION (TASK_PREVIEW), "active", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "task-layout", - ACTION (TASK_VIEW_VERTICAL), "current-value", - G_SETTINGS_BIND_DEFAULT); - - g_object_unref (settings); + e_ui_manager_add_actions (ui_manager, "lockdown-save-to-disk", NULL, + lockdown_save_to_disk_entries, G_N_ELEMENTS (lockdown_save_to_disk_entries), self); /* Fine tuning. */ @@ -1228,45 +1008,119 @@ e_task_shell_view_actions_init (ETaskShellView *task_shell_view) ACTION (TASK_PREVIEW), "active", ACTION (TASK_VIEW_VERTICAL), "sensitive", G_BINDING_SYNC_CREATE); - - e_web_view_set_open_proxy (web_view, ACTION (TASK_OPEN)); - e_web_view_set_print_proxy (web_view, ACTION (TASK_PRINT)); - e_web_view_set_save_as_proxy (web_view, ACTION (TASK_SAVE_AS)); } void e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view) { + static const EUIActionEnumEntry task_filter_entries[] = { + + { "task-filter-active-tasks", + NULL, + N_("Active Tasks"), + NULL, + NULL, + NULL, TASK_FILTER_ACTIVE_TASKS }, + + { "task-filter-any-category", + NULL, + N_("Any Category"), + NULL, + NULL, + NULL, TASK_FILTER_ANY_CATEGORY }, + + { "task-filter-cancelled-tasks", + NULL, + N_("Cancelled Tasks"), + NULL, + NULL, + NULL, TASK_FILTER_CANCELLED_TASKS }, + + { "task-filter-completed-tasks", + NULL, + N_("Completed Tasks"), + NULL, + NULL, + NULL, TASK_FILTER_COMPLETED_TASKS }, + + { "task-filter-uncompleted-tasks", + NULL, + N_("Uncompleted Tasks"), + NULL, + NULL, + NULL, TASK_FILTER_UNCOMPLETED_TASKS }, + + { "task-filter-scheduled-tasks", + NULL, + N_("Scheduled Tasks"), + NULL, + N_("Show scheduled tasks, aka those with a Due date"), + NULL, TASK_FILTER_SCHEDULED_TASKS }, + + { "task-filter-next-7-days-tasks", + NULL, + N_("Next 7 Days’ Tasks"), + NULL, + NULL, + NULL, TASK_FILTER_NEXT_7_DAYS_TASKS }, + + { "task-filter-overdue-tasks", + NULL, + N_("Overdue Tasks"), + NULL, + NULL, + NULL, TASK_FILTER_OVERDUE_TASKS }, + + { "task-filter-tasks-with-attachments", + NULL, + N_("Tasks with Attachments"), + NULL, + NULL, + NULL, TASK_FILTER_TASKS_WITH_ATTACHMENTS }, + + { "task-filter-unmatched", + NULL, + N_("Without Category"), + NULL, + N_("Show tasks with no category set"), + NULL, TASK_FILTER_UNMATCHED }, + + { "task-filter-started", + NULL, + N_("Started Tasks"), + NULL, + N_("Filters for tasks that either do not have a start date or the start date is earlier than the time the filter is selected at"), + NULL, TASK_FILTER_STARTED } + }; + ETaskShellContent *task_shell_content; EShellView *shell_view; - EShellWindow *shell_window; EShellSearchbar *searchbar; EActionComboBox *combo_box; - GtkActionGroup *action_group; - GtkRadioAction *radio_action; + EUIActionGroup *action_group; + EUIAction *action; GList *list, *iter; - GSList *group; + GPtrArray *radio_group; gint ii; shell_view = E_SHELL_VIEW (task_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - action_group = ACTION_GROUP (TASKS_FILTER); - e_action_group_remove_all_actions (action_group); + action_group = e_ui_manager_get_action_group (e_shell_view_get_ui_manager (shell_view), "tasks-filter"); + e_ui_action_group_remove_all (action_group); /* Add the standard filter actions. No callback is needed * because changes in the EActionComboBox are detected and * handled by EShellSearchbar. */ - gtk_action_group_add_radio_actions ( - action_group, task_filter_entries, - G_N_ELEMENTS (task_filter_entries), - TASK_FILTER_ANY_CATEGORY, NULL, NULL); + e_ui_manager_add_actions_enum (e_shell_view_get_ui_manager (shell_view), + e_ui_action_group_get_name (action_group), NULL, + task_filter_entries, G_N_ELEMENTS (task_filter_entries), NULL); - /* Retrieve the radio group from an action we just added. */ - list = gtk_action_group_list_actions (action_group); - radio_action = GTK_RADIO_ACTION (list->data); - group = gtk_radio_action_get_group (radio_action); - g_list_free (list); + radio_group = g_ptr_array_new (); + + for (ii = 0; ii < G_N_ELEMENTS (task_filter_entries); ii++) { + action = e_ui_action_group_get_action (action_group, task_filter_entries[ii].name); + e_ui_action_set_radio_group (action, radio_group); + } /* Build the category actions. */ @@ -1274,14 +1128,14 @@ e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view) for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) { const gchar *category_name = iter->data; gchar *filename; - GtkAction *action; - gchar *action_name; + gchar action_name[128]; - action_name = g_strdup_printf ( - "task-filter-category-%d", ii); - radio_action = gtk_radio_action_new ( - action_name, category_name, NULL, NULL, ii); - g_free (action_name); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "task-filter-category-%d", ii) < sizeof (action_name)); + + action = e_ui_action_new (e_ui_action_group_get_name (action_group), action_name, NULL); + e_ui_action_set_label (action, category_name); + e_ui_action_set_state (action, g_variant_new_int32 (ii)); + e_ui_action_set_radio_group (action, radio_group); /* Convert the category icon file to a themed icon name. */ filename = e_categories_dup_icon_file_for (category_name); @@ -1295,21 +1149,16 @@ e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view) if ((cp = strrchr (basename, '.')) != NULL) *cp = '\0'; - g_object_set ( - radio_action, "icon-name", basename, NULL); + e_ui_action_set_icon_name (action, basename); g_free (basename); } g_free (filename); - gtk_radio_action_set_group (radio_action, group); - group = gtk_radio_action_get_group (radio_action); + e_ui_action_group_add (action_group, action); - /* The action group takes ownership of the action. */ - action = GTK_ACTION (radio_action); - gtk_action_group_add_action (action_group, action); - g_object_unref (radio_action); + g_object_unref (action); } g_list_free_full (list, g_free); @@ -1320,7 +1169,7 @@ e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view) e_shell_view_block_execute_search (shell_view); /* Use any action in the group; doesn't matter which. */ - e_action_combo_box_set_action (combo_box, radio_action); + e_action_combo_box_set_action (combo_box, action); ii = TASK_FILTER_UNMATCHED; e_action_combo_box_add_separator_after (combo_box, ii); @@ -1329,4 +1178,6 @@ e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view) e_action_combo_box_add_separator_after (combo_box, ii); e_shell_view_unblock_execute_search (shell_view); + + g_ptr_array_unref (radio_group); } diff --git a/src/modules/calendar/e-task-shell-view-actions.h b/src/modules/calendar/e-task-shell-view-actions.h index f7c6e33be4..9067c84964 100644 --- a/src/modules/calendar/e-task-shell-view-actions.h +++ b/src/modules/calendar/e-task-shell-view-actions.h @@ -21,100 +21,94 @@ #ifndef E_TASK_SHELL_VIEW_ACTIONS_H #define E_TASK_SHELL_VIEW_ACTIONS_H -#include +#include /* Task Actions */ -#define E_SHELL_WINDOW_ACTION_TASK_ASSIGN(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-assign") -#define E_SHELL_WINDOW_ACTION_TASK_BULK_EDIT(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-bulk-edit") -#define E_SHELL_WINDOW_ACTION_TASK_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-delete") -#define E_SHELL_WINDOW_ACTION_TASK_FIND(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-find") -#define E_SHELL_WINDOW_ACTION_TASK_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-forward") -#define E_SHELL_WINDOW_ACTION_TASK_MARK_COMPLETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-mark-complete") -#define E_SHELL_WINDOW_ACTION_TASK_MARK_INCOMPLETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-mark-incomplete") -#define E_SHELL_WINDOW_ACTION_TASK_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-new") -#define E_SHELL_WINDOW_ACTION_TASK_OPEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-open") -#define E_SHELL_WINDOW_ACTION_TASK_OPEN_URL(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-open-url") -#define E_SHELL_WINDOW_ACTION_TASK_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-preview") -#define E_SHELL_WINDOW_ACTION_TASK_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-print") -#define E_SHELL_WINDOW_ACTION_TASK_PURGE(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-purge") -#define E_SHELL_WINDOW_ACTION_TASK_SAVE_AS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-save-as") -#define E_SHELL_WINDOW_ACTION_TASK_VIEW_CLASSIC(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-view-classic") -#define E_SHELL_WINDOW_ACTION_TASK_VIEW_VERTICAL(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-view-vertical") +#define E_SHELL_VIEW_ACTION_TASK_ASSIGN(view) \ + E_SHELL_VIEW_ACTION ((view), "task-assign") +#define E_SHELL_VIEW_ACTION_TASK_BULK_EDIT(view) \ + E_SHELL_VIEW_ACTION ((view), "task-bulk-edit") +#define E_SHELL_VIEW_ACTION_TASK_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "task-delete") +#define E_SHELL_VIEW_ACTION_TASK_FIND(view) \ + E_SHELL_VIEW_ACTION ((view), "task-find") +#define E_SHELL_VIEW_ACTION_TASK_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "task-forward") +#define E_SHELL_VIEW_ACTION_TASK_MARK_COMPLETE(view) \ + E_SHELL_VIEW_ACTION ((view), "task-mark-complete") +#define E_SHELL_VIEW_ACTION_TASK_MARK_INCOMPLETE(view) \ + E_SHELL_VIEW_ACTION ((view), "task-mark-incomplete") +#define E_SHELL_VIEW_ACTION_TASK_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "task-new") +#define E_SHELL_VIEW_ACTION_TASK_OPEN(view) \ + E_SHELL_VIEW_ACTION ((view), "task-open") +#define E_SHELL_VIEW_ACTION_TASK_OPEN_URL(view) \ + E_SHELL_VIEW_ACTION ((view), "task-open-url") +#define E_SHELL_VIEW_ACTION_TASK_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "task-preview") +#define E_SHELL_VIEW_ACTION_TASK_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "task-print") +#define E_SHELL_VIEW_ACTION_TASK_PURGE(view) \ + E_SHELL_VIEW_ACTION ((view), "task-purge") +#define E_SHELL_VIEW_ACTION_TASK_SAVE_AS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-save-as") +#define E_SHELL_VIEW_ACTION_TASK_VIEW_CLASSIC(view) \ + E_SHELL_VIEW_ACTION ((view), "task-view-classic") +#define E_SHELL_VIEW_ACTION_TASK_VIEW_VERTICAL(view) \ + E_SHELL_VIEW_ACTION ((view), "task-view-vertical") /* Task List Actions */ -#define E_SHELL_WINDOW_ACTION_TASK_LIST_COPY(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-copy") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-delete") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-new") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-print") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_PRINT_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-print-preview") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_PROPERTIES(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-properties") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_REFRESH(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-refresh") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_REFRESH_BACKEND(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-refresh-backend") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_RENAME(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-rename") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_SELECT_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-select-all") -#define E_SHELL_WINDOW_ACTION_TASK_LIST_SELECT_ONE(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-list-select-one") +#define E_SHELL_VIEW_ACTION_TASK_LIST_COPY(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-copy") +#define E_SHELL_VIEW_ACTION_TASK_LIST_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-delete") +#define E_SHELL_VIEW_ACTION_TASK_LIST_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-new") +#define E_SHELL_VIEW_ACTION_TASK_LIST_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-print") +#define E_SHELL_VIEW_ACTION_TASK_LIST_PRINT_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-print-preview") +#define E_SHELL_VIEW_ACTION_TASK_LIST_PROPERTIES(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-properties") +#define E_SHELL_VIEW_ACTION_TASK_LIST_REFRESH(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-refresh") +#define E_SHELL_VIEW_ACTION_TASK_LIST_REFRESH_BACKEND(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-refresh-backend") +#define E_SHELL_VIEW_ACTION_TASK_LIST_RENAME(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-rename") +#define E_SHELL_VIEW_ACTION_TASK_LIST_SELECT_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-select-all") +#define E_SHELL_VIEW_ACTION_TASK_LIST_SELECT_ONE(view) \ + E_SHELL_VIEW_ACTION ((view), "task-list-select-one") /* Task Query Actions */ -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_ACTIVE_TASKS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-active-tasks") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_ANY_CATEGORY(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-any-category") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_CANCELLED_TASKS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-cancelled-tasks") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_COMPLETED_TASKS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-completed-tasks") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_NEXT_7_DAYS_TASKS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-next-7-days-tasks") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_OVERDUE_TASKS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-overdue-tasks") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_SCHEDULED_TASKS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-scheduled-tasks") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_TASKS_WITH_ATTACHMENTS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-tasks-with-attachments") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_TASK_FILTER_STARTED(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-started") -#define E_SHELL_WINDOW_ACTION_TASK_FILTER_UNMATCHED(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-filter-unmatched") -#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_ADVANCED_HIDDEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-search-advanced-hidden") -#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_ANY_FIELD_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-search-any-field-contains") -#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_DESCRIPTION_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-search-description-contains") -#define E_SHELL_WINDOW_ACTION_TASK_SEARCH_SUMMARY_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "task-search-summary-contains") - -/* Action Groups */ -#define E_SHELL_WINDOW_ACTION_GROUP_TASKS(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "tasks") -#define E_SHELL_WINDOW_ACTION_GROUP_TASKS_FILTER(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "tasks-filter") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_ACTIVE_TASKS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-active-tasks") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_ANY_CATEGORY(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-any-category") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_CANCELLED_TASKS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-cancelled-tasks") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_COMPLETED_TASKS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-completed-tasks") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_NEXT_7_DAYS_TASKS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-next-7-days-tasks") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_OVERDUE_TASKS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-overdue-tasks") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_SCHEDULED_TASKS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-scheduled-tasks") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_TASKS_WITH_ATTACHMENTS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-tasks-with-attachments") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_TASK_FILTER_STARTED(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-started") +#define E_SHELL_VIEW_ACTION_TASK_FILTER_UNMATCHED(view) \ + E_SHELL_VIEW_ACTION ((view), "task-filter-unmatched") +#define E_SHELL_VIEW_ACTION_TASK_SEARCH_ADVANCED_HIDDEN(view) \ + E_SHELL_VIEW_ACTION ((view), "task-search-advanced-hidden") +#define E_SHELL_VIEW_ACTION_TASK_SEARCH_ANY_FIELD_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-search-any-field-contains") +#define E_SHELL_VIEW_ACTION_TASK_SEARCH_DESCRIPTION_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-search-description-contains") +#define E_SHELL_VIEW_ACTION_TASK_SEARCH_SUMMARY_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "task-search-summary-contains") #endif /* E_TASK_SHELL_VIEW_ACTIONS_H */ diff --git a/src/modules/calendar/e-task-shell-view-private.c b/src/modules/calendar/e-task-shell-view-private.c index 9420905eb2..1d30575313 100644 --- a/src/modules/calendar/e-task-shell-view-private.c +++ b/src/modules/calendar/e-task-shell-view-private.c @@ -123,7 +123,7 @@ static void task_shell_view_table_popup_event_cb (EShellView *shell_view, GdkEvent *button_event) { - e_cal_base_shell_view_show_popup_menu (shell_view, "/task-popup", button_event, NULL); + e_cal_base_shell_view_show_popup_menu (shell_view, "task-popup", button_event, NULL); } static gboolean @@ -131,7 +131,7 @@ task_shell_view_selector_popup_event_cb (EShellView *shell_view, ESource *clicked_source, GdkEvent *button_event) { - e_cal_base_shell_view_show_popup_menu (shell_view, "/task-list-popup", button_event, clicked_source); + e_cal_base_shell_view_show_popup_menu (shell_view, "task-list-popup", button_event, clicked_source); return TRUE; } @@ -199,6 +199,37 @@ task_shell_view_notify_view_id_cb (EShellView *shell_view) gal_view_instance_set_current_view_id (view_instance, view_id); } +static void +task_shell_view_task_view_notify_state_cb (GObject *object, + GParamSpec *param, + gpointer user_data) +{ + GAction *action = G_ACTION (object); + ETaskShellView *task_shell_view = user_data; + ETaskShellContent *task_shell_content; + GtkOrientable *orientable; + GtkOrientation orientation; + GVariant *state; + + task_shell_content = task_shell_view->priv->task_shell_content; + orientable = GTK_ORIENTABLE (task_shell_content); + state = g_action_get_state (action); + + switch (g_variant_get_int32 (state)) { + case 0: + orientation = GTK_ORIENTATION_VERTICAL; + break; + case 1: + orientation = GTK_ORIENTATION_HORIZONTAL; + break; + default: + g_return_if_reached (); + } + + gtk_orientable_set_orientation (orientable, orientation); + g_clear_pointer (&state, g_variant_unref); +} + void e_task_shell_view_private_init (ETaskShellView *task_shell_view) { @@ -219,6 +250,11 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view) EShellWindow *shell_window; EShellView *shell_view; EShell *shell; + EPreviewPane *preview_pane; + EShellSearchbar *searchbar; + EWebView *web_view; + EUIAction *action; + GSettings *settings; gulong handler_id; shell_view = E_SHELL_VIEW (task_shell_view); @@ -228,9 +264,6 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view) shell_window = e_shell_view_get_shell_window (shell_view); shell = e_shell_window_get_shell (shell_window); - e_shell_window_add_action_group_full (shell_window, "tasks", "tasks"); - e_shell_window_add_action_group_full (shell_window, "tasks-filter", "tasks"); - /* Cache these to avoid lots of awkward casting. */ priv->task_shell_backend = E_TASK_SHELL_BACKEND (g_object_ref (shell_backend)); priv->task_shell_content = E_TASK_SHELL_CONTENT (g_object_ref (shell_content)); @@ -360,7 +393,18 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view) task_shell_view); priv->settings_hide_cancelled_tasks_handler_id = handler_id; - e_task_shell_view_actions_init (task_shell_view); + preview_pane = e_task_shell_content_get_preview_pane (task_shell_view->priv->task_shell_content); + web_view = e_preview_pane_get_web_view (preview_pane); + e_web_view_set_open_proxy (web_view, ACTION (TASK_OPEN)); + e_web_view_set_print_proxy (web_view, ACTION (TASK_PRINT)); + e_web_view_set_save_as_proxy (web_view, ACTION (TASK_SAVE_AS)); + + /* Advanced Search Action */ + action = ACTION (TASK_SEARCH_ADVANCED_HIDDEN); + e_ui_action_set_visible (action, FALSE); + searchbar = e_task_shell_content_get_searchbar (task_shell_view->priv->task_shell_content); + e_shell_searchbar_set_search_option (searchbar, action); + e_task_shell_view_update_sidebar (task_shell_view); e_task_shell_view_update_search_filter (task_shell_view); @@ -371,6 +415,39 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view) G_PRIORITY_LOW, 60000, task_shell_view_update_timeout_cb, task_shell_view, NULL); + + /* Bind GObject properties to settings keys. */ + + settings = e_util_ref_settings ("org.gnome.evolution.calendar"); + + action = ACTION (TASK_PREVIEW); + + g_settings_bind ( + settings, "show-task-preview", + action, "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + e_binding_bind_property ( + action, "active", + priv->task_shell_content, "preview-visible", + G_BINDING_SYNC_CREATE); + + action = ACTION (TASK_VIEW_VERTICAL); + + g_settings_bind_with_mapping ( + settings, "task-layout", + ACTION (TASK_VIEW_VERTICAL), "state", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY, + e_shell_view_util_layout_to_state_cb, + e_shell_view_util_state_to_layout_cb, NULL, NULL); + + g_object_unref (settings); + + g_signal_connect_object (action, "notify::state", + G_CALLBACK (task_shell_view_task_view_notify_state_cb), task_shell_view, 0); + + /* to propagate the loaded state */ + task_shell_view_task_view_notify_state_cb (G_OBJECT (action), NULL, task_shell_view); } void diff --git a/src/modules/calendar/e-task-shell-view-private.h b/src/modules/calendar/e-task-shell-view-private.h index 4aa235ee52..9057ec048d 100644 --- a/src/modules/calendar/e-task-shell-view-private.h +++ b/src/modules/calendar/e-task-shell-view-private.h @@ -41,11 +41,9 @@ #include "e-task-shell-content.h" #include "e-task-shell-view-actions.h" -/* Shorthand, requires a variable named "shell_window". */ +/* Shorthand, requires a variable named "shell_view". */ #define ACTION(name) \ - (E_SHELL_WINDOW_ACTION_##name (shell_window)) -#define ACTION_GROUP(name) \ - (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window)) + (E_SHELL_VIEW_ACTION_##name (shell_view)) G_BEGIN_DECLS diff --git a/src/modules/calendar/e-task-shell-view.c b/src/modules/calendar/e-task-shell-view.c index bdf9e6d0fd..9ec78af611 100644 --- a/src/modules/calendar/e-task-shell-view.c +++ b/src/modules/calendar/e-task-shell-view.c @@ -37,17 +37,17 @@ static void task_shell_view_execute_search (EShellView *shell_view) { ETaskShellContent *task_shell_content; - EShellWindow *shell_window; EShellContent *shell_content; EShellSearchbar *searchbar; EActionComboBox *combo_box; - GtkRadioAction *action; + EUIAction *action; ECalComponentPreview *task_preview; EPreviewPane *preview_pane; ETaskTable *task_table; EWebView *web_view; ECalModel *model; ECalDataModel *data_model; + GVariant *state; ICalTimezone *timezone; ICalTime *current_time; time_t start_range; @@ -58,7 +58,6 @@ task_shell_view_execute_search (EShellView *shell_view) gchar *temp; gint value; - shell_window = e_shell_view_get_shell_window (shell_view); shell_content = e_shell_view_get_shell_content (shell_view); task_shell_content = E_TASK_SHELL_CONTENT (shell_content); @@ -73,8 +72,10 @@ task_shell_view_execute_search (EShellView *shell_view) now_time = time_day_begin (i_cal_time_as_timet (current_time)); g_clear_object (¤t_time); - action = GTK_RADIO_ACTION (ACTION (TASK_SEARCH_ANY_FIELD_CONTAINS)); - value = gtk_radio_action_get_current_value (action); + action = ACTION (TASK_SEARCH_ANY_FIELD_CONTAINS); + state = g_action_get_state (G_ACTION (action)); + value = g_variant_get_int32 (state); + g_clear_pointer (&state, g_variant_unref); if (value == TASK_SEARCH_ADVANCED) { query = e_shell_view_get_search_query (shell_view); @@ -272,8 +273,7 @@ task_shell_view_update_actions (EShellView *shell_view) { EShellContent *shell_content; EShellSidebar *shell_sidebar; - EShellWindow *shell_window; - GtkAction *action; + EUIAction *action; const gchar *label; gboolean sensitive; guint32 state; @@ -300,8 +300,6 @@ task_shell_view_update_actions (EShellView *shell_view) /* Chain up to parent's update_actions() method. */ E_SHELL_VIEW_CLASS (e_task_shell_view_parent_class)->update_actions (shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - shell_content = e_shell_view_get_shell_content (shell_view); state = e_shell_content_check_state (shell_content); @@ -346,108 +344,116 @@ task_shell_view_update_actions (EShellView *shell_view) action = ACTION (TASK_LIST_SELECT_ALL); sensitive = clicked_source_is_primary && !all_sources_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_SELECT_ONE); sensitive = clicked_source_is_primary; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_ASSIGN); sensitive = single_task_selected && sources_are_editable && selection_is_assignable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_BULK_EDIT); sensitive = any_tasks_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_DELETE); sensitive = any_tasks_selected && sources_are_editable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); if (multiple_tasks_selected) label = _("Delete Tasks"); else label = _("Delete Task"); - gtk_action_set_label (action, label); + e_ui_action_set_label (action, label); action = ACTION (TASK_FIND); sensitive = single_task_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_FORWARD); sensitive = single_task_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_COPY); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_DELETE); sensitive = primary_source_is_removable || primary_source_is_remote_deletable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_PRINT); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_PRINT_PREVIEW); sensitive = has_primary_source; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_PROPERTIES); sensitive = clicked_source_is_primary && primary_source_is_writable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_REFRESH); sensitive = clicked_source_is_primary && refresh_supported; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_REFRESH_BACKEND); sensitive = clicked_source_is_collection; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_LIST_RENAME); sensitive = clicked_source_is_primary && primary_source_is_writable && !primary_source_in_collection; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_MARK_COMPLETE); sensitive = any_tasks_selected && sources_are_editable && some_tasks_incomplete; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_MARK_INCOMPLETE); sensitive = any_tasks_selected && sources_are_editable && some_tasks_complete; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_OPEN); sensitive = single_task_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_OPEN_URL); sensitive = single_task_selected && selection_has_url; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_PRINT); sensitive = single_task_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_PURGE); sensitive = sources_are_editable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (TASK_SAVE_AS); sensitive = single_task_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); +} + +static void +task_shell_view_init_ui_data (EShellView *shell_view) +{ + g_return_if_fail (E_IS_TASK_SHELL_VIEW (shell_view)); + + e_task_shell_view_actions_init (E_TASK_SHELL_VIEW (shell_view)); } static void @@ -505,10 +511,18 @@ task_shell_view_finalize (GObject *object) static void task_shell_view_constructed (GObject *object) { + EUIManager *ui_manager; + + ui_manager = e_shell_view_get_ui_manager (E_SHELL_VIEW (object)); + + e_ui_manager_freeze (ui_manager); + /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_task_shell_view_parent_class)->constructed (object); e_task_shell_view_private_constructed (E_TASK_SHELL_VIEW (object)); + + e_ui_manager_thaw (ui_manager); } static void @@ -528,14 +542,14 @@ e_task_shell_view_class_init (ETaskShellViewClass *class) shell_view_class = E_SHELL_VIEW_CLASS (class); shell_view_class->label = _("Tasks"); shell_view_class->icon_name = "evolution-tasks"; - shell_view_class->ui_definition = "evolution-tasks.ui"; + shell_view_class->ui_definition = "evolution-tasks.eui"; shell_view_class->ui_manager_id = "org.gnome.evolution.tasks"; - shell_view_class->search_options = "/task-search-options"; shell_view_class->search_rules = "tasktypes.xml"; shell_view_class->new_shell_content = e_task_shell_content_new; shell_view_class->new_shell_sidebar = e_cal_base_shell_sidebar_new; shell_view_class->execute_search = task_shell_view_execute_search; shell_view_class->update_actions = task_shell_view_update_actions; + shell_view_class->init_ui_data = task_shell_view_init_ui_data; cal_base_shell_view_class = E_CAL_BASE_SHELL_VIEW_CLASS (class); cal_base_shell_view_class->source_type = E_CAL_CLIENT_SOURCE_TYPE_TASKS; diff --git a/src/modules/composer-to-meeting/e-composer-to-meeting.c b/src/modules/composer-to-meeting/e-composer-to-meeting.c index ac566a493d..5e9c399a37 100644 --- a/src/modules/composer-to-meeting/e-composer-to-meeting.c +++ b/src/modules/composer-to-meeting/e-composer-to-meeting.c @@ -344,9 +344,11 @@ compose_to_meeting_content_ready_cb (GObject *source_object, } static void -action_composer_to_meeting_cb (GtkAction *action, - EMsgComposer *composer) +action_composer_to_meeting_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; EHTMLEditor *editor; EContentEditor *cnt_editor; EActivity *activity; @@ -373,47 +375,38 @@ action_composer_to_meeting_cb (GtkAction *action, static void e_composer_to_meeting_setup_ui (EMsgComposer *composer) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - GtkActionEntry entries[] = { + static const EUIActionEntry entries[] = { { "composer-to-meeting-action", "stock_people", N_("Convert to M_eeting"), NULL, N_("Convert the message to a meeting request"), - G_CALLBACK (action_composer_to_meeting_cb) } + action_composer_to_meeting_cb, NULL, NULL, NULL } }; EHTMLEditor *editor; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GError *error = NULL; + EUIManager *ui_manager; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); editor = e_msg_composer_get_editor (composer); ui_manager = e_html_editor_get_ui_manager (editor); - action_group = e_html_editor_get_action_group (editor, "composer"); - gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), composer); - - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "composer", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), composer, eui); } static void diff --git a/src/modules/composer-to-meeting/e-meeting-to-composer.c b/src/modules/composer-to-meeting/e-meeting-to-composer.c index c763dc6e96..a7987e37ca 100644 --- a/src/modules/composer-to-meeting/e-meeting-to-composer.c +++ b/src/modules/composer-to-meeting/e-meeting-to-composer.c @@ -335,9 +335,11 @@ meeting_to_composer_composer_created_cb (GObject *source_object, } static void -action_meeting_to_composer_cb (GtkAction *action, - ECompEditor *comp_editor) +action_meeting_to_composer_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + ECompEditor *comp_editor = user_data; ICalComponent *icomp; ICalComponentKind kind; const gchar *prompt_key; @@ -364,43 +366,34 @@ action_meeting_to_composer_cb (GtkAction *action, static void e_meeting_to_composer_setup_ui (ECompEditor *comp_editor) { - const gchar *ui = - "" - " " - " " - " " - " " - " " - " " - " " - ""; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + ""; - GtkActionEntry entries[] = { + static const EUIActionEntry entries[] = { { "meeting-to-composer-action", "mail-message-new", N_("Convert to M_essage"), NULL, N_("Convert to the mail message"), - G_CALLBACK (action_meeting_to_composer_cb) } + action_meeting_to_composer_cb, NULL, NULL, NULL } }; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GError *error = NULL; + EUIManager *ui_manager; g_return_if_fail (E_IS_COMP_EDITOR (comp_editor)); ui_manager = e_comp_editor_get_ui_manager (comp_editor); - action_group = e_comp_editor_get_action_group (comp_editor, "individual"); - gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), comp_editor); - - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - - if (error) { - g_critical ("%s: %s", G_STRFUNC, error->message); - g_error_free (error); - } + e_ui_manager_add_actions_with_eui_data (ui_manager, "individual", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), comp_editor, eui); } static void diff --git a/src/modules/mail/e-mail-attachment-handler.c b/src/modules/mail/e-mail-attachment-handler.c index 75fdbb4a43..0baa967560 100644 --- a/src/modules/mail/e-mail-attachment-handler.c +++ b/src/modules/mail/e-mail-attachment-handler.c @@ -36,29 +36,6 @@ struct _EMailAttachmentHandlerPrivate { G_DEFINE_DYNAMIC_TYPE_EXTENDED (EMailAttachmentHandler, e_mail_attachment_handler, E_TYPE_ATTACHMENT_HANDLER, 0, G_ADD_PRIVATE_DYNAMIC (EMailAttachmentHandler)) -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; - /* Note: Do not use the info field. */ static GtkTargetEntry target_table[] = { { (gchar *) "message/rfc822", 0, 0 }, @@ -249,9 +226,11 @@ mail_attachment_handler_forward_with_style (EAttachmentHandler *handler, } static void -mail_attachment_handler_forward (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_forward (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; GSettings *settings; EMailForwardStyle style; @@ -287,30 +266,41 @@ mail_attachment_handler_reply (EAttachmentHandler *handler, } static void -mail_attachment_handler_reply_all (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_reply_all (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + mail_attachment_handler_reply (handler, E_MAIL_REPLY_TO_ALL); } static void -mail_attachment_handler_reply_list (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_reply_list (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + mail_attachment_handler_reply (handler, E_MAIL_REPLY_TO_LIST); } static void -mail_attachment_handler_reply_sender (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_reply_sender (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + mail_attachment_handler_reply (handler, E_MAIL_REPLY_TO_SENDER); } static void -mail_attachment_handler_message_edit (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_message_edit (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; EMailAttachmentHandler *self = E_MAIL_ATTACHMENT_HANDLER (handler); CamelMimeMessage *message; CamelFolder *folder; @@ -331,29 +321,40 @@ mail_attachment_handler_message_edit (GtkAction *action, } static void -mail_attachment_handler_forward_attached (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_forward_attached (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + mail_attachment_handler_forward_with_style (handler, E_MAIL_FORWARD_STYLE_ATTACHED); } static void -mail_attachment_handler_forward_inline (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_forward_inline (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + mail_attachment_handler_forward_with_style (handler, E_MAIL_FORWARD_STYLE_INLINE); } static void -mail_attachment_handler_forward_quoted (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_forward_quoted (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; + mail_attachment_handler_forward_with_style (handler, E_MAIL_FORWARD_STYLE_QUOTED); } static void -mail_attachment_handler_redirect (GtkAction *action, - EAttachmentHandler *handler) +mail_attachment_handler_redirect (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; EMailAttachmentHandler *self = E_MAIL_ATTACHMENT_HANDLER (handler); CamelMimeMessage *message; CreateComposerData *ccd; @@ -373,9 +374,11 @@ mail_attachment_handler_redirect (GtkAction *action, } static void -action_mail_import_pgp_key_cb (GtkAction *action, - EAttachmentHandler *handler) +action_mail_import_pgp_key_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EAttachmentHandler *handler = user_data; EAttachmentView *view; EAttachment *attachment; EAttachmentStore *store; @@ -441,89 +444,6 @@ action_mail_import_pgp_key_cb (GtkAction *action, g_clear_object (&part); } -static GtkActionEntry standard_entries[] = { - - { "mail-forward", - "mail-forward", - N_("_Forward"), - NULL, - N_("Forward the selected message to someone"), - G_CALLBACK (mail_attachment_handler_forward) }, - - { "mail-reply-all", - "mail-reply-all", - N_("Reply to _All"), - NULL, - N_("Compose a reply to all the recipients of the selected message"), - G_CALLBACK (mail_attachment_handler_reply_all) }, - - { "mail-reply-list", - NULL, - N_("Reply to _List"), - NULL, - N_("Compose a reply to the mailing list of the selected message"), - G_CALLBACK (mail_attachment_handler_reply_list) }, - - { "mail-reply-sender", - "mail-reply-sender", - N_("_Reply to Sender"), - NULL, - N_("Compose a reply to the sender of the selected message"), - G_CALLBACK (mail_attachment_handler_reply_sender) }, - - { "mail-message-edit", - NULL, - N_("_Edit as New Message…"), - NULL, - N_("Open the selected messages in the composer for editing"), - G_CALLBACK (mail_attachment_handler_message_edit) }, - - { "mail-forward-as-menu", - NULL, - N_("F_orward As"), - NULL, - NULL, - NULL }, - - { "mail-forward-attached", - NULL, - N_("_Attached"), - NULL, - N_("Forward the selected message to someone as an attachment"), - G_CALLBACK (mail_attachment_handler_forward_attached) }, - - { "mail-forward-inline", - NULL, - N_("_Inline"), - NULL, - N_("Forward the selected message in the body of a new message"), - G_CALLBACK (mail_attachment_handler_forward_inline) }, - - { "mail-forward-quoted", - NULL, - N_("_Quoted"), - NULL, - N_("Forward the selected message quoted like a reply"), - G_CALLBACK (mail_attachment_handler_forward_quoted) }, - - { "mail-redirect", - NULL, - N_("Re_direct"), - NULL, - N_("Redirect (bounce) the selected message to someone"), - G_CALLBACK (mail_attachment_handler_redirect) } -}; - -static GtkActionEntry custom_entries[] = { - - { "mail-import-pgp-key", - "stock_signature", - N_("Import OpenP_GP key…"), - NULL, - N_("Import Pretty Good Privacy (OpenPGP) key"), - G_CALLBACK (action_mail_import_pgp_key_cb) } -}; - static void call_attachment_load_handle_error (GObject *source_object, GAsyncResult *result, @@ -773,8 +693,8 @@ mail_attachment_handler_update_actions (EAttachmentView *view, { EAttachment *attachment; CamelMimePart *mime_part; - GtkActionGroup *action_group; - GtkAction *action; + EUIActionGroup *action_group; + EUIAction *action; GList *selected; gboolean visible = FALSE, has_list_post = FALSE, can_import_pgp_key = FALSE; @@ -812,16 +732,15 @@ mail_attachment_handler_update_actions (EAttachmentView *view, exit: action_group = e_attachment_view_get_action_group (view, "mail"); - gtk_action_group_set_visible (action_group, visible); + e_ui_action_group_set_visible (action_group, visible); - action = gtk_action_group_get_action (action_group, "mail-reply-list"); - gtk_action_set_visible (action, has_list_post); + action = e_ui_action_group_get_action (action_group, "mail-reply-list"); + e_ui_action_set_visible (action, has_list_post); action = e_attachment_view_get_action (view, "mail-import-pgp-key"); - gtk_action_set_visible (action, can_import_pgp_key); + e_ui_action_set_visible (action, can_import_pgp_key); - g_list_foreach (selected, (GFunc) g_object_unref, NULL); - g_list_free (selected); + g_list_free_full (selected, g_object_unref); } static void @@ -838,16 +757,117 @@ mail_attachment_handler_dispose (GObject *object) static void mail_attachment_handler_constructed (GObject *object) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry mail_entries[] = { + + { "mail-forward", + "mail-forward", + N_("_Forward"), + NULL, + N_("Forward the selected message to someone"), + mail_attachment_handler_forward, NULL, NULL, NULL }, + + { "mail-reply-all", + "mail-reply-all", + N_("Reply to _All"), + NULL, + N_("Compose a reply to all the recipients of the selected message"), + mail_attachment_handler_reply_all, NULL, NULL, NULL }, + + { "mail-reply-list", + NULL, + N_("Reply to _List"), + NULL, + N_("Compose a reply to the mailing list of the selected message"), + mail_attachment_handler_reply_list, NULL, NULL, NULL }, + + { "mail-reply-sender", + "mail-reply-sender", + N_("_Reply to Sender"), + NULL, + N_("Compose a reply to the sender of the selected message"), + mail_attachment_handler_reply_sender, NULL, NULL, NULL }, + + { "mail-message-edit", + NULL, + N_("_Edit as New Message…"), + NULL, + N_("Open the selected messages in the composer for editing"), + mail_attachment_handler_message_edit, NULL, NULL, NULL }, + + { "mail-forward-as-menu", + NULL, + N_("F_orward As"), + NULL, + NULL, + NULL, NULL, NULL, NULL }, + + { "mail-forward-attached", + NULL, + N_("_Attached"), + NULL, + N_("Forward the selected message to someone as an attachment"), + mail_attachment_handler_forward_attached, NULL, NULL, NULL }, + + { "mail-forward-inline", + NULL, + N_("_Inline"), + NULL, + N_("Forward the selected message in the body of a new message"), + mail_attachment_handler_forward_inline, NULL, NULL, NULL }, + + { "mail-forward-quoted", + NULL, + N_("_Quoted"), + NULL, + N_("Forward the selected message quoted like a reply"), + mail_attachment_handler_forward_quoted, NULL, NULL, NULL }, + + { "mail-redirect", + NULL, + N_("Re_direct"), + NULL, + N_("Redirect (bounce) the selected message to someone"), + mail_attachment_handler_redirect, NULL, NULL, NULL } + }; + + static const EUIActionEntry custom_entries[] = { + + { "mail-import-pgp-key", + "stock_signature", + N_("Import OpenP_GP key…"), + NULL, + N_("Import Pretty Good Privacy (OpenPGP) key"), + action_mail_import_pgp_key_cb, NULL, NULL, NULL } + }; + EMailAttachmentHandler *self = E_MAIL_ATTACHMENT_HANDLER (object); EShell *shell; EShellBackend *shell_backend; - EAttachmentHandler *handler; EAttachmentView *view; - GtkActionGroup *action_group; - GtkUIManager *ui_manager; - GError *error = NULL; - - handler = E_ATTACHMENT_HANDLER (object); + EUIManager *ui_manager; /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_attachment_handler_parent_class)->constructed (object); @@ -856,40 +876,29 @@ mail_attachment_handler_constructed (GObject *object) shell_backend = e_shell_get_backend_by_name (shell, "mail"); self->priv->backend = E_MAIL_BACKEND (g_object_ref (shell_backend)); - view = e_attachment_handler_get_view (handler); - - action_group = e_attachment_view_add_action_group (view, "mail"); - gtk_action_group_add_actions ( - action_group, standard_entries, - G_N_ELEMENTS (standard_entries), handler); - - action_group = e_attachment_view_add_action_group (view, "mail-custom"); - gtk_action_group_add_actions ( - action_group, custom_entries, - G_N_ELEMENTS (custom_entries), handler); - + view = e_attachment_handler_get_view (E_ATTACHMENT_HANDLER (self)); ui_manager = e_attachment_view_get_ui_manager (view); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } + e_ui_manager_add_actions (ui_manager, "mail", NULL, + mail_entries, G_N_ELEMENTS (mail_entries), self); + + e_ui_manager_add_actions_with_eui_data (ui_manager, "mail-custom", NULL, + custom_entries, G_N_ELEMENTS (custom_entries), self, eui); g_signal_connect ( view, "update-actions", G_CALLBACK (mail_attachment_handler_update_actions), - handler); + self); g_signal_connect ( view, "drag-data-received", G_CALLBACK (mail_attachment_handler_message_rfc822), - handler); + self); g_signal_connect ( view, "drag-data-received", G_CALLBACK (mail_attachment_handler_x_uid_list), - handler); + self); } static GdkDragAction diff --git a/src/modules/mail/e-mail-shell-backend.c b/src/modules/mail/e-mail-shell-backend.c index f98b945378..1fd9889ecb 100644 --- a/src/modules/mail/e-mail-shell-backend.c +++ b/src/modules/mail/e-mail-shell-backend.c @@ -92,7 +92,7 @@ mbox_create_preview_cb (GObject *preview, mail_backend = E_MAIL_BACKEND (e_shell_get_backend_by_name (e_shell_get_default (), BACKEND_NAME)); g_return_if_fail (mail_backend != NULL); - display = E_MAIL_DISPLAY (e_mail_display_new (e_mail_backend_get_remote_content (mail_backend))); + display = E_MAIL_DISPLAY (e_mail_display_new (e_mail_backend_get_remote_content (mail_backend), NULL)); g_object_set_data_full ( preview, "mbox-imp-display", g_object_ref (display), g_object_unref); @@ -213,11 +213,10 @@ static void mail_shell_backend_mail_icon_cb (EShellWindow *shell_window, const gchar *icon_name) { - GtkAction *action; + EUIAction *action; - action = e_shell_window_get_shell_view_action ( - shell_window, BACKEND_NAME); - gtk_action_set_icon_name (action, icon_name); + action = e_shell_window_get_shell_view_action (shell_window, BACKEND_NAME); + e_ui_action_set_icon_name (action, icon_name); } static void @@ -243,9 +242,11 @@ mail_shell_backend_folder_created_cb (EMailFolderCreateDialog *dialog, } static void -action_mail_folder_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_mail_folder_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EMFolderTree *folder_tree = NULL; EMailShellSidebar *mail_shell_sidebar; EMailSession *session; @@ -297,9 +298,11 @@ exit: } static void -action_mail_account_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_mail_account_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; EShellBackend *shell_backend; @@ -348,9 +351,11 @@ action_mail_message_new_composer_created_cb (GObject *source_object, } static void -action_mail_message_new_cb (GtkAction *action, - EShellWindow *shell_window) +action_mail_message_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShellView *shell_view; EShell *shell; ESourceRegistry *registry; @@ -381,7 +386,8 @@ action_mail_message_new_cb (GtkAction *action, shell_view = e_shell_window_get_shell_view (shell_window, view_name); - message_list = e_mail_reader_get_message_list (E_MAIL_READER (e_shell_view_get_shell_content (shell_view))); + message_list = e_mail_reader_get_message_list (E_MAIL_READER ( + e_mail_shell_content_get_mail_view (E_MAIL_SHELL_CONTENT (e_shell_view_get_shell_content (shell_view))))); if (message_list) { MessageList *ml = MESSAGE_LIST (message_list); GPtrArray *selected_uids; @@ -407,33 +413,6 @@ action_mail_message_new_cb (GtkAction *action, e_msg_composer_new (shell, action_mail_message_new_composer_created_cb, ncd); } -static GtkActionEntry item_entries[] = { - - { "mail-message-new", - "mail-message-new", - NC_("New", "_Mail Message"), - "m", - N_("Compose a new mail message"), - G_CALLBACK (action_mail_message_new_cb) } -}; - -static GtkActionEntry source_entries[] = { - - { "mail-account-new", - "evolution-mail", - NC_("New", "Mail Acco_unt"), - NULL, - N_("Create a new mail account"), - G_CALLBACK (action_mail_account_new_cb) }, - - { "mail-folder-new", - "folder-new", - NC_("New", "Mail _Folder"), - NULL, - N_("Create a new mail folder"), - G_CALLBACK (action_mail_folder_new_cb) } -}; - static void mail_shell_backend_sync_store_done_cb (CamelStore *store, gpointer user_data) @@ -618,9 +597,8 @@ mail_shell_backend_search_mid (EMailShellBackend *mail_shell_backend, if (shell_view) { EShellSearchbar *shell_searchbar; - EShellWindow *shell_window = E_SHELL_WINDOW (window); GString *expr; - GtkAction *action; + EUIAction *action; gint ii; shell_searchbar = e_mail_shell_content_get_searchbar (E_MAIL_SHELL_CONTENT (e_shell_view_get_shell_content (shell_view))); @@ -639,13 +617,13 @@ mail_shell_backend_search_mid (EMailShellBackend *mail_shell_backend, e_shell_view_block_execute_search (shell_view); action = ACTION (MAIL_FILTER_ALL_MESSAGES); - gtk_action_activate (action); + g_action_activate (G_ACTION (action), NULL); action = ACTION (MAIL_SEARCH_FREE_FORM_EXPR); - gtk_action_activate (action); + g_action_activate (G_ACTION (action), NULL); action = ACTION (MAIL_SCOPE_ALL_ACCOUNTS); - gtk_action_activate (action); + g_action_activate (G_ACTION (action), NULL); e_shell_view_set_search_rule (shell_view, NULL); e_shell_searchbar_set_search_text (shell_searchbar, expr->str); @@ -763,6 +741,31 @@ mail_shell_backend_window_added_cb (GtkApplication *application, GtkWindow *window, EShellBackend *shell_backend) { + static const EUIActionEntry item_entries[] = { + { "new-menu-mail-message-new", + "mail-message-new", + NC_("New", "_Mail Message"), + "m", + N_("Compose a new mail message"), + action_mail_message_new_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry source_entries[] = { + { "new-menu-mail-account-new", + "evolution-mail", + NC_("New", "Mail Acco_unt"), + NULL, + N_("Create a new mail account"), + action_mail_account_new_cb, NULL, NULL, NULL }, + + { "new-menu-mail-folder-new", + "folder-new", + NC_("New", "Mail _Folder"), + NULL, + N_("Create a new mail folder"), + action_mail_folder_new_cb, NULL, NULL, NULL } + }; + EShell *shell = E_SHELL (application); EMailBackend *backend; EMailSession *session; diff --git a/src/modules/mail/e-mail-shell-content.c b/src/modules/mail/e-mail-shell-content.c index 3746e4c109..a7d137ca0c 100644 --- a/src/modules/mail/e-mail-shell-content.c +++ b/src/modules/mail/e-mail-shell-content.c @@ -44,22 +44,12 @@ struct _EMailShellContentPrivate { enum { PROP_0, - PROP_FORWARD_STYLE, - PROP_GROUP_BY_THREADS, PROP_MAIL_VIEW, - PROP_REPLY_STYLE, - PROP_MARK_SEEN_ALWAYS, - PROP_TO_DO_PANE, - PROP_DELETE_SELECTS_PREVIOUS + PROP_TO_DO_PANE }; -/* Forward Declarations */ -static void e_mail_shell_content_reader_init - (EMailReaderInterface *iface); - G_DEFINE_DYNAMIC_TYPE_EXTENDED (EMailShellContent, e_mail_shell_content, E_TYPE_SHELL_CONTENT, 0, - G_ADD_PRIVATE_DYNAMIC (EMailShellContent) - G_IMPLEMENT_INTERFACE_DYNAMIC (E_TYPE_MAIL_READER, e_mail_shell_content_reader_init)) + G_ADD_PRIVATE_DYNAMIC (EMailShellContent)) static gboolean mail_shell_content_transform_num_attachments_to_visible_boolean_with_settings (GBinding *binding, @@ -82,20 +72,6 @@ mail_shell_content_transform_num_attachments_to_visible_boolean_with_settings (G return res; } -static void -reconnect_changed_event (EMailReader *child, - EMailReader *parent) -{ - g_signal_emit_by_name (parent, "changed"); -} - -static void -reconnect_folder_loaded_event (EMailReader *child, - EMailReader *parent) -{ - g_signal_emit_by_name (parent, "folder-loaded"); -} - /* To recognize old values from new values */ #define PROPORTION_LOWER_LIMIT 1000000 @@ -129,47 +105,6 @@ mail_shell_content_map_proportion_to_setting_cb (const GValue *value, return g_variant_new_int32 (PROPORTION_LOWER_LIMIT + (gint32) (proportion * PROPORTION_LOWER_LIMIT)); } -static void -mail_shell_content_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_FORWARD_STYLE: - e_mail_reader_set_forward_style ( - E_MAIL_READER (object), - g_value_get_enum (value)); - return; - - case PROP_GROUP_BY_THREADS: - e_mail_reader_set_group_by_threads ( - E_MAIL_READER (object), - g_value_get_boolean (value)); - return; - - case PROP_REPLY_STYLE: - e_mail_reader_set_reply_style ( - E_MAIL_READER (object), - g_value_get_enum (value)); - return; - - case PROP_MARK_SEEN_ALWAYS: - e_mail_reader_set_mark_seen_always ( - E_MAIL_READER (object), - g_value_get_boolean (value)); - return; - - case PROP_DELETE_SELECTS_PREVIOUS: - e_mail_reader_set_delete_selects_previous ( - E_MAIL_READER (object), - g_value_get_boolean (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - static void mail_shell_content_get_property (GObject *object, guint property_id, @@ -177,47 +112,17 @@ mail_shell_content_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_FORWARD_STYLE: - g_value_set_enum ( - value, e_mail_reader_get_forward_style ( - E_MAIL_READER (object))); - return; - - case PROP_GROUP_BY_THREADS: - g_value_set_boolean ( - value, e_mail_reader_get_group_by_threads ( - E_MAIL_READER (object))); - return; - case PROP_MAIL_VIEW: g_value_set_object ( value, e_mail_shell_content_get_mail_view ( E_MAIL_SHELL_CONTENT (object))); return; - case PROP_REPLY_STYLE: - g_value_set_enum ( - value, e_mail_reader_get_reply_style ( - E_MAIL_READER (object))); - return; - - case PROP_MARK_SEEN_ALWAYS: - g_value_set_boolean ( - value, e_mail_reader_get_mark_seen_always ( - E_MAIL_READER (object))); - return; - case PROP_TO_DO_PANE: g_value_set_object ( value, e_mail_shell_content_get_to_do_pane ( E_MAIL_SHELL_CONTENT (object))); return; - - case PROP_DELETE_SELECTS_PREVIOUS: - g_value_set_boolean ( - value, e_mail_reader_get_delete_selects_previous ( - E_MAIL_READER (object))); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -230,10 +135,6 @@ mail_shell_content_dispose (GObject *object) g_clear_object (&self->priv->mail_view); - /* Intentionally after freeing the mail_view, because - the widgets it contains/references can be freed already */ - e_mail_reader_dispose (E_MAIL_READER (object)); - /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_mail_shell_content_parent_class)->dispose (object); } @@ -278,14 +179,7 @@ mail_shell_content_constructed (GObject *object) self->priv->mail_view = E_MAIL_VIEW (g_object_ref (widget)); gtk_widget_show (widget); - g_signal_connect ( - widget, "changed", - G_CALLBACK (reconnect_changed_event), object); - g_signal_connect ( - widget, "folder-loaded", - G_CALLBACK (reconnect_folder_loaded_event), object); - - display = e_mail_reader_get_mail_display (E_MAIL_READER (object)); + display = e_mail_reader_get_mail_display (E_MAIL_READER (self->priv->mail_view)); attachment_store = e_mail_display_get_attachment_store (display); widget = GTK_WIDGET (e_mail_display_get_attachment_view (display)); @@ -386,242 +280,6 @@ mail_shell_content_focus_search_results (EShellContent *shell_content) gtk_widget_grab_focus (message_list); } -static guint -mail_shell_content_open_selected_mail (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return 0; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - return e_mail_reader_open_selected_mail (reader); -} - -static GtkActionGroup * -mail_shell_content_get_action_group (EMailReader *reader, - EMailReaderActionGroup group) -{ - EShellView *shell_view; - EShellWindow *shell_window; - EShellContent *shell_content; - const gchar *group_name; - - shell_content = E_SHELL_CONTENT (reader); - shell_view = e_shell_content_get_shell_view (shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - - switch (group) { - case E_MAIL_READER_ACTION_GROUP_STANDARD: - group_name = "mail"; - break; - case E_MAIL_READER_ACTION_GROUP_SEARCH_FOLDERS: - group_name = "search-folders"; - break; - case E_MAIL_READER_ACTION_GROUP_LABELS: - group_name = "mail-labels"; - break; - default: - g_return_val_if_reached (NULL); - } - - return e_shell_window_get_action_group (shell_window, group_name); -} - -static EMailBackend * -mail_shell_content_get_backend (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return NULL; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - return e_mail_reader_get_backend (reader); -} - -static EMailDisplay * -mail_shell_content_get_mail_display (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return NULL; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - return e_mail_reader_get_mail_display (reader); -} - -static gboolean -mail_shell_content_get_hide_deleted (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return FALSE; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - return e_mail_reader_get_hide_deleted (reader); -} - -static GtkWidget * -mail_shell_content_get_message_list (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return NULL; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - return e_mail_reader_get_message_list (reader); -} - -static GtkMenu * -mail_shell_content_get_popup_menu (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return NULL; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - return e_mail_reader_get_popup_menu (reader); -} - -static EPreviewPane * -mail_shell_content_get_preview_pane (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return NULL; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - return e_mail_reader_get_preview_pane (reader); -} - -static GtkWindow * -mail_shell_content_get_window (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return NULL; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - return e_mail_reader_get_window (reader); -} - -static void -mail_shell_content_set_folder (EMailReader *reader, - CamelFolder *folder) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - e_mail_reader_set_folder (reader, folder); -} - -static void -mail_shell_content_update_actions (EMailReader *reader, - guint32 state) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - e_mail_reader_update_actions (reader, state); -} - -static void -mail_shell_content_reload (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - e_mail_reader_reload (reader); -} - -static void -mail_shell_content_remove_ui (EMailReader *reader) -{ - EMailShellContent *mail_shell_content; - - mail_shell_content = E_MAIL_SHELL_CONTENT (reader); - - if (!mail_shell_content->priv->mail_view) - return; - - /* Forward this to our internal EMailView, which - * also implements the EMailReader interface. */ - reader = E_MAIL_READER (mail_shell_content->priv->mail_view); - - e_mail_reader_remove_ui (reader); -} - static void e_mail_shell_content_class_init (EMailShellContentClass *class) { @@ -629,27 +287,13 @@ e_mail_shell_content_class_init (EMailShellContentClass *class) EShellContentClass *shell_content_class; object_class = G_OBJECT_CLASS (class); - object_class->set_property = mail_shell_content_set_property; object_class->get_property = mail_shell_content_get_property; object_class->dispose = mail_shell_content_dispose; object_class->constructed = mail_shell_content_constructed; shell_content_class = E_SHELL_CONTENT_CLASS (class); shell_content_class->check_state = mail_shell_content_check_state; - shell_content_class->focus_search_results = - mail_shell_content_focus_search_results; - - /* Inherited from EMailReader */ - g_object_class_override_property ( - object_class, - PROP_FORWARD_STYLE, - "forward-style"); - - /* Inherited from EMailReader */ - g_object_class_override_property ( - object_class, - PROP_GROUP_BY_THREADS, - "group-by-threads"); + shell_content_class->focus_search_results = mail_shell_content_focus_search_results; g_object_class_install_property ( object_class, @@ -661,24 +305,6 @@ e_mail_shell_content_class_init (EMailShellContentClass *class) E_TYPE_MAIL_VIEW, G_PARAM_READABLE)); - /* Inherited from EMailReader */ - g_object_class_override_property ( - object_class, - PROP_REPLY_STYLE, - "reply-style"); - - /* Inherited from EMailReader */ - g_object_class_override_property ( - object_class, - PROP_MARK_SEEN_ALWAYS, - "mark-seen-always"); - - /* Inherited from EMailReader */ - g_object_class_override_property ( - object_class, - PROP_DELETE_SELECTS_PREVIOUS, - "delete-selects-previous"); - g_object_class_install_property ( object_class, PROP_TO_DO_PANE, @@ -695,24 +321,6 @@ e_mail_shell_content_class_finalize (EMailShellContentClass *class) { } -static void -e_mail_shell_content_reader_init (EMailReaderInterface *iface) -{ - iface->get_action_group = mail_shell_content_get_action_group; - iface->get_backend = mail_shell_content_get_backend; - iface->get_mail_display = mail_shell_content_get_mail_display; - iface->get_hide_deleted = mail_shell_content_get_hide_deleted; - iface->get_message_list = mail_shell_content_get_message_list; - iface->get_popup_menu = mail_shell_content_get_popup_menu; - iface->get_preview_pane = mail_shell_content_get_preview_pane; - iface->get_window = mail_shell_content_get_window; - iface->set_folder = mail_shell_content_set_folder; - iface->open_selected_mail = mail_shell_content_open_selected_mail; - iface->update_actions = mail_shell_content_update_actions; - iface->reload = mail_shell_content_reload; - iface->remove_ui = mail_shell_content_remove_ui; -} - static void e_mail_shell_content_init (EMailShellContent *mail_shell_content) { diff --git a/src/modules/mail/e-mail-shell-view-actions.c b/src/modules/mail/e-mail-shell-view-actions.c index 8f85c837ac..2b89cb0c20 100644 --- a/src/modules/mail/e-mail-shell-view-actions.c +++ b/src/modules/mail/e-mail-shell-view-actions.c @@ -21,9 +21,10 @@ #include "evolution-config.h" #include "mail/e-mail-folder-sort-order-dialog.h" - #include "e-mail-shell-view-private.h" +#include "e-mail-shell-view-actions.h" + static void mail_shell_view_folder_created_cb (EMailFolderCreateDialog *dialog, CamelStore *store, @@ -47,9 +48,11 @@ mail_shell_view_folder_created_cb (EMailFolderCreateDialog *dialog, } static void -action_mail_account_disable_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_account_disable_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellSidebar *mail_shell_sidebar; EShellView *shell_view; EShellWindow *shell_window; @@ -86,9 +89,11 @@ action_mail_account_disable_cb (GtkAction *action, } static void -action_mail_account_properties_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_account_properties_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellSidebar *mail_shell_sidebar; EShell *shell; EShellView *shell_view; @@ -157,9 +162,11 @@ account_refresh_folder_info_received_cb (GObject *source, } static void -action_mail_account_refresh_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_account_refresh_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; EMFolderTree *folder_tree; @@ -200,9 +207,11 @@ action_mail_account_refresh_cb (GtkAction *action, } static void -action_mail_create_search_folder_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_create_search_folder_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailReader *reader; EShellView *shell_view; @@ -256,17 +265,21 @@ action_mail_create_search_folder_cb (GtkAction *action, } static void -action_mail_attachment_bar_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_attachment_bar_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailDisplay *mail_display; EAttachmentView *attachment_view; g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view)); - mail_display = e_mail_reader_get_mail_display (E_MAIL_READER (mail_shell_view->priv->mail_shell_content)); + e_ui_action_set_state (action, parameter); + + mail_display = e_mail_reader_get_mail_display (E_MAIL_READER (e_mail_shell_content_get_mail_view (mail_shell_view->priv->mail_shell_content))); attachment_view = e_mail_display_get_attachment_view (mail_display); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) { + if (e_ui_action_get_active (action)) { EAttachmentBar *bar; EAttachmentStore *store; guint num_attachments; @@ -281,34 +294,22 @@ action_mail_attachment_bar_cb (GtkAction *action, } static void -action_mail_show_preview_toolbar_cb (GtkAction *action, - EShellView *shell_view) -{ - EShellWindow *shell_window; - GtkWidget *toolbar; - - g_return_if_fail (E_IS_MAIL_SHELL_VIEW (shell_view)); - - shell_window = e_shell_view_get_shell_window (shell_view); - toolbar = e_shell_window_get_managed_widget (shell_window, "/mail-preview-toolbar"); - - if (toolbar) - gtk_widget_set_visible (toolbar, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); -} - -static void -action_mail_to_do_bar_cb (GtkAction *action, - EShellView *shell_view) +action_mail_to_do_bar_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; EShellContent *shell_content; GtkWidget *to_do_pane; g_return_if_fail (E_IS_MAIL_SHELL_VIEW (shell_view)); + e_ui_action_set_state (action, parameter); + shell_content = e_shell_view_get_shell_content (shell_view); to_do_pane = e_mail_shell_content_get_to_do_pane (E_MAIL_SHELL_CONTENT (shell_content)); - gtk_widget_set_visible (to_do_pane, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))); + gtk_widget_set_visible (to_do_pane, e_ui_action_get_active (action)); } static void @@ -338,9 +339,11 @@ action_mail_download_finished_cb (CamelStore *store, } static void -action_mail_download_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_download_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailView *mail_view; EMailReader *reader; @@ -391,9 +394,11 @@ action_mail_download_cb (GtkAction *action, } static void -action_mail_flush_outbox_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_flush_outbox_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellBackend *shell_backend; EShellView *shell_view; EMailBackend *backend; @@ -409,9 +414,11 @@ action_mail_flush_outbox_cb (GtkAction *action, } static void -action_mail_folder_copy_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_copy_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellSidebar *mail_shell_sidebar; EShellContent *shell_content; EShellWindow *shell_window; @@ -440,9 +447,11 @@ action_mail_folder_copy_cb (GtkAction *action, } static void -action_mail_folder_delete_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_delete_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; EMailView *mail_view; @@ -470,9 +479,11 @@ action_mail_folder_delete_cb (GtkAction *action, } static void -action_mail_folder_edit_sort_order_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_edit_sort_order_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailView *mail_view; EMFolderTree *folder_tree; CamelStore *store; @@ -500,9 +511,11 @@ action_mail_folder_edit_sort_order_cb (GtkAction *action, } static void -action_mail_folder_expunge_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_expunge_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; EMailView *mail_view; @@ -538,9 +551,11 @@ action_mail_folder_expunge_cb (GtkAction *action, } static void -action_mail_folder_empty_junk_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_empty_junk_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; EMailView *mail_view; @@ -886,9 +901,11 @@ e_mail_shell_view_actions_mark_all_read (EMailShellView *mail_shell_view, } static void -action_mail_folder_mark_all_as_read_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_mark_all_as_read_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailReader *reader; EMailView *mail_view; @@ -918,9 +935,11 @@ action_mail_folder_mark_all_as_read_cb (GtkAction *action, } static void -action_mail_popup_folder_mark_all_as_read_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_popup_folder_mark_all_as_read_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellSidebar *mail_shell_sidebar; EMFolderTree *folder_tree; CamelStore *store = NULL; @@ -941,9 +960,11 @@ action_mail_popup_folder_mark_all_as_read_cb (GtkAction *action, } static void -action_mail_folder_move_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_move_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellSidebar *mail_shell_sidebar; EShellContent *shell_content; EShellWindow *shell_window; @@ -972,9 +993,11 @@ action_mail_folder_move_cb (GtkAction *action, } static void -action_mail_folder_new_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; EMailSession *session; @@ -1013,9 +1036,11 @@ action_mail_folder_new_cb (GtkAction *action, } static void -action_mail_folder_properties_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_properties_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellSidebar *mail_shell_sidebar; EShellView *shell_view; EShellWindow *shell_window; @@ -1044,9 +1069,11 @@ action_mail_folder_properties_cb (GtkAction *action, } static void -action_mail_folder_refresh_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_refresh_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; EMailView *mail_view; @@ -1074,16 +1101,21 @@ action_mail_folder_refresh_cb (GtkAction *action, } static void -action_mail_folder_rename_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_rename_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; + e_mail_shell_view_rename_folder (mail_shell_view); } static void -action_mail_folder_select_thread_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_select_thread_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; GtkWidget *message_list; EMailReader *reader; @@ -1099,9 +1131,11 @@ action_mail_folder_select_thread_cb (GtkAction *action, } static void -action_mail_folder_select_subthread_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_select_subthread_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; GtkWidget *message_list; EMailReader *reader; @@ -1194,9 +1228,11 @@ mail_folder_unsubscribe_got_folder_cb (GObject *source_object, } static void -action_mail_folder_unsubscribe_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_folder_unsubscribe_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; EMailView *mail_view; @@ -1227,9 +1263,11 @@ action_mail_folder_unsubscribe_cb (GtkAction *action, } static void -action_mail_global_expunge_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_global_expunge_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellBackend *shell_backend; EShellWindow *shell_window; EShellView *shell_view; @@ -1248,9 +1286,11 @@ action_mail_global_expunge_cb (GtkAction *action, } static void -action_mail_goto_folder_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_goto_folder_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; CamelFolder *folder; EMailReader *reader; EMailView *mail_view; @@ -1305,9 +1345,11 @@ action_mail_goto_folder_cb (GtkAction *action, } static void -action_mail_send_receive_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_send_receive_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; EShellBackend *shell_backend; @@ -1325,9 +1367,11 @@ action_mail_send_receive_cb (GtkAction *action, } static void -action_mail_send_receive_receive_all_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_send_receive_receive_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; EShellBackend *shell_backend; @@ -1345,9 +1389,11 @@ action_mail_send_receive_receive_all_cb (GtkAction *action, } static void -action_mail_send_receive_send_all_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_send_receive_send_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellView *shell_view; EShellBackend *shell_backend; EMailBackend *backend; @@ -1419,23 +1465,31 @@ mail_shell_view_magic_spacebar (EMailShellView *mail_shell_view, } static void -action_mail_smart_backward_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_smart_backward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; + mail_shell_view_magic_spacebar (mail_shell_view, FALSE); } static void -action_mail_smart_forward_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_smart_forward_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; + mail_shell_view_magic_spacebar (mail_shell_view, TRUE); } static void -action_mail_stop_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_stop_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellView *shell_view; EShellBackend *shell_backend; @@ -1446,9 +1500,11 @@ action_mail_stop_cb (GtkAction *action, } static void -action_mail_threads_collapse_all_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_threads_collapse_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; GtkWidget *message_list; EMailReader *reader; @@ -1464,9 +1520,11 @@ action_mail_threads_collapse_all_cb (GtkAction *action, } static void -action_mail_threads_expand_all_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_threads_expand_all_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellContent *mail_shell_content; GtkWidget *message_list; EMailReader *reader; @@ -1482,9 +1540,11 @@ action_mail_threads_expand_all_cb (GtkAction *action, } static void -action_mail_tools_filters_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_tools_filters_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellBackend *shell_backend; EShellContent *shell_content; EShellWindow *shell_window; @@ -1507,9 +1567,11 @@ action_mail_tools_filters_cb (GtkAction *action, } static void -action_mail_tools_search_folders_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_tools_search_folders_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EShellView *shell_view; EShellWindow *shell_window; EShellBackend *shell_backend; @@ -1524,9 +1586,11 @@ action_mail_tools_search_folders_cb (GtkAction *action, } static void -action_mail_tools_subscriptions_cb (GtkAction *action, - EMailShellView *mail_shell_view) +action_mail_tools_subscriptions_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailShellView *mail_shell_view = user_data; EMailShellSidebar *mail_shell_sidebar; EShellWindow *shell_window; EShellView *shell_view; @@ -1555,655 +1619,461 @@ action_mail_tools_subscriptions_cb (GtkAction *action, gtk_widget_destroy (dialog); } -static void -action_mail_view_cb (GtkRadioAction *action, - GtkRadioAction *current, - EMailShellView *mail_shell_view) -{ - EMailShellContent *mail_shell_content; - GtkOrientation orientation; - EMailView *mail_view; - - mail_shell_content = mail_shell_view->priv->mail_shell_content; - mail_view = e_mail_shell_content_get_mail_view (mail_shell_content); - - switch (gtk_radio_action_get_current_value (action)) { - case 0: - orientation = GTK_ORIENTATION_VERTICAL; - break; - case 1: - orientation = GTK_ORIENTATION_HORIZONTAL; - break; - default: - g_return_if_reached (); - } - - e_mail_view_set_orientation (mail_view, orientation); -} - -static GtkActionEntry mail_entries[] = { - - { "mail-account-disable", - NULL, - N_("_Disable Account"), - NULL, - N_("Disable this account"), - G_CALLBACK (action_mail_account_disable_cb) }, - - { "mail-account-expunge", - NULL, - N_("_Empty Trash"), - NULL, - N_("Permanently remove all the deleted messages from all folders"), - G_CALLBACK (action_mail_folder_expunge_cb) }, - - { "mail-account-empty-junk", - NULL, - N_("Empty _Junk"), - NULL, - N_("Delete all Junk messages from all folders"), - G_CALLBACK (action_mail_folder_empty_junk_cb) }, - - { "mail-account-properties", - "document-properties", - N_("_Properties"), - NULL, - N_("Edit properties of this account"), - G_CALLBACK (action_mail_account_properties_cb) }, - - { "mail-account-refresh", - "view-refresh", - N_("_Refresh"), - NULL, - N_("Refresh list of folders of this account"), - G_CALLBACK (action_mail_account_refresh_cb) }, - - { "mail-download", - NULL, - N_("_Download Messages for Offline Usage"), - NULL, - N_("Download messages of accounts and folders marked for offline usage"), - G_CALLBACK (action_mail_download_cb) }, - - { "mail-flush-outbox", - "mail-send", - N_("Fl_ush Outbox"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mail_flush_outbox_cb) }, - - { "mail-folder-copy", - "folder-copy", - N_("_Copy Folder To…"), - NULL, - N_("Copy the selected folder into another folder"), - G_CALLBACK (action_mail_folder_copy_cb) }, - - { "mail-folder-delete", - "edit-delete", - N_("_Delete"), - NULL, - N_("Permanently remove this folder"), - G_CALLBACK (action_mail_folder_delete_cb) }, - - { "mail-folder-edit-sort-order", - NULL, - N_("Edit Sort _Order…"), - NULL, - N_("Change sort order of the folders in the folder tree"), - G_CALLBACK (action_mail_folder_edit_sort_order_cb) }, - - { "mail-folder-expunge", - NULL, - N_("E_xpunge"), - "e", - N_("Permanently remove all deleted messages from this folder"), - G_CALLBACK (action_mail_folder_expunge_cb) }, - - { "mail-folder-mark-all-as-read", - "mail-mark-read", - N_("Mar_k All Messages as Read"), - "slash", - N_("Mark all messages in the folder as read"), - G_CALLBACK (action_mail_folder_mark_all_as_read_cb) }, - - { "mail-folder-move", - "folder-move", - N_("_Move Folder To…"), - NULL, - N_("Move the selected folder into another folder"), - G_CALLBACK (action_mail_folder_move_cb) }, - - { "mail-folder-new", - "folder-new", - /* Translators: An action caption to create a new mail folder */ - N_("_New…"), - NULL, - N_("Create a new folder for storing mail"), - G_CALLBACK (action_mail_folder_new_cb) }, - - { "mail-folder-properties", - "document-properties", - N_("_Properties"), - NULL, - N_("Change the properties of this folder"), - G_CALLBACK (action_mail_folder_properties_cb) }, - - { "mail-folder-refresh", - "view-refresh", - N_("_Refresh"), - "F5", - N_("Refresh the folder"), - G_CALLBACK (action_mail_folder_refresh_cb) }, - - { "mail-folder-rename", - NULL, - N_("_Rename…"), - "F2", - N_("Change the name of this folder"), - G_CALLBACK (action_mail_folder_rename_cb) }, - - { "mail-folder-select-thread", - NULL, - N_("Select Message _Thread"), - "h", - N_("Select all messages in the same thread as the selected message"), - G_CALLBACK (action_mail_folder_select_thread_cb) }, - - { "mail-folder-select-subthread", - NULL, - N_("Select Message S_ubthread"), - "h", - N_("Select all replies to the currently selected message"), - G_CALLBACK (action_mail_folder_select_subthread_cb) }, - - { "mail-folder-unsubscribe", - NULL, - N_("_Unsubscribe"), - NULL, - N_("Unsubscribe from the selected folder"), - G_CALLBACK (action_mail_folder_unsubscribe_cb) }, - - { "mail-global-expunge", - NULL, - N_("Empty _Trash"), - NULL, - N_("Permanently remove all the deleted messages from all accounts"), - G_CALLBACK (action_mail_global_expunge_cb) }, - - { "mail-goto-folder", - NULL, - N_("Go to _Folder"), - "g", - N_("Opens a dialog to select a folder to go to"), - G_CALLBACK (action_mail_goto_folder_cb) }, - - /* This is the same as "mail-tools-subscriptions" but only - * appears in the sidebar context menu when right-clicking - * on a store that supports folder subscriptions. No need - * for a special callback because Folder->Subscriptions... - * already tries to open the "Folder Subscriptions" dialog - * according to the highlighted item in the sidebar, which - * is exactly the behavior we want here. */ - { "mail-manage-subscriptions", - NULL, - N_("_Manage Subscriptions"), - NULL, - N_("Subscribe or unsubscribe to folders on remote servers"), - G_CALLBACK (action_mail_tools_subscriptions_cb) }, - - { "mail-popup-folder-mark-all-as-read", - "mail-mark-read", - N_("Mar_k All Messages as Read"), - NULL, - N_("Mark all messages in the folder as read"), - G_CALLBACK (action_mail_popup_folder_mark_all_as_read_cb) }, - - { "mail-send-receive", - "mail-send-receive", - N_("Send / _Receive"), - "F12", - N_("Send queued items and retrieve new items"), - G_CALLBACK (action_mail_send_receive_cb) }, - - { "mail-send-receive-receive-all", - NULL, - N_("R_eceive All"), - NULL, - N_("Receive new items from all accounts"), - G_CALLBACK (action_mail_send_receive_receive_all_cb) }, - - { "mail-send-receive-send-all", - "mail-send", - N_("_Send All"), - NULL, - N_("Send queued items in all accounts"), - G_CALLBACK (action_mail_send_receive_send_all_cb) }, - - { "mail-send-receive-submenu", - "mail-send-receive", - N_("Send / _Receive"), - NULL, - NULL, - NULL }, - - { "mail-smart-backward", - "go-up", /* In case a user adds it to the UI */ - NULL, /* No menu item; key press only */ - "BackSpace", - NULL, - G_CALLBACK (action_mail_smart_backward_cb) }, - - { "mail-smart-forward", - "go-down", /* In case a user adds it to the UI */ - NULL, /* No menu item; key press only */ - "space", - NULL, - G_CALLBACK (action_mail_smart_forward_cb) }, - - { "mail-stop", - "process-stop", - N_("Cancel"), - NULL, - N_("Cancel the current mail operation"), - G_CALLBACK (action_mail_stop_cb) }, - - { "mail-threads-collapse-all", - NULL, - N_("Collapse All _Threads"), - "b", - N_("Collapse all message threads"), - G_CALLBACK (action_mail_threads_collapse_all_cb) }, - - { "mail-threads-expand-all", - NULL, - N_("E_xpand All Threads"), - NULL, - N_("Expand all message threads"), - G_CALLBACK (action_mail_threads_expand_all_cb) }, - - { "mail-tools-filters", - NULL, - N_("_Message Filters"), - NULL, - N_("Create or edit rules for filtering new mail"), - G_CALLBACK (action_mail_tools_filters_cb) }, - - { "mail-tools-subscriptions", - NULL, - N_("_Subscriptions…"), - NULL, - N_("Subscribe or unsubscribe to folders on remote servers"), - G_CALLBACK (action_mail_tools_subscriptions_cb) }, - - /*** Menus ***/ - - { "mail-folder-menu", - NULL, - N_("F_older"), - NULL, - NULL, - NULL }, - - { "mail-preview-menu", - NULL, - N_("_Preview"), - NULL, - NULL, - NULL } -}; - -static GtkActionEntry search_folder_entries[] = { - - { "mail-create-search-folder", - NULL, - N_("C_reate Search Folder From Search…"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mail_create_search_folder_cb) }, - - { "mail-tools-search-folders", - NULL, - N_("Search F_olders"), - NULL, - N_("Create or edit search folder definitions"), - G_CALLBACK (action_mail_tools_search_folders_cb) }, -}; - -static EPopupActionEntry mail_popup_entries[] = { - - { "mail-popup-account-disable", - NULL, - "mail-account-disable" }, - - { "mail-popup-account-expunge", - NULL, - "mail-account-expunge" }, - - { "mail-popup-account-empty-junk", - NULL, - "mail-account-empty-junk" }, - - { "mail-popup-account-refresh", - NULL, - "mail-account-refresh" }, - - { "mail-popup-account-properties", - NULL, - "mail-account-properties" }, - - { "mail-popup-flush-outbox", - NULL, - "mail-flush-outbox" }, - - { "mail-popup-folder-copy", - NULL, - "mail-folder-copy" }, - - { "mail-popup-folder-delete", - NULL, - "mail-folder-delete" }, - - { "mail-popup-folder-move", - NULL, - "mail-folder-move" }, - - { "mail-popup-folder-new", - N_("_New Folder…"), - "mail-folder-new" }, - - { "mail-popup-folder-properties", - NULL, - "mail-folder-properties" }, - - { "mail-popup-folder-refresh", - NULL, - "mail-folder-refresh" }, - - { "mail-popup-folder-rename", - NULL, - "mail-folder-rename" }, - - { "mail-popup-folder-unsubscribe", - NULL, - "mail-folder-unsubscribe" }, - - { "mail-popup-manage-subscriptions", - NULL, - "mail-manage-subscriptions" } -}; - -static GtkToggleActionEntry mail_toggle_entries[] = { - - { "mail-preview", - NULL, - N_("Show Message _Preview"), - "m", - N_("Show message preview pane"), - NULL, /* Handled by property bindings */ - TRUE }, - - { "mail-attachment-bar", - NULL, - N_("Show _Attachment Bar"), - NULL, - N_("Show Attachment Bar below the message preview pane when the message has attachments"), - G_CALLBACK (action_mail_attachment_bar_cb), - TRUE }, - - { "mail-show-deleted", - NULL, - N_("Show _Deleted Messages"), - NULL, - N_("Show deleted messages with a line through them"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "mail-show-junk", - NULL, - N_("Show _Junk Messages"), - NULL, - N_("Show junk messages with a red line through them"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "mail-show-preview-toolbar", - NULL, - N_("Show _Preview Tool Bar"), - NULL, - N_("Show tool bar above the preview panel"), - G_CALLBACK (action_mail_show_preview_toolbar_cb), - TRUE }, - - { "mail-threads-group-by", - NULL, - N_("_Group By Threads"), - "t", - N_("Threaded message list"), - NULL, /* Handled by property bindings */ - FALSE }, - - { "mail-to-do-bar", - NULL, - N_("Show To _Do Bar"), - NULL, - N_("Show To Do bar with appointments and tasks"), - G_CALLBACK (action_mail_to_do_bar_cb), - TRUE }, - - { "mail-vfolder-unmatched-enable", - NULL, - N_("_Unmatched Folder Enabled"), - NULL, - N_("Toggles whether Unmatched search folder is enabled"), - NULL } -}; - -static GtkRadioActionEntry mail_view_entries[] = { - - /* This action represents the initial active mail view. - * It should not be visible in the UI, nor should it be - * possible to switch to it from another shell view. */ - { "mail-view-initial", - NULL, - NULL, - NULL, - NULL, - -1 }, - - { "mail-view-classic", - NULL, - N_("_Classic View"), - NULL, - N_("Show message preview below the message list"), - 0 }, - - { "mail-view-vertical", - NULL, - N_("_Vertical View"), - NULL, - N_("Show message preview alongside the message list"), - 1 } -}; - -static GtkRadioActionEntry mail_filter_entries[] = { - - { "mail-filter-all-messages", - NULL, - N_("All Messages"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_ALL_MESSAGES }, - - { "mail-filter-important-messages", - "emblem-important", - N_("Important Messages"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_IMPORTANT_MESSAGES }, - - { "mail-filter-last-5-days-messages", - NULL, - N_("Last 5 Days’ Messages"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_LAST_5_DAYS_MESSAGES }, - - { "mail-filter-messages-not-junk", - "mail-mark-notjunk", - N_("Messages Not Junk"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_MESSAGES_NOT_JUNK }, - - { "mail-filter-messages-with-attachments", - "mail-attachment", - N_("Messages with Attachments"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS }, - - { "mail-filter-messages-with-notes", - "evolution-memos", - N_("Messages with Notes"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_MESSAGES_WITH_NOTES }, - - { "mail-filter-no-label", - NULL, - N_("No Label"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_NO_LABEL }, - - { "mail-filter-read-messages", - "mail-read", - N_("Read Messages"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_READ_MESSAGES }, - - { "mail-filter-unread-messages", - "mail-unread", - N_("Unread Messages"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_UNREAD_MESSAGES }, - - { "mail-filter-message-thread", - NULL, - N_("Message Thread"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_FILTER_MESSAGE_THREAD } - -}; - -static GtkRadioActionEntry mail_search_entries[] = { - - { "mail-search-advanced-hidden", - NULL, - N_("Advanced Search"), - NULL, - NULL, - MAIL_SEARCH_ADVANCED }, - - { "mail-search-body-contains", - NULL, - N_("Body contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SEARCH_BODY_CONTAINS }, - - { "mail-search-free-form-expr", - NULL, - N_("Free form expression"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SEARCH_FREE_FORM_EXPR }, - - { "mail-search-message-contains", - NULL, - N_("Message contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SEARCH_MESSAGE_CONTAINS }, - - { "mail-search-recipients-contain", - NULL, - N_("Recipients contain"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SEARCH_RECIPIENTS_CONTAIN }, - - { "mail-search-sender-contains", - NULL, - N_("Sender contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SEARCH_SENDER_CONTAINS }, - - { "mail-search-subject-contains", - NULL, - N_("Subject contains"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SEARCH_SUBJECT_CONTAINS }, - - { "mail-search-subject-or-addresses-contain", - NULL, - N_("Subject or Addresses contain"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SEARCH_SUBJECT_OR_ADDRESSES_CONTAIN } -}; - -static GtkRadioActionEntry mail_scope_entries[] = { - - { "mail-scope-all-accounts", - NULL, - N_("All Accounts"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SCOPE_ALL_ACCOUNTS }, - - { "mail-scope-current-account", - NULL, - N_("Current Account"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SCOPE_CURRENT_ACCOUNT }, - - { "mail-scope-current-folder", - NULL, - N_("Current Folder"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SCOPE_CURRENT_FOLDER }, - - { "mail-scope-current-folder-and-subfolders", - NULL, - N_("Current Folder and Subfolders"), - NULL, - NULL, /* XXX Add a tooltip! */ - MAIL_SCOPE_CURRENT_FOLDER_AND_SUBFOLDERS } -}; - void e_mail_shell_view_actions_init (EMailShellView *mail_shell_view) { - EMailShellContent *mail_shell_content; + static const EUIActionEntry mail_entries[] = { + + { "mail-account-disable", + NULL, + N_("_Disable Account"), + NULL, + N_("Disable this account"), + action_mail_account_disable_cb, NULL, NULL, NULL }, + + { "mail-account-expunge", + NULL, + N_("_Empty Trash"), + NULL, + N_("Permanently remove all the deleted messages from all folders"), + action_mail_folder_expunge_cb, NULL, NULL, NULL }, + + { "mail-account-empty-junk", + NULL, + N_("Empty _Junk"), + NULL, + N_("Delete all Junk messages from all folders"), + action_mail_folder_empty_junk_cb, NULL, NULL, NULL }, + + { "mail-account-properties", + "document-properties", + N_("_Properties"), + NULL, + N_("Edit properties of this account"), + action_mail_account_properties_cb, NULL, NULL, NULL }, + + { "mail-account-refresh", + "view-refresh", + N_("_Refresh"), + NULL, + N_("Refresh list of folders of this account"), + action_mail_account_refresh_cb, NULL, NULL, NULL }, + + { "mail-download", + NULL, + N_("_Download Messages for Offline Usage"), + NULL, + N_("Download messages of accounts and folders marked for offline usage"), + action_mail_download_cb, NULL, NULL, NULL }, + + { "mail-flush-outbox", + "mail-send", + N_("Fl_ush Outbox"), + NULL, + NULL, + action_mail_flush_outbox_cb, NULL, NULL, NULL }, + + { "mail-folder-copy", + "folder-copy", + N_("_Copy Folder To…"), + NULL, + N_("Copy the selected folder into another folder"), + action_mail_folder_copy_cb, NULL, NULL, NULL }, + + { "mail-folder-delete", + "edit-delete", + N_("_Delete"), + NULL, + N_("Permanently remove this folder"), + action_mail_folder_delete_cb, NULL, NULL, NULL }, + + { "mail-folder-edit-sort-order", + NULL, + N_("Edit Sort _Order…"), + NULL, + N_("Change sort order of the folders in the folder tree"), + action_mail_folder_edit_sort_order_cb, NULL, NULL, NULL }, + + { "mail-folder-expunge", + NULL, + N_("E_xpunge"), + "e", + N_("Permanently remove all deleted messages from this folder"), + action_mail_folder_expunge_cb, NULL, NULL, NULL }, + + { "mail-folder-mark-all-as-read", + "mail-mark-read", + N_("Mar_k All Messages as Read"), + "slash", + N_("Mark all messages in the folder as read"), + action_mail_folder_mark_all_as_read_cb, NULL, NULL, NULL }, + + { "mail-folder-move", + "folder-move", + N_("_Move Folder To…"), + NULL, + N_("Move the selected folder into another folder"), + action_mail_folder_move_cb, NULL, NULL, NULL }, + + { "mail-folder-new", + "folder-new", + /* Translators: An action caption to create a new mail folder */ + N_("_New…"), + NULL, + N_("Create a new folder for storing mail"), + action_mail_folder_new_cb, NULL, NULL, NULL }, + + { "mail-folder-new-full", + "folder-new", + N_("_New Folder…"), + NULL, + N_("Create a new folder for storing mail"), + action_mail_folder_new_cb, NULL, NULL, NULL }, + + { "mail-folder-properties", + "document-properties", + N_("_Properties"), + NULL, + N_("Change the properties of this folder"), + action_mail_folder_properties_cb, NULL, NULL, NULL }, + + { "mail-folder-refresh", + "view-refresh", + N_("_Refresh"), + "F5", + N_("Refresh the folder"), + action_mail_folder_refresh_cb, NULL, NULL, NULL }, + + { "mail-folder-rename", + NULL, + N_("_Rename…"), + NULL, + N_("Change the name of this folder"), + action_mail_folder_rename_cb, NULL, NULL, NULL }, + + { "mail-folder-select-thread", + NULL, + N_("Select Message _Thread"), + "h", + N_("Select all messages in the same thread as the selected message"), + action_mail_folder_select_thread_cb, NULL, NULL, NULL }, + + { "mail-folder-select-subthread", + NULL, + N_("Select Message S_ubthread"), + "h", + N_("Select all replies to the currently selected message"), + action_mail_folder_select_subthread_cb, NULL, NULL, NULL }, + + { "mail-folder-unsubscribe", + NULL, + N_("_Unsubscribe"), + NULL, + N_("Unsubscribe from the selected folder"), + action_mail_folder_unsubscribe_cb, NULL, NULL, NULL }, + + { "mail-global-expunge", + NULL, + N_("Empty _Trash"), + NULL, + N_("Permanently remove all the deleted messages from all accounts"), + action_mail_global_expunge_cb, NULL, NULL, NULL }, + + { "mail-goto-folder", + NULL, + N_("Go to _Folder"), + "g", + N_("Opens a dialog to select a folder to go to"), + action_mail_goto_folder_cb, NULL, NULL, NULL }, + + /* This is the same as "mail-tools-subscriptions" but only + * appears in the sidebar context menu when right-clicking + * on a store that supports folder subscriptions. No need + * for a special callback because Folder->Subscriptions... + * already tries to open the "Folder Subscriptions" dialog + * according to the highlighted item in the sidebar, which + * is exactly the behavior we want here. */ + { "mail-manage-subscriptions", + NULL, + N_("_Manage Subscriptions"), + NULL, + N_("Subscribe or unsubscribe to folders on remote servers"), + action_mail_tools_subscriptions_cb, NULL, NULL, NULL }, + + { "mail-popup-folder-mark-all-as-read", + "mail-mark-read", + N_("Mar_k All Messages as Read"), + NULL, + N_("Mark all messages in the folder as read"), + action_mail_popup_folder_mark_all_as_read_cb, NULL, NULL, NULL }, + + { "mail-send-receive", + "mail-send-receive", + N_("Send / _Receive"), + "F12", + N_("Send queued items and retrieve new items"), + action_mail_send_receive_cb, NULL, NULL, NULL }, + + { "mail-send-receive-receive-all", + NULL, + N_("R_eceive All"), + NULL, + N_("Receive new items from all accounts"), + action_mail_send_receive_receive_all_cb, NULL, NULL, NULL }, + + { "mail-send-receive-send-all", + "mail-send", + N_("_Send All"), + NULL, + N_("Send queued items in all accounts"), + action_mail_send_receive_send_all_cb, NULL, NULL, NULL }, + + { "mail-smart-backward", + "go-up", /* In case a user adds it to the UI */ + "Mail smart backward", + "BackSpace", + NULL, + action_mail_smart_backward_cb, NULL, NULL, NULL }, + + { "mail-smart-forward", + "go-down", /* In case a user adds it to the UI */ + "Mail smart forward", + "space", + NULL, + action_mail_smart_forward_cb, NULL, NULL, NULL }, + + { "mail-stop", + "process-stop", + N_("Cancel"), + NULL, + N_("Cancel the current mail operation"), + action_mail_stop_cb, NULL, NULL, NULL }, + + { "mail-threads-collapse-all", + NULL, + N_("Collapse All _Threads"), + "b", + N_("Collapse all message threads"), + action_mail_threads_collapse_all_cb, NULL, NULL, NULL }, + + { "mail-threads-expand-all", + NULL, + N_("E_xpand All Threads"), + NULL, + N_("Expand all message threads"), + action_mail_threads_expand_all_cb, NULL, NULL, NULL }, + + { "mail-tools-filters", + NULL, + N_("_Message Filters"), + NULL, + N_("Create or edit rules for filtering new mail"), + action_mail_tools_filters_cb, NULL, NULL, NULL }, + + { "mail-tools-subscriptions", + NULL, + N_("_Subscriptions…"), + NULL, + N_("Subscribe or unsubscribe to folders on remote servers"), + action_mail_tools_subscriptions_cb, NULL, NULL, NULL }, + + /*** Menus ***/ + + { "mail-folder-menu", NULL, N_("F_older"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "mail-preview-menu", NULL, N_("_Preview"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EMailShellView::mail-send-receive", "mail-send-receive", N_("Send / _Receive"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + + static const EUIActionEntry search_folder_entries[] = { + + { "mail-create-search-folder", + NULL, + N_("C_reate Search Folder From Search…"), + NULL, + NULL, + action_mail_create_search_folder_cb, NULL, NULL, NULL }, + + { "mail-tools-search-folders", + NULL, + N_("Search F_olders"), + NULL, + N_("Create or edit search folder definitions"), + action_mail_tools_search_folders_cb, NULL, NULL, NULL }, + }; + + static const EUIActionEntry mail_toggle_entries[] = { + + { "mail-preview", + NULL, + N_("Show Message _Preview"), + "m", + N_("Show message preview pane"), + NULL, NULL, "true", NULL /* Handled by property bindings */ }, + + { "mail-attachment-bar", + NULL, + N_("Show _Attachment Bar"), + NULL, + N_("Show Attachment Bar below the message preview pane when the message has attachments"), + NULL, NULL, "true", action_mail_attachment_bar_cb }, + + { "mail-show-deleted", + NULL, + N_("Show _Deleted Messages"), + NULL, + N_("Show deleted messages with a line through them"), + NULL, NULL, "false", NULL }, /* Handled by property bindings */ + + { "mail-show-junk", + NULL, + N_("Show _Junk Messages"), + NULL, + N_("Show junk messages with a red line through them"), + NULL, NULL, "false", NULL }, /* Handled by property bindings */ + + { "mail-show-preview-toolbar", + NULL, + N_("Show _Preview Tool Bar"), + NULL, + N_("Show tool bar above the preview panel"), + NULL, NULL, "true", NULL }, /* Handled by property bindings */ + + { "mail-threads-group-by", + NULL, + N_("_Group By Threads"), + "t", + N_("Threaded message list"), + NULL, NULL, "false", NULL }, /* Handled by property bindings */ + + { "mail-to-do-bar", + NULL, + N_("Show To _Do Bar"), + NULL, + N_("Show To Do bar with appointments and tasks"), + NULL, NULL, "true", action_mail_to_do_bar_cb }, + + { "mail-vfolder-unmatched-enable", + NULL, + N_("_Unmatched Folder Enabled"), + NULL, + N_("Toggles whether Unmatched search folder is enabled"), + NULL, NULL, "true", NULL } + }; + + static const EUIActionEnumEntry mail_view_entries[] = { + + { "mail-view-classic", + NULL, + N_("_Classic View"), + NULL, + N_("Show message preview below the message list"), + NULL, 0 }, + + { "mail-view-vertical", + NULL, + N_("_Vertical View"), + NULL, + N_("Show message preview alongside the message list"), + NULL, 1 } + }; + + static const EUIActionEnumEntry mail_search_entries[] = { + + { "mail-search-advanced-hidden", + NULL, + N_("Advanced Search"), + NULL, + NULL, + NULL, MAIL_SEARCH_ADVANCED }, + + { "mail-search-body-contains", + NULL, + N_("Body contains"), + NULL, + NULL, + NULL, MAIL_SEARCH_BODY_CONTAINS }, + + { "mail-search-free-form-expr", + NULL, + N_("Free form expression"), + NULL, + NULL, + NULL, MAIL_SEARCH_FREE_FORM_EXPR }, + + { "mail-search-message-contains", + NULL, + N_("Message contains"), + NULL, + NULL, + NULL, MAIL_SEARCH_MESSAGE_CONTAINS }, + + { "mail-search-recipients-contain", + NULL, + N_("Recipients contain"), + NULL, + NULL, + NULL, MAIL_SEARCH_RECIPIENTS_CONTAIN }, + + { "mail-search-sender-contains", + NULL, + N_("Sender contains"), + NULL, + NULL, + NULL, MAIL_SEARCH_SENDER_CONTAINS }, + + { "mail-search-subject-contains", + NULL, + N_("Subject contains"), + NULL, + NULL, + NULL, MAIL_SEARCH_SUBJECT_CONTAINS }, + + { "mail-search-subject-or-addresses-contain", + NULL, + N_("Subject or Addresses contain"), + NULL, + NULL, + NULL, MAIL_SEARCH_SUBJECT_OR_ADDRESSES_CONTAIN } + }; + + static const EUIActionEnumEntry mail_scope_entries[] = { + + { "mail-scope-all-accounts", + NULL, + N_("All Accounts"), + NULL, + NULL, + NULL, MAIL_SCOPE_ALL_ACCOUNTS }, + + { "mail-scope-current-account", + NULL, + N_("Current Account"), + NULL, + NULL, + NULL, MAIL_SCOPE_CURRENT_ACCOUNT }, + + { "mail-scope-current-folder", + NULL, + N_("Current Folder"), + NULL, + NULL, + NULL, MAIL_SCOPE_CURRENT_FOLDER }, + + { "mail-scope-current-folder-and-subfolders", + NULL, + N_("Current Folder and Subfolders"), + NULL, + NULL, + NULL, MAIL_SCOPE_CURRENT_FOLDER_AND_SUBFOLDERS } + }; + EShellView *shell_view; EShellWindow *shell_window; EShellBackend *shell_backend; EShell *shell; - EShellSearchbar *searchbar; - EActionComboBox *combo_box; - EMailView *mail_view; - GtkActionGroup *action_group; - GtkAction *action; - GSettings *settings; + EUIManager *ui_manager; + GPtrArray *group; + guint ii; g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view)); @@ -2211,106 +2081,35 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view) shell_window = e_shell_view_get_shell_window (shell_view); shell_backend = e_shell_view_get_shell_backend (shell_view); shell = e_shell_window_get_shell (shell_window); - - mail_shell_content = mail_shell_view->priv->mail_shell_content; - mail_view = e_mail_shell_content_get_mail_view (mail_shell_content); - searchbar = e_mail_shell_content_get_searchbar (mail_shell_content); + ui_manager = e_shell_view_get_ui_manager (shell_view); /* Mail Actions */ - action_group = ACTION_GROUP (MAIL); - gtk_action_group_add_actions ( - action_group, mail_entries, - G_N_ELEMENTS (mail_entries), mail_shell_view); - gtk_action_group_add_toggle_actions ( - action_group, mail_toggle_entries, - G_N_ELEMENTS (mail_toggle_entries), mail_shell_view); - gtk_action_group_add_radio_actions ( - action_group, mail_view_entries, - G_N_ELEMENTS (mail_view_entries), -1, - G_CALLBACK (action_mail_view_cb), mail_shell_view); - gtk_action_group_add_radio_actions ( - action_group, mail_search_entries, - G_N_ELEMENTS (mail_search_entries), - -1, NULL, NULL); - gtk_action_group_add_radio_actions ( - action_group, mail_scope_entries, - G_N_ELEMENTS (mail_scope_entries), - MAIL_SCOPE_CURRENT_FOLDER, NULL, NULL); - e_action_group_add_popup_actions ( - action_group, mail_popup_entries, - G_N_ELEMENTS (mail_popup_entries)); - - /* WebKitGTK does not support print preview, thus hide the option from the menu; - maybe it'll be supported in the future */ - action = ACTION (MAIL_PRINT_PREVIEW); - gtk_action_set_visible (action, FALSE); + e_ui_manager_add_actions (ui_manager, "mail", NULL, + mail_entries, G_N_ELEMENTS (mail_entries), mail_shell_view); + e_ui_manager_add_actions (ui_manager, "mail", NULL, + mail_toggle_entries, G_N_ELEMENTS (mail_toggle_entries), mail_shell_view); + e_ui_manager_add_actions_enum (ui_manager, "mail", NULL, + mail_view_entries, G_N_ELEMENTS (mail_view_entries), mail_shell_view); + e_ui_manager_add_actions_enum (ui_manager, "mail", NULL, + mail_search_entries, G_N_ELEMENTS (mail_search_entries), mail_shell_view); + e_ui_manager_add_actions_enum (ui_manager, "mail", NULL, + mail_scope_entries, G_N_ELEMENTS (mail_scope_entries), mail_shell_view); /* Search Folder Actions */ - action_group = ACTION_GROUP (SEARCH_FOLDERS); - gtk_action_group_add_actions ( - action_group, search_folder_entries, - G_N_ELEMENTS (search_folder_entries), mail_shell_view); + e_ui_manager_add_actions (ui_manager, "search-folders", NULL, + search_folder_entries, G_N_ELEMENTS (search_folder_entries), mail_shell_view); - action = ACTION (MAIL_SCOPE_ALL_ACCOUNTS); - combo_box = e_shell_searchbar_get_scope_combo_box (searchbar); - e_action_combo_box_set_action (combo_box, GTK_RADIO_ACTION (action)); - e_shell_searchbar_set_scope_visible (searchbar, TRUE); + /* Add scopes into a radio group */ - /* Advanced Search Action */ - action = ACTION (MAIL_SEARCH_ADVANCED_HIDDEN); - gtk_action_set_visible (action, FALSE); - e_shell_searchbar_set_search_option ( - searchbar, GTK_RADIO_ACTION (action)); + group = g_ptr_array_sized_new (G_N_ELEMENTS (mail_scope_entries)); - g_object_set (ACTION (MAIL_SEND_RECEIVE), "is-important", TRUE, NULL); + for (ii = 0; ii < G_N_ELEMENTS (mail_scope_entries); ii++) { + EUIAction *action = e_ui_manager_get_action (ui_manager, mail_scope_entries[ii].name); - /* Bind GObject properties for GSettings keys. */ - - settings = e_util_ref_settings ("org.gnome.evolution.mail"); - - g_settings_bind ( - settings, "show-deleted", - ACTION (MAIL_SHOW_DELETED), "active", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "show-junk", - ACTION (MAIL_SHOW_JUNK), "active", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "show-preview-toolbar", - ACTION (MAIL_SHOW_PREVIEW_TOOLBAR), "active", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "layout", - ACTION (MAIL_VIEW_VERTICAL), "current-value", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "enable-unmatched", - ACTION (MAIL_VFOLDER_UNMATCHED_ENABLE), "active", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "show-attachment-bar", - ACTION (MAIL_ATTACHMENT_BAR), "active", - G_SETTINGS_BIND_DEFAULT); - - if (e_shell_window_is_main_instance (shell_window)) { - g_settings_bind ( - settings, "show-to-do-bar", - ACTION (MAIL_TO_DO_BAR), "active", - G_SETTINGS_BIND_DEFAULT); - } else { - g_settings_bind ( - settings, "show-to-do-bar-sub", - ACTION (MAIL_TO_DO_BAR), "active", - G_SETTINGS_BIND_DEFAULT); + e_ui_action_set_radio_group (action, group); } - g_object_unref (settings); + g_clear_pointer (&group, g_ptr_array_unref); /* Fine tuning. */ @@ -2334,18 +2133,6 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view) ACTION (MAIL_THREADS_EXPAND_ALL), "sensitive", G_BINDING_SYNC_CREATE); - e_binding_bind_property ( - ACTION (MAIL_PREVIEW), "active", - mail_view, "preview-visible", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - ACTION (MAIL_THREADS_GROUP_BY), "active", - mail_shell_content, "group-by-threads", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - e_binding_bind_property ( ACTION (MAIL_PREVIEW), "active", ACTION (MAIL_VIEW_CLASSIC), "sensitive", @@ -2356,31 +2143,11 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view) ACTION (MAIL_VIEW_VERTICAL), "sensitive", G_BINDING_SYNC_CREATE); - e_binding_bind_property ( - ACTION (MAIL_SHOW_DELETED), "active", - mail_view, "show-deleted", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - ACTION (MAIL_SHOW_JUNK), "active", - mail_view, "show-junk", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - e_binding_bind_property ( shell_backend, "busy", ACTION (MAIL_STOP), "sensitive", G_BINDING_SYNC_CREATE); - /* Keep the sensitivity of "Create Search Folder from Search" - * in sync with "Save Search" so that its only selectable when - * showing search results. */ - e_binding_bind_property ( - ACTION (SEARCH_SAVE), "sensitive", - ACTION (MAIL_CREATE_SEARCH_FOLDER), "sensitive", - G_BINDING_SYNC_CREATE); - e_binding_bind_property ( shell, "online", ACTION (MAIL_DOWNLOAD), "sensitive", @@ -2390,27 +2157,97 @@ e_mail_shell_view_actions_init (EMailShellView *mail_shell_view) void e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view) { + static const EUIActionEnumEntry mail_filter_entries[] = { + + { "mail-filter-all-messages", + NULL, + N_("All Messages"), + NULL, + NULL, + NULL, MAIL_FILTER_ALL_MESSAGES }, + + { "mail-filter-important-messages", + "emblem-important", + N_("Important Messages"), + NULL, + NULL, + NULL, MAIL_FILTER_IMPORTANT_MESSAGES }, + + { "mail-filter-last-5-days-messages", + NULL, + N_("Last 5 Days’ Messages"), + NULL, + NULL, + NULL, MAIL_FILTER_LAST_5_DAYS_MESSAGES }, + + { "mail-filter-messages-not-junk", + "mail-mark-notjunk", + N_("Messages Not Junk"), + NULL, + NULL, + NULL, MAIL_FILTER_MESSAGES_NOT_JUNK }, + + { "mail-filter-messages-with-attachments", + "mail-attachment", + N_("Messages with Attachments"), + NULL, + NULL, + NULL, MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS }, + + { "mail-filter-messages-with-notes", + "evolution-memos", + N_("Messages with Notes"), + NULL, + NULL, + NULL, MAIL_FILTER_MESSAGES_WITH_NOTES }, + + { "mail-filter-no-label", + NULL, + N_("No Label"), + NULL, + NULL, + NULL, MAIL_FILTER_NO_LABEL }, + + { "mail-filter-read-messages", + "mail-read", + N_("Read Messages"), + NULL, + NULL, + NULL, MAIL_FILTER_READ_MESSAGES }, + + { "mail-filter-unread-messages", + "mail-unread", + N_("Unread Messages"), + NULL, + NULL, + NULL, MAIL_FILTER_UNREAD_MESSAGES }, + + { "mail-filter-message-thread", + NULL, + N_("Message Thread"), + NULL, + NULL, + NULL, MAIL_FILTER_MESSAGE_THREAD } + }; + EMailShellContent *mail_shell_content; EShellView *shell_view; - EShellWindow *shell_window; EShellBackend *shell_backend; EShellSearchbar *searchbar; EMailLabelListStore *label_store; EMailBackend *backend; EMailSession *session; EActionComboBox *combo_box; - GtkActionGroup *action_group; - GtkRadioAction *radio_action; + EUIActionGroup *action_group; + EUIAction *action; GtkTreeIter iter; - GList *list; - GSList *group; + GPtrArray *radio_group; gboolean valid; - gint ii = 0; + gint ii; g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view)); shell_view = E_SHELL_VIEW (mail_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); shell_backend = e_shell_view_get_shell_backend (shell_view); backend = E_MAIL_BACKEND (shell_backend); @@ -2418,55 +2255,49 @@ e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view) label_store = e_mail_ui_session_get_label_store ( E_MAIL_UI_SESSION (session)); - action_group = ACTION_GROUP (MAIL_FILTER); - e_action_group_remove_all_actions (action_group); + action_group = e_ui_manager_get_action_group (e_shell_view_get_ui_manager (shell_view), "mail-filter"); + e_ui_action_group_remove_all (action_group); /* Add the standard filter actions. No callback is needed * because changes in the EActionComboBox are detected and * handled by EShellSearchbar. */ - gtk_action_group_add_radio_actions ( - action_group, mail_filter_entries, - G_N_ELEMENTS (mail_filter_entries), - MAIL_FILTER_ALL_MESSAGES, NULL, NULL); + e_ui_manager_add_actions_enum (e_shell_view_get_ui_manager (shell_view), + e_ui_action_group_get_name (action_group), NULL, + mail_filter_entries, G_N_ELEMENTS (mail_filter_entries), NULL); - /* Retrieve the radio group from an action we just added. */ - list = gtk_action_group_list_actions (action_group); - radio_action = GTK_RADIO_ACTION (list->data); - group = gtk_radio_action_get_group (radio_action); - g_list_free (list); + radio_group = g_ptr_array_new (); - valid = gtk_tree_model_get_iter_first ( - GTK_TREE_MODEL (label_store), &iter); + for (ii = 0; ii < G_N_ELEMENTS (mail_filter_entries); ii++) { + action = e_ui_action_group_get_action (action_group, mail_filter_entries[ii].name); + e_ui_action_set_radio_group (action, radio_group); + } + + ii = 0; /* start labels from zero, mail_shell_view_execute_search() expects it */ + valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (label_store), &iter); while (valid) { - GtkAction *action; - gchar *action_name; - gchar *stock_id; + gchar action_name[128]; + gchar *icon_name; gchar *label; - label = e_mail_label_list_store_get_name ( - label_store, &iter); - stock_id = e_mail_label_list_store_get_stock_id ( - label_store, &iter); + label = e_mail_label_list_store_get_name (label_store, &iter); + icon_name = e_mail_label_list_store_dup_icon_name (label_store, &iter); - action_name = g_strdup_printf ("mail-filter-label-%d", ii); - radio_action = gtk_radio_action_new ( - action_name, label, NULL, stock_id, ii); - g_free (action_name); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "mail-filter-label-%d", ii) < sizeof (action_name)); - gtk_radio_action_set_group (radio_action, group); - group = gtk_radio_action_get_group (radio_action); + action = e_ui_action_new (e_ui_action_group_get_name (action_group), action_name, NULL); + e_ui_action_set_label (action, label); + e_ui_action_set_icon_name (action, icon_name); + e_ui_action_set_state (action, g_variant_new_int32 (ii)); + e_ui_action_set_radio_group (action, radio_group); - /* The action group takes ownership of the action. */ - action = GTK_ACTION (radio_action); - gtk_action_group_add_action (action_group, action); - g_object_unref (radio_action); + e_ui_action_group_add (action_group, action); + g_object_unref (action); g_free (label); - g_free (stock_id); + g_free (icon_name); - valid = gtk_tree_model_iter_next ( - GTK_TREE_MODEL (label_store), &iter); + valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (label_store), &iter); ii++; } @@ -2477,7 +2308,7 @@ e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view) e_shell_view_block_execute_search (shell_view); /* Use any action in the group; doesn't matter which. */ - e_action_combo_box_set_action (combo_box, radio_action); + e_action_combo_box_set_action (combo_box, action); ii = MAIL_FILTER_MESSAGES_NOT_JUNK; e_action_combo_box_add_separator_after (combo_box, ii); diff --git a/src/modules/mail/e-mail-shell-view-actions.h b/src/modules/mail/e-mail-shell-view-actions.h index 2ce9e22190..36cb205670 100644 --- a/src/modules/mail/e-mail-shell-view-actions.h +++ b/src/modules/mail/e-mail-shell-view-actions.h @@ -21,266 +21,266 @@ #ifndef E_MAIL_SHELL_VIEW_ACTIONS_H #define E_MAIL_SHELL_VIEW_ACTIONS_H -#include +#include /* Mail Actions */ -#define E_SHELL_WINDOW_ACTION_MAIL_ACCOUNT_DISABLE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-account-disable") -#define E_SHELL_WINDOW_ACTION_MAIL_ACCOUNT_EXPUNGE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-account-expunge") -#define E_SHELL_WINDOW_ACTION_MAIL_ACCOUNT_EMPTY_JUNK(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-account-empty-junk") -#define E_SHELL_WINDOW_ACTION_MAIL_ACCOUNT_PROPERTIES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-account-properties") -#define E_SHELL_WINDOW_ACTION_MAIL_ACCOUNT_REFRESH(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-account-refresh") -#define E_SHELL_WINDOW_ACTION_MAIL_ADD_SENDER(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-add-sender") -#define E_SHELL_WINDOW_ACTION_MAIL_ATTACHMENT_BAR(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-attachment-bar") -#define E_SHELL_WINDOW_ACTION_MAIL_CARET_MODE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-caret-mode") -#define E_SHELL_WINDOW_ACTION_MAIL_CHECK_FOR_JUNK(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-check-for-junk") -#define E_SHELL_WINDOW_ACTION_MAIL_CLIPBOARD_COPY(window) \ - E_SHELL_WINDOw_ACTION ((window), "mail-clipboard-copy") -#define E_SHELL_WINDOW_ACTION_MAIL_COPY(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-copy") -#define E_SHELL_WINDOW_ACTION_MAIL_CREATE_SEARCH_FOLDER(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-create-search-folder") -#define E_SHELL_WINDOW_ACTION_MAIL_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-delete") -#define E_SHELL_WINDOW_ACTION_MAIL_DOWNLOAD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-download") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_RULE_FOR_MAILING_LIST(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-rule-for-mailing-list") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_RULE_FOR_RECIPIENTS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-rule-for-recipients") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_RULE_FOR_SENDER(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-rule-for-sender") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_RULE_FOR_SUBJECT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-rule-for-subject") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTERS_APPLY(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filters-apply") -#define E_SHELL_WINDOW_ACTION_MAIL_FIND(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-find") -#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_CLEAR(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-flag-clear") -#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_COMPLETED(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-flag-completed") -#define E_SHELL_WINDOW_ACTION_MAIL_FLAG_FOR_FOLLOWUP(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-flag-for-followup") -#define E_SHELL_WINDOW_ACTION_MAIL_FLUSH_OUTBOX(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-flush-outbox") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_COPY(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-copy") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_DELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-delete") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_EDIT_SORT_ORDER(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-edit-sort-order") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_EXPUNGE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-expunge") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_MARK_ALL_AS_READ(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-mark-all-as-read") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_MOVE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-move") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-new") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_PROPERTIES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-properties") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_REFRESH(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-refresh") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_RENAME(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-rename") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-all") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_THREAD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-thread") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_SELECT_SUBTHREAD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-select-subthread") -#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_UNSUBSCRIBE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-folder-unsubscribe") -#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-forward") -#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_ATTACHED(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-forward-attached") -#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_INLINE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-forward-inline") -#define E_SHELL_WINDOW_ACTION_MAIL_FORWARD_QUOTED(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-forward-quoted") -#define E_SHELL_WINDOW_ACTION_MAIL_LOAD_IMAGES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-load-images") -#define E_SHELL_WINDOW_ACTION_MAIL_MANAGE_SUBSCRIPTIONS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-manage-subscriptions") -#define E_SHELL_WINDOW_ACTION_MAIL_MARK_IMPORTANT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-mark-important") -#define E_SHELL_WINDOW_ACTION_MAIL_MARK_JUNK(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-mark-junk") -#define E_SHELL_WINDOW_ACTION_MAIL_MARK_NOTJUNK(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-mark-notjunk") -#define E_SHELL_WINDOW_ACTION_MAIL_MARK_READ(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-mark-read") -#define E_SHELL_WINDOW_ACTION_MAIL_MARK_UNIMPORTANT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-mark-unimportant") -#define E_SHELL_WINDOW_ACTION_MAIL_MARK_UNREAD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-mark-unread") -#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_EDIT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-message-edit") -#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_NEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-message-new") -#define E_SHELL_WINDOW_ACTION_MAIL_MESSAGE_OPEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-message-open") -#define E_SHELL_WINDOW_ACTION_MAIL_MOVE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-move") -#define E_SHELL_WINDOW_ACTION_MAIL_NEXT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-next") -#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_IMPORTANT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-next-important") -#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_THREAD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-next-thread") -#define E_SHELL_WINDOW_ACTION_MAIL_NEXT_UNREAD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-next-unread") -#define E_SHELL_WINDOW_ACTION_MAIL_POPUP_FOLDER_MARK_ALL_AS_READ(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-popup-folder-mark-all-as-read") -#define E_SHELL_WINDOW_ACTION_MAIL_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-preview") -#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-previous") -#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS_IMPORTANT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-previous-important") -#define E_SHELL_WINDOW_ACTION_MAIL_PREVIOUS_UNREAD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-previous-unread") -#define E_SHELL_WINDOW_ACTION_MAIL_PRINT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-print") -#define E_SHELL_WINDOW_ACTION_MAIL_PRINT_PREVIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-print-preview") -#define E_SHELL_WINDOW_ACTION_MAIL_REDIRECT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-redirect") -#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-reply-all") -#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_LIST(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-reply-list") -#define E_SHELL_WINDOW_ACTION_MAIL_REPLY_SENDER(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-reply-sender") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_ADVANCED_HIDDEN(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-advanced-hidden") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_MAILING_LIST(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-mailing-list") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_RECIPIENTS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-recipients") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_SENDER(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-sender") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FOLDER_FROM_SUBJECT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-folder-from-subject") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FREE_FORM_EXPR(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-free-form-expr") -#define E_SHELL_WINDOW_ACTION_MAIL_SELECT_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-select-all") -#define E_SHELL_WINDOW_ACTION_MAIL_SEND_RECEIVE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-send-receive") -#define E_SHELL_WINDOW_ACTION_MAIL_SEND_RECEIVE_RECEIVE_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-send-receive-receive-all") -#define E_SHELL_WINDOW_ACTION_MAIL_SEND_RECEIVE_SEND_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-send-receive-send-all") -#define E_SHELL_WINDOW_ACTION_MAIL_SEND_RECEIVE_SUBMENU(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-send-receive-submenu") -#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_ALL_HEADERS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-show-all-headers") -#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_DELETED(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-show-deleted") -#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_JUNK(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-show-junk") -#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_PREVIEW_TOOLBAR(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-show-preview-toolbar") -#define E_SHELL_WINDOW_ACTION_MAIL_SHOW_SOURCE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-show-source") -#define E_SHELL_WINDOW_ACTION_MAIL_SMART_BACKWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-smart-backward") -#define E_SHELL_WINDOW_ACTION_MAIL_SMART_FORWARD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-smart-forward") -#define E_SHELL_WINDOW_ACTION_MAIL_STOP(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-stop") -#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_COLLAPSE_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-threads-collapse-all") -#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_EXPAND_ALL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-threads-expand-all") -#define E_SHELL_WINDOW_ACTION_MAIL_THREADS_GROUP_BY(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-threads-group-by") -#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_FILTERS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-tools-filters") -#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_SEARCH_FOLDERS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-tools-search-folders") -#define E_SHELL_WINDOW_ACTION_MAIL_TOOLS_SUBSCRIPTIONS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-tools-subscriptions") -#define E_SHELL_WINDOW_ACTION_MAIL_TO_DO_BAR(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-to-do-bar") -#define E_SHELL_WINDOW_ACTION_MAIL_UNDELETE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-undelete") -#define E_SHELL_WINDOW_ACTION_MAIL_VFOLDER_UNMATCHED_ENABLE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-vfolder-unmatched-enable") -#define E_SHELL_WINDOW_ACTION_MAIL_VIEW_CLASSIC(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-view-classic") -#define E_SHELL_WINDOW_ACTION_MAIL_VIEW_VERTICAL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-view-vertical") -#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_100(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-zoom-100") -#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_IN(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-zoom-in") -#define E_SHELL_WINDOW_ACTION_MAIL_ZOOM_OUT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-zoom-out") +#define E_SHELL_VIEW_ACTION_MAIL_ACCOUNT_DISABLE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-account-disable") +#define E_SHELL_VIEW_ACTION_MAIL_ACCOUNT_EXPUNGE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-account-expunge") +#define E_SHELL_VIEW_ACTION_MAIL_ACCOUNT_EMPTY_JUNK(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-account-empty-junk") +#define E_SHELL_VIEW_ACTION_MAIL_ACCOUNT_PROPERTIES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-account-properties") +#define E_SHELL_VIEW_ACTION_MAIL_ACCOUNT_REFRESH(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-account-refresh") +#define E_SHELL_VIEW_ACTION_MAIL_ADD_SENDER(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-add-sender") +#define E_SHELL_VIEW_ACTION_MAIL_ATTACHMENT_BAR(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-attachment-bar") +#define E_SHELL_VIEW_ACTION_MAIL_CARET_MODE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-caret-mode") +#define E_SHELL_VIEW_ACTION_MAIL_CHECK_FOR_JUNK(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-check-for-junk") +#define E_SHELL_VIEW_ACTION_MAIL_CLIPBOARD_COPY(view) \ + E_SHELL_WINDOw_ACTION ((view), "mail-clipboard-copy") +#define E_SHELL_VIEW_ACTION_MAIL_COPY(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-copy") +#define E_SHELL_VIEW_ACTION_MAIL_CREATE_SEARCH_FOLDER(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-create-search-folder") +#define E_SHELL_VIEW_ACTION_MAIL_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-delete") +#define E_SHELL_VIEW_ACTION_MAIL_DOWNLOAD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-download") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_RULE_FOR_MAILING_LIST(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-rule-for-mailing-list") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_RULE_FOR_RECIPIENTS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-rule-for-recipients") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_RULE_FOR_SENDER(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-rule-for-sender") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_RULE_FOR_SUBJECT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-rule-for-subject") +#define E_SHELL_VIEW_ACTION_MAIL_FILTERS_APPLY(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filters-apply") +#define E_SHELL_VIEW_ACTION_MAIL_FIND(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-find") +#define E_SHELL_VIEW_ACTION_MAIL_FLAG_CLEAR(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-flag-clear") +#define E_SHELL_VIEW_ACTION_MAIL_FLAG_COMPLETED(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-flag-completed") +#define E_SHELL_VIEW_ACTION_MAIL_FLAG_FOR_FOLLOWUP(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-flag-for-followup") +#define E_SHELL_VIEW_ACTION_MAIL_FLUSH_OUTBOX(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-flush-outbox") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_COPY(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-copy") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_DELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-delete") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_EDIT_SORT_ORDER(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-edit-sort-order") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_EXPUNGE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-expunge") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_MARK_ALL_AS_READ(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-mark-all-as-read") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_MOVE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-move") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-new") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_NEW_FULL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-new-full") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_PROPERTIES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-properties") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_REFRESH(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-refresh") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_RENAME(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-rename") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_SELECT_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-select-all") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_SELECT_THREAD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-select-thread") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_SELECT_SUBTHREAD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-select-subthread") +#define E_SHELL_VIEW_ACTION_MAIL_FOLDER_UNSUBSCRIBE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-folder-unsubscribe") +#define E_SHELL_VIEW_ACTION_MAIL_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-forward") +#define E_SHELL_VIEW_ACTION_MAIL_FORWARD_ATTACHED(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-forward-attached") +#define E_SHELL_VIEW_ACTION_MAIL_FORWARD_INLINE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-forward-inline") +#define E_SHELL_VIEW_ACTION_MAIL_FORWARD_QUOTED(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-forward-quoted") +#define E_SHELL_VIEW_ACTION_MAIL_LOAD_IMAGES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-load-images") +#define E_SHELL_VIEW_ACTION_MAIL_MANAGE_SUBSCRIPTIONS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-manage-subscriptions") +#define E_SHELL_VIEW_ACTION_MAIL_MARK_IMPORTANT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-mark-important") +#define E_SHELL_VIEW_ACTION_MAIL_MARK_JUNK(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-mark-junk") +#define E_SHELL_VIEW_ACTION_MAIL_MARK_NOTJUNK(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-mark-notjunk") +#define E_SHELL_VIEW_ACTION_MAIL_MARK_READ(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-mark-read") +#define E_SHELL_VIEW_ACTION_MAIL_MARK_UNIMPORTANT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-mark-unimportant") +#define E_SHELL_VIEW_ACTION_MAIL_MARK_UNREAD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-mark-unread") +#define E_SHELL_VIEW_ACTION_MAIL_MESSAGE_EDIT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-message-edit") +#define E_SHELL_VIEW_ACTION_MAIL_MESSAGE_NEW(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-message-new") +#define E_SHELL_VIEW_ACTION_MAIL_MESSAGE_OPEN(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-message-open") +#define E_SHELL_VIEW_ACTION_MAIL_MOVE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-move") +#define E_SHELL_VIEW_ACTION_MAIL_NEXT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-next") +#define E_SHELL_VIEW_ACTION_MAIL_NEXT_IMPORTANT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-next-important") +#define E_SHELL_VIEW_ACTION_MAIL_NEXT_THREAD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-next-thread") +#define E_SHELL_VIEW_ACTION_MAIL_NEXT_UNREAD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-next-unread") +#define E_SHELL_VIEW_ACTION_MAIL_POPUP_FOLDER_MARK_ALL_AS_READ(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-popup-folder-mark-all-as-read") +#define E_SHELL_VIEW_ACTION_MAIL_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-preview") +#define E_SHELL_VIEW_ACTION_MAIL_PREVIOUS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-previous") +#define E_SHELL_VIEW_ACTION_MAIL_PREVIOUS_IMPORTANT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-previous-important") +#define E_SHELL_VIEW_ACTION_MAIL_PREVIOUS_UNREAD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-previous-unread") +#define E_SHELL_VIEW_ACTION_MAIL_PRINT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-print") +#define E_SHELL_VIEW_ACTION_MAIL_PRINT_PREVIEW(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-print-preview") +#define E_SHELL_VIEW_ACTION_MAIL_REDIRECT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-redirect") +#define E_SHELL_VIEW_ACTION_MAIL_REPLY_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-reply-all") +#define E_SHELL_VIEW_ACTION_MAIL_REPLY_LIST(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-reply-list") +#define E_SHELL_VIEW_ACTION_MAIL_REPLY_SENDER(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-reply-sender") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_ADVANCED_HIDDEN(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-advanced-hidden") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_FOLDER_FROM_MAILING_LIST(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-folder-from-mailing-list") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_FOLDER_FROM_RECIPIENTS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-folder-from-recipients") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_FOLDER_FROM_SENDER(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-folder-from-sender") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_FOLDER_FROM_SUBJECT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-folder-from-subject") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_FREE_FORM_EXPR(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-free-form-expr") +#define E_SHELL_VIEW_ACTION_MAIL_SELECT_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-select-all") +#define E_SHELL_VIEW_ACTION_MAIL_SEND_RECEIVE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-send-receive") +#define E_SHELL_VIEW_ACTION_MAIL_SEND_RECEIVE_RECEIVE_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-send-receive-receive-all") +#define E_SHELL_VIEW_ACTION_MAIL_SEND_RECEIVE_SEND_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-send-receive-send-all") +#define E_SHELL_VIEW_ACTION_MAIL_SHOW_ALL_HEADERS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-show-all-headers") +#define E_SHELL_VIEW_ACTION_MAIL_SHOW_DELETED(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-show-deleted") +#define E_SHELL_VIEW_ACTION_MAIL_SHOW_JUNK(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-show-junk") +#define E_SHELL_VIEW_ACTION_MAIL_SHOW_PREVIEW_TOOLBAR(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-show-preview-toolbar") +#define E_SHELL_VIEW_ACTION_MAIL_SHOW_SOURCE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-show-source") +#define E_SHELL_VIEW_ACTION_MAIL_SMART_BACKWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-smart-backward") +#define E_SHELL_VIEW_ACTION_MAIL_SMART_FORWARD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-smart-forward") +#define E_SHELL_VIEW_ACTION_MAIL_STOP(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-stop") +#define E_SHELL_VIEW_ACTION_MAIL_THREADS_COLLAPSE_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-threads-collapse-all") +#define E_SHELL_VIEW_ACTION_MAIL_THREADS_EXPAND_ALL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-threads-expand-all") +#define E_SHELL_VIEW_ACTION_MAIL_THREADS_GROUP_BY(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-threads-group-by") +#define E_SHELL_VIEW_ACTION_MAIL_TOOLS_FILTERS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-tools-filters") +#define E_SHELL_VIEW_ACTION_MAIL_TOOLS_SEARCH_FOLDERS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-tools-search-folders") +#define E_SHELL_VIEW_ACTION_MAIL_TOOLS_SUBSCRIPTIONS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-tools-subscriptions") +#define E_SHELL_VIEW_ACTION_MAIL_TO_DO_BAR(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-to-do-bar") +#define E_SHELL_VIEW_ACTION_MAIL_UNDELETE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-undelete") +#define E_SHELL_VIEW_ACTION_MAIL_VFOLDER_UNMATCHED_ENABLE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-vfolder-unmatched-enable") +#define E_SHELL_VIEW_ACTION_MAIL_VIEW_CLASSIC(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-view-classic") +#define E_SHELL_VIEW_ACTION_MAIL_VIEW_VERTICAL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-view-vertical") +#define E_SHELL_VIEW_ACTION_MAIL_ZOOM_100(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-zoom-100") +#define E_SHELL_VIEW_ACTION_MAIL_ZOOM_IN(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-zoom-in") +#define E_SHELL_VIEW_ACTION_MAIL_ZOOM_OUT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-zoom-out") /* Mail Query Actions */ -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ALL_MESSAGES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-all-messages") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_IMPORTANT_MESSAGES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-important-messages") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_LAST_5_DAYS_MESSAGES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-last-5-days-messages") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGE_THREAD(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-message-thread") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_NOT_JUNK(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-not-junk") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-with-attachments") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_MESSAGES_WITH_NOTES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-messages-with-notes") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_NO_LABEL(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-no-label") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_READ_MESSAGES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-read-messages") -#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_UNREAD_MESSAGES(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-filter-unread-messages") -#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_ALL_ACCOUNTS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-scope-all-accounts") -#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_ACCOUNT(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-account") -#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_FOLDER(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-folder") -#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_FOLDER_AND_SUBFOLDERS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-folder-and-subfolders") -#define E_SHELL_WINDOW_ACTION_MAIL_SCOPE_CURRENT_MESSAGE(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-scope-current-message") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_BODY_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-body-contains") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_FREE_FORM_EXPR(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-free-form-expr") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_MESSAGE_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-message-contains") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_RECIPIENTS_CONTAIN(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-recipients-contain") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SENDER_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-sender-contains") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_CONTAINS(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-contains") -#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_OR_ADDRESSES_CONTAIN(window) \ - E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-or-addresses-contain") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_ALL_MESSAGES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-all-messages") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_IMPORTANT_MESSAGES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-important-messages") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_LAST_5_DAYS_MESSAGES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-last-5-days-messages") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_MESSAGE_THREAD(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-message-thread") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_MESSAGES_NOT_JUNK(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-messages-not-junk") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-messages-with-attachments") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_MESSAGES_WITH_NOTES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-messages-with-notes") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_NO_LABEL(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-no-label") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_READ_MESSAGES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-read-messages") +#define E_SHELL_VIEW_ACTION_MAIL_FILTER_UNREAD_MESSAGES(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-filter-unread-messages") +#define E_SHELL_VIEW_ACTION_MAIL_SCOPE_ALL_ACCOUNTS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-scope-all-accounts") +#define E_SHELL_VIEW_ACTION_MAIL_SCOPE_CURRENT_ACCOUNT(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-scope-current-account") +#define E_SHELL_VIEW_ACTION_MAIL_SCOPE_CURRENT_FOLDER(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-scope-current-folder") +#define E_SHELL_VIEW_ACTION_MAIL_SCOPE_CURRENT_FOLDER_AND_SUBFOLDERS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-scope-current-folder-and-subfolders") +#define E_SHELL_VIEW_ACTION_MAIL_SCOPE_CURRENT_MESSAGE(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-scope-current-message") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_BODY_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-body-contains") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_FREE_FORM_EXPR(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-free-form-expr") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_MESSAGE_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-message-contains") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_RECIPIENTS_CONTAIN(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-recipients-contain") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_SENDER_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-sender-contains") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_SUBJECT_CONTAINS(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-subject-contains") +#define E_SHELL_VIEW_ACTION_MAIL_SEARCH_SUBJECT_OR_ADDRESSES_CONTAIN(view) \ + E_SHELL_VIEW_ACTION ((view), "mail-search-subject-or-addresses-contain") /* Action Groups */ -#define E_SHELL_WINDOW_ACTION_GROUP_MAIL(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "mail") -#define E_SHELL_WINDOW_ACTION_GROUP_MAIL_FILTER(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "mail-filter") -#define E_SHELL_WINDOW_ACTION_GROUP_SEARCH_FOLDERS(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "search-folders") +#define E_SHELL_VIEW_ACTION_GROUP_MAIL(view) \ + E_SHELL_VIEW_ACTION_GROUP ((view), "mail") +#define E_SHELL_VIEW_ACTION_GROUP_MAIL_FILTER(view) \ + E_SHELL_VIEW_ACTION_GROUP ((view), "mail-filter") +#define E_SHELL_VIEW_ACTION_GROUP_SEARCH_FOLDERS(view) \ + E_SHELL_VIEW_ACTION_GROUP ((view), "search-folders") #endif /* E_MAIL_SHELL_VIEW_ACTIONS_H */ diff --git a/src/modules/mail/e-mail-shell-view-private.c b/src/modules/mail/e-mail-shell-view-private.c index 2e67db978d..8c978eefb1 100644 --- a/src/modules/mail/e-mail-shell-view-private.c +++ b/src/modules/mail/e-mail-shell-view-private.c @@ -251,8 +251,7 @@ mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view, mail_shell_view = E_MAIL_SHELL_VIEW (shell_view); mail_shell_view->priv->ignore_folder_popup_selection_done = FALSE; - menu = e_shell_view_show_popup_menu ( - shell_view, "/mail-folder-popup", button_event); + menu = e_shell_view_show_popup_menu (shell_view, "mail-folder-popup", button_event); g_signal_connect_object ( menu, "selection-done", @@ -260,76 +259,10 @@ mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view, shell_view, G_CONNECT_SWAPPED); } -static gboolean -mail_shell_view_process_key_press_event (EMailShellView *mail_shell_view, - GdkEventKey *event, - gboolean pass_event) -{ - EShellView *shell_view; - EShellWindow *shell_window; - EShellContent *shell_content; - EMailView *mail_view; - EMailDisplay *mail_display; - - shell_view = E_SHELL_VIEW (mail_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - shell_content = e_shell_view_get_shell_content (shell_view); - mail_view = e_mail_shell_content_get_mail_view (E_MAIL_SHELL_CONTENT (shell_content)); - mail_display = e_mail_reader_get_mail_display (E_MAIL_READER (mail_view)); - - if (!event || (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0) - return event && e_mail_display_need_key_event (mail_display, event); - - if (e_shell_window_get_need_input (shell_window, event)) - return FALSE; - - if (e_web_view_get_need_input (E_WEB_VIEW (mail_display)) && - gtk_widget_has_focus (GTK_WIDGET (mail_display))) { - if (pass_event) - gtk_widget_event (GTK_WIDGET (mail_display), (GdkEvent *) event); - - return pass_event; - } - - return e_mail_display_need_key_event (mail_display, event); -} - -static gboolean -mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view, - GdkEventKey *event) -{ - return mail_shell_view_process_key_press_event (mail_shell_view, event, FALSE); -} - -static gboolean -mail_shell_window_key_press_event_cb (EMailShellView *mail_shell_view, - GdkEventKey *event, - EShellWindow *shell_window) -{ - if (!e_shell_view_is_active (E_SHELL_VIEW (mail_shell_view))) - return FALSE; - - return mail_shell_view_process_key_press_event (mail_shell_view, event, TRUE); -} - -static gboolean -mail_shell_view_message_list_key_press_cb (EMailShellView *mail_shell_view, - gint row, - ETreePath path, - gint col, - GdkEvent *event) -{ - return mail_shell_view_key_press_event_cb ( - mail_shell_view, &event->key); -} - static gboolean mail_shell_view_message_list_popup_menu_cb (EShellView *shell_view) { - const gchar *widget_path; - - widget_path = "/mail-message-popup"; - e_shell_view_show_popup_menu (shell_view, widget_path, NULL); + e_shell_view_show_popup_menu (shell_view, "mail-message-popup", NULL); return TRUE; } @@ -341,10 +274,7 @@ mail_shell_view_message_list_right_click_cb (EShellView *shell_view, gint col, GdkEvent *button_event) { - const gchar *widget_path; - - widget_path = "/mail-message-popup"; - e_shell_view_show_popup_menu (shell_view, widget_path, button_event); + e_shell_view_show_popup_menu (shell_view, "mail-message-popup", button_event); return TRUE; } @@ -373,10 +303,10 @@ mail_shell_view_popup_event_cb (EMailShellView *mail_shell_view, if (e_web_view_get_cursor_image_src (E_WEB_VIEW (display)) != NULL) return FALSE; - menu = e_mail_reader_get_popup_menu (reader); shell_view = E_SHELL_VIEW (mail_shell_view); e_shell_view_update_actions (shell_view); + menu = e_mail_reader_get_popup_menu (reader); gtk_menu_popup_at_pointer (menu, event); return TRUE; @@ -401,16 +331,9 @@ mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view, e_mail_shell_view_update_sidebar (mail_shell_view); /* Connect if its not connected already */ - if (g_signal_handler_find ( - message_list, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, - mail_shell_view_message_list_key_press_cb, NULL)) + if (g_signal_handler_find (message_list, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, mail_shell_view_message_list_popup_menu_cb, NULL)) return; - g_signal_connect_object ( - message_list, "key-press", - G_CALLBACK (mail_shell_view_message_list_key_press_cb), - mail_shell_view, G_CONNECT_SWAPPED); - g_signal_connect_object ( message_list, "popup-menu", G_CALLBACK (mail_shell_view_message_list_popup_menu_cb), @@ -421,11 +344,6 @@ mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view, G_CALLBACK (mail_shell_view_message_list_right_click_cb), mail_shell_view, G_CONNECT_SWAPPED); - g_signal_connect_object ( - display, "key-press-event", - G_CALLBACK (mail_shell_view_key_press_event_cb), - mail_shell_view, G_CONNECT_SWAPPED); - g_signal_connect_object ( display, "popup-event", G_CALLBACK (mail_shell_view_popup_event_cb), @@ -504,12 +422,45 @@ mail_shell_view_search_filter_changed_cb (EMailShellView *mail_shell_view) e_mail_reader_avoid_next_mark_as_seen (E_MAIL_READER (mail_view)); } +static void +e_mail_shell_view_mail_view_notify_cb (GObject *object, + GParamSpec *param, + gpointer user_data) +{ + GAction *action = G_ACTION (object); + EMailShellView *mail_shell_view = user_data; + EMailShellContent *mail_shell_content; + GtkOrientation orientation; + EMailView *mail_view; + GVariant *state; + + mail_shell_content = mail_shell_view->priv->mail_shell_content; + mail_view = e_mail_shell_content_get_mail_view (mail_shell_content); + state = g_action_get_state (G_ACTION (action)); + + switch (g_variant_get_int32 (state)) { + case 0: + orientation = GTK_ORIENTATION_VERTICAL; + break; + case 1: + orientation = GTK_ORIENTATION_HORIZONTAL; + break; + default: + g_return_if_reached (); + } + + e_mail_view_set_orientation (mail_view, orientation); + g_clear_pointer (&state, g_variant_unref); +} + void e_mail_shell_view_private_init (EMailShellView *mail_shell_view) { e_signal_connect_notify ( mail_shell_view, "notify::view-id", G_CALLBACK (mail_shell_view_notify_view_id_cb), NULL); + + mail_shell_view->priv->send_receive_menu = g_menu_new (); } void @@ -530,6 +481,8 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) EActionComboBox *combo_box; ERuleContext *context; EFilterRule *rule = NULL; + EUIAction *action; + EUIManager *ui_manager; GtkTreeSelection *selection; GtkWidget *message_list; GSettings *settings; @@ -550,22 +503,24 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) shell_window = e_shell_view_get_shell_window (shell_view); shell = e_shell_window_get_shell (shell_window); + ui_manager = e_shell_view_get_ui_manager (shell_view); + + e_ui_manager_freeze (ui_manager); backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); label_store = e_mail_ui_session_get_label_store ( E_MAIL_UI_SESSION (session)); - e_shell_window_add_action_group_full (shell_window, "mail", "mail"); - e_shell_window_add_action_group_full (shell_window, "mail-filter", "mail"); - e_shell_window_add_action_group_full (shell_window, "mail-labels", "mail"); - e_shell_window_add_action_group_full (shell_window, "search-folders", "mail"); - /* Cache these to avoid lots of awkward casting. */ priv->mail_shell_backend = E_MAIL_SHELL_BACKEND (g_object_ref (shell_backend)); - priv->mail_shell_content = E_MAIL_SHELL_CONTENT (g_object_ref (shell_content)); priv->mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (g_object_ref (shell_sidebar)); + /* this is set from the EMaiLShellView::contructed() method, because it's needed in the init_ui_data(), + to have available actions from the EMailReader, which is called from the EShellView::contructed(), + thus before this private_constructed() function */ + g_warn_if_fail (priv->mail_shell_content != NULL); + mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar); folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (folder_tree)); @@ -574,7 +529,7 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) mail_view = e_mail_shell_content_get_mail_view (mail_shell_content); searchbar = e_mail_shell_content_get_searchbar (mail_shell_content); - reader = E_MAIL_READER (shell_content); + reader = E_MAIL_READER (mail_view); display = e_mail_reader_get_mail_display (reader); message_list = e_mail_reader_get_message_list (reader); @@ -601,11 +556,6 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) G_CALLBACK (mail_shell_view_folder_tree_popup_event_cb), mail_shell_view, G_CONNECT_SWAPPED); - g_signal_connect_object ( - message_list, "key-press", - G_CALLBACK (mail_shell_view_message_list_key_press_cb), - mail_shell_view, G_CONNECT_SWAPPED); - g_signal_connect_object ( message_list, "popup-menu", G_CALLBACK (mail_shell_view_message_list_popup_menu_cb), @@ -642,11 +592,6 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) G_CALLBACK (e_mail_shell_view_update_search_filter), mail_shell_view, G_CONNECT_SWAPPED); - g_signal_connect_object ( - display, "key-press-event", - G_CALLBACK (mail_shell_view_key_press_event_cb), - mail_shell_view, G_CONNECT_SWAPPED); - g_signal_connect_object ( display, "popup-event", G_CALLBACK (mail_shell_view_popup_event_cb), @@ -657,16 +602,6 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) G_CALLBACK (e_shell_taskbar_set_message), shell_taskbar, G_CONNECT_SWAPPED); - g_signal_connect_object ( - mail_shell_view, "toggled", - G_CALLBACK (e_mail_shell_view_update_send_receive_menus), - mail_shell_view, G_CONNECT_AFTER | G_CONNECT_SWAPPED); - - g_signal_connect_object ( - shell_window, "key-press-event", - G_CALLBACK (mail_shell_window_key_press_event_cb), - mail_shell_view, G_CONNECT_SWAPPED); - /* Need to keep the handler ID so we can disconnect it in * dispose(). The shell outlives us and we don't want it * invoking callbacks on finalized shell views. */ @@ -676,22 +611,75 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) G_CALLBACK (mail_shell_view_prepare_for_quit_cb), mail_shell_view, G_CONNECT_SWAPPED); - e_mail_reader_init (reader, TRUE, FALSE); - e_mail_shell_view_actions_init (mail_shell_view); + /* Advanced Search Action */ + action = ACTION (MAIL_SEARCH_ADVANCED_HIDDEN); + e_ui_action_set_visible (action, FALSE); + searchbar = e_mail_shell_content_get_searchbar (mail_shell_view->priv->mail_shell_content); + e_shell_searchbar_set_search_option (searchbar, action); + e_mail_shell_view_update_search_filter (mail_shell_view); - /* This binding must come after e_mail_reader_init(). */ - e_binding_bind_property ( - shell_content, "group-by-threads", - mail_view, "group-by-threads", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); + /* Bind GObject properties for GSettings keys. */ settings = e_util_ref_settings ("org.gnome.evolution.mail"); + + g_settings_bind ( + settings, "show-deleted", + ACTION (MAIL_SHOW_DELETED), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + g_settings_bind ( + settings, "show-junk", + ACTION (MAIL_SHOW_JUNK), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + g_settings_bind ( + settings, "show-preview-toolbar", + ACTION (MAIL_SHOW_PREVIEW_TOOLBAR), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + action = ACTION (MAIL_VIEW_VERTICAL); + + g_settings_bind_with_mapping ( + settings, "layout", + action, "state", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY, + e_shell_view_util_layout_to_state_cb, + e_shell_view_util_state_to_layout_cb, NULL, NULL); + + g_signal_connect_object (action, "notify::state", + G_CALLBACK (e_mail_shell_view_mail_view_notify_cb), mail_shell_view, 0); + + /* to propagate the loaded state */ + e_mail_shell_view_mail_view_notify_cb (G_OBJECT (action), NULL, mail_shell_view); + + g_settings_bind ( + settings, "enable-unmatched", + ACTION (MAIL_VFOLDER_UNMATCHED_ENABLE), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + g_settings_bind ( + settings, "show-attachment-bar", + ACTION (MAIL_ATTACHMENT_BAR), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + + if (e_shell_window_is_main_instance (shell_window)) { + g_settings_bind ( + settings, "show-to-do-bar", + ACTION (MAIL_TO_DO_BAR), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + } else { + g_settings_bind ( + settings, "show-to-do-bar-sub", + ACTION (MAIL_TO_DO_BAR), "active", + G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY); + } + g_settings_bind ( settings, "vfolder-allow-expunge", mail_shell_view, "vfolder-allow-expunge", - G_SETTINGS_BIND_GET); + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY); + g_clear_object (&settings); /* Populate built-in rules for search entry popup menu. @@ -709,6 +697,8 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view) /* Now that we're all set up, simulate selecting a folder. */ g_signal_emit_by_name (selection, "changed"); + + e_ui_manager_thaw (ui_manager); } void @@ -735,6 +725,7 @@ e_mail_shell_view_private_dispose (EMailShellView *mail_shell_view) g_clear_object (&priv->mail_shell_backend); g_clear_object (&priv->mail_shell_content); g_clear_object (&priv->mail_shell_sidebar); + g_clear_object (&priv->send_receive_menu); for (ii = 0; ii < MAIL_NUM_SEARCH_RULES; ii++) g_clear_object (&priv->search_rules[ii]); @@ -884,15 +875,12 @@ e_mail_shell_view_update_sidebar (EMailShellView *mail_shell_view) /* If no folder is selected, reset the sidebar banners * to their default values and stop. */ if (folder == NULL) { - GtkAction *action; - gchar *label; + EUIAction *action; - action = e_shell_view_get_action (shell_view); + action = e_shell_view_get_switcher_action (shell_view); - g_object_get (action, "label", &label, NULL); e_shell_sidebar_set_secondary_text (shell_sidebar, NULL); - e_shell_view_set_title (shell_view, label); - g_free (label); + e_shell_view_set_title (shell_view, e_ui_action_get_label (action)); return; } @@ -1053,12 +1041,10 @@ e_mail_shell_view_update_sidebar (EMailShellView *mail_shell_view) } typedef struct { - GtkMenuShell *menu; + GMenu *section; CamelSession *session; EMailAccountStore *account_store; - - /* GtkMenuItem -> CamelService */ - GHashTable *menu_items; + EUIManager *ui_manager; /* Signal handlers */ gulong service_added_id; @@ -1118,38 +1104,63 @@ send_receive_can_use_service (EMailAccountStore *account_store, return enabled && !builtin; } -static GtkMenuItem * -send_receive_find_menu_item (SendReceiveData *data, - gpointer service) +static gint +send_receive_find_menu_index (SendReceiveData *data, + CamelService *service) { - GHashTableIter iter; - gpointer menu_item; - gpointer candidate; + GMenuModel *menu_model; + const gchar *uid; + const gchar *prefix = "mail-send-receive.mail-send-receive-service-"; + guint prefix_len = strlen (prefix); + gint ii, n_items; - g_hash_table_iter_init (&iter, data->menu_items); + menu_model = G_MENU_MODEL (data->section); + n_items = g_menu_model_get_n_items (menu_model); + uid = camel_service_get_uid (service); - while (g_hash_table_iter_next (&iter, &menu_item, &candidate)) - if (service == candidate) - return GTK_MENU_ITEM (menu_item); + for (ii = 0; ii < n_items; ii++) { + GVariant *attr; + const gchar *action_name_with_uid; - return NULL; + attr = g_menu_model_get_item_attribute_value (menu_model, ii, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING); + action_name_with_uid = attr ? g_variant_get_string (attr, NULL) : NULL; + + if (action_name_with_uid && + g_str_has_prefix (action_name_with_uid, prefix) && + g_strcmp0 (uid, action_name_with_uid + prefix_len) == 0) { + g_clear_pointer (&attr, g_variant_unref); + return ii; + } + + g_clear_pointer (&attr, g_variant_unref); + } + + return -1; } static void -send_receive_account_item_activate_cb (GtkMenuItem *menu_item, - SendReceiveData *data) +send_receive_service_activated_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + CamelSession *session = user_data; CamelService *service; + GVariant *state; + + state = g_action_get_state (G_ACTION (action)); + service = camel_session_ref_service (session, g_variant_get_string (state, NULL)); + g_clear_pointer (&state, g_variant_unref); - service = g_hash_table_lookup (data->menu_items, menu_item); g_return_if_fail (CAMEL_IS_SERVICE (service)); mail_receive_service (service); + + g_clear_object (&service); } typedef struct _EMenuItemSensitivityData { - GObject *service; - GtkWidget *menu_item; + EUIAction *action; + gboolean is_online; } EMenuItemSensitivityData; static void @@ -1160,8 +1171,7 @@ free_menu_item_sensitivity_data (gpointer ptr) if (!data) return; - g_object_unref (data->service); - g_object_unref (data->menu_item); + g_object_unref (data->action); g_slice_free (EMenuItemSensitivityData, data); } @@ -1169,30 +1179,31 @@ static gboolean update_menu_item_sensitivity_cb (gpointer user_data) { EMenuItemSensitivityData *data = user_data; - gboolean is_online = FALSE; g_return_val_if_fail (data != NULL, FALSE); - g_object_get (data->service, "online", &is_online, NULL); - - gtk_widget_set_sensitive (data->menu_item, is_online); + e_ui_action_set_sensitive (data->action, data->is_online); return FALSE; } static void -service_online_state_changed_cb (GObject *service, +service_online_state_changed_cb (GObject *object, GParamSpec *param, - GtkWidget *menu_item) + gpointer user_data) { + EUIAction *action = user_data; EMenuItemSensitivityData *data; + gboolean is_online = FALSE; - g_return_if_fail (G_IS_OBJECT (service)); - g_return_if_fail (GTK_IS_WIDGET (menu_item)); + g_return_if_fail (CAMEL_IS_SESSION (object) || CAMEL_IS_SERVICE (object)); + g_return_if_fail (E_IS_UI_ACTION (action)); + + g_object_get (object, "online", &is_online, NULL); data = g_slice_new0 (EMenuItemSensitivityData); - data->service = g_object_ref (service); - data->menu_item = g_object_ref (menu_item); + data->action = g_object_ref (action); + data->is_online = is_online; g_idle_add_full (G_PRIORITY_HIGH_IDLE, update_menu_item_sensitivity_cb, data, free_menu_item_sensitivity_data); } @@ -1202,68 +1213,75 @@ send_receive_add_to_menu (SendReceiveData *data, CamelService *service, gint position) { - GtkWidget *menu_item; CamelProvider *provider; + EUIAction *action; + GMenuItem *item; + gchar *action_name; - if (send_receive_find_menu_item (data, service) != NULL) + if (send_receive_find_menu_index (data, service) >= 0) return; provider = camel_service_get_provider (service); + action_name = g_strconcat ("mail-send-receive-service-", camel_service_get_uid (service), NULL); - menu_item = gtk_menu_item_new (); - gtk_widget_show (menu_item); + action = e_ui_action_new ("mail-send-receive", action_name, NULL); + e_ui_action_set_state (action, g_variant_new_string (camel_service_get_uid (service))); + + g_free (action_name); e_binding_bind_property ( service, "display-name", - menu_item, "label", + action, "label", G_BINDING_SYNC_CREATE); + g_signal_connect_object (action, "activate", + G_CALLBACK (send_receive_service_activated_cb), data->session, 0); + + e_ui_manager_add_action (data->ui_manager, "mail-send-receive", action, NULL, NULL, NULL); + + item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (data->ui_manager, item, action); + + if (position < 0) + g_menu_append_item (data->section, item); + else + g_menu_insert_item (data->section, position, item); + + g_clear_object (&item); + if (provider && (provider->flags & CAMEL_PROVIDER_IS_REMOTE) != 0) { gpointer object; + gboolean is_online = FALSE; if (CAMEL_IS_OFFLINE_STORE (service)) object = g_object_ref (service); else object = camel_service_ref_session (service); + g_object_get (object, "online", &is_online, NULL); + e_signal_connect_notify_object ( object, "notify::online", - G_CALLBACK (service_online_state_changed_cb), menu_item, + G_CALLBACK (service_online_state_changed_cb), action, 0); + e_ui_action_set_sensitive (action, is_online); + g_object_unref (object); } - g_hash_table_insert ( - data->menu_items, menu_item, - g_object_ref (service)); - - g_signal_connect ( - menu_item, "activate", - G_CALLBACK (send_receive_account_item_activate_cb), data); - - /* Position is with respect to the sorted list of CamelService-s, - * not menu item position. */ - if (position < 0) - gtk_menu_shell_append (data->menu, menu_item); - else - gtk_menu_shell_insert (data->menu, menu_item, position + 4); -} - -static void -send_receive_gather_services (gpointer menu_item, - gpointer service, - gpointer queue) -{ - g_queue_push_head (queue, service); + g_clear_object (&action); } static gint -sort_services_cb (gconstpointer service1, - gconstpointer service2, +sort_services_cb (gconstpointer pservice1, + gconstpointer pservice2, gpointer account_store) { - return e_mail_account_store_compare_services (account_store, CAMEL_SERVICE (service1), CAMEL_SERVICE (service2)); + CamelService *service1 = *((CamelService **) pservice1); + CamelService *service2 = *((CamelService **) pservice2); + + return e_mail_account_store_compare_services (account_store, service1, service2); } static void @@ -1271,20 +1289,49 @@ send_receive_menu_service_added_cb (EMailAccountStore *account_store, CamelService *service, SendReceiveData *data) { - GQueue *services; + EUIActionGroup *action_group; + GPtrArray *actions; + GPtrArray *services; + guint position = G_MAXUINT; if (!send_receive_can_use_service (account_store, service, NULL)) return; - services = g_queue_new (); + action_group = e_ui_manager_get_action_group (data->ui_manager, "mail-send-receive"); + actions = e_ui_action_group_list_actions (action_group); - g_queue_push_head (services, service); - g_hash_table_foreach (data->menu_items, send_receive_gather_services, services); - g_queue_sort (services, sort_services_cb, account_store); + services = g_ptr_array_new_full (1 + (actions ? actions->len : 0), g_object_unref); + g_ptr_array_add (services, g_object_ref (service)); - send_receive_add_to_menu (data, service, g_queue_index (services, service)); + if (actions) { + guint ii; - g_queue_free (services); + for (ii = 0; ii < actions->len; ii++) { + EUIAction *action = g_ptr_array_index (actions, ii); + GVariant *state; + + state = g_action_get_state (G_ACTION (action)); + if (state) { + CamelService *action_service; + + action_service = camel_session_ref_service (data->session, g_variant_get_string (state, NULL)); + if (action_service) + g_ptr_array_add (services, action_service); + + g_clear_pointer (&state, g_variant_unref); + } + } + } + + g_ptr_array_sort_with_data (services, sort_services_cb, account_store); + + if (!g_ptr_array_find (services, service, &position)) + position = -1; + + send_receive_add_to_menu (data, service, position); + + g_clear_pointer (&actions, g_ptr_array_unref); + g_clear_pointer (&services, g_ptr_array_unref); } static void @@ -1292,17 +1339,21 @@ send_receive_menu_service_removed_cb (EMailAccountStore *account_store, CamelService *service, SendReceiveData *data) { - GtkMenuItem *menu_item; + EUIActionGroup *action_group; + gint index; - menu_item = send_receive_find_menu_item (data, service); - if (menu_item == NULL) - return; + action_group = e_ui_manager_get_action_group (data->ui_manager, "mail"); + if (action_group) { + gchar *action_name; - g_hash_table_remove (data->menu_items, menu_item); + action_name = g_strconcat ("mail-send-receive-service-", camel_service_get_uid (service), NULL); + e_ui_action_group_remove_by_name (action_group, action_name); + g_free (action_name); + } - gtk_container_remove ( - GTK_CONTAINER (data->menu), - GTK_WIDGET (menu_item)); + index = send_receive_find_menu_index (data, service); + if (index >= 0) + g_menu_remove (data->section, index); } static void @@ -1313,17 +1364,16 @@ send_receive_data_free (SendReceiveData *data) g_signal_handler_disconnect (data->account_store, data->service_enabled_id); g_signal_handler_disconnect (data->account_store, data->service_disabled_id); - g_object_unref (data->session); - g_object_unref (data->account_store); - - g_hash_table_destroy (data->menu_items); + g_clear_object (&data->session); + g_clear_object (&data->account_store); + g_clear_object (&data->ui_manager); g_slice_free (SendReceiveData, data); } static SendReceiveData * send_receive_data_new (EMailShellView *mail_shell_view, - GtkWidget *menu) + GMenu *section) { SendReceiveData *data; EShellView *shell_view; @@ -1337,19 +1387,13 @@ send_receive_data_new (EMailShellView *mail_shell_view, backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); - account_store = e_mail_ui_session_get_account_store ( - E_MAIL_UI_SESSION (session)); + account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session)); data = g_slice_new0 (SendReceiveData); - data->menu = GTK_MENU_SHELL (menu); /* do not reference */ + data->section = section; /* do not reference */ data->session = CAMEL_SESSION (g_object_ref (session)); data->account_store = g_object_ref (account_store); - - data->menu_items = g_hash_table_new_full ( - (GHashFunc) g_direct_hash, - (GEqualFunc) g_direct_equal, - (GDestroyNotify) NULL, - (GDestroyNotify) g_object_unref); + data->ui_manager = g_object_ref (e_shell_view_get_ui_manager (shell_view)); data->service_added_id = g_signal_connect ( account_store, "service-added", @@ -1364,69 +1408,69 @@ send_receive_data_new (EMailShellView *mail_shell_view, account_store, "service-disabled", G_CALLBACK (send_receive_menu_service_removed_cb), data); - g_object_weak_ref ( - G_OBJECT (menu), (GWeakNotify) - send_receive_data_free, data); + g_object_weak_ref (G_OBJECT (shell_view), (GWeakNotify) send_receive_data_free, data); return data; } -static GtkWidget * -create_send_receive_submenu (EMailShellView *mail_shell_view) +void +e_mail_shell_view_fill_send_receive_menu (EMailShellView *self) { EShellView *shell_view; - EShellWindow *shell_window; EShellBackend *shell_backend; EMailAccountStore *account_store; EMailBackend *backend; EMailSession *session; - GtkWidget *menu; - GtkAccelGroup *accel_group; - GtkUIManager *ui_manager; - GtkAction *action; + EUIManager *ui_manager; + EUIAction *action; + EUIActionGroup *action_group; + GMenu *section; + GMenuItem *item; GtkTreeModel *model; GtkTreeIter iter; SendReceiveData *data; - g_return_val_if_fail (mail_shell_view != NULL, NULL); + g_return_if_fail (self != NULL); - shell_view = E_SHELL_VIEW (mail_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); + shell_view = E_SHELL_VIEW (self); shell_backend = e_shell_view_get_shell_backend (shell_view); + ui_manager = e_shell_view_get_ui_manager (shell_view); backend = E_MAIL_BACKEND (shell_backend); session = e_mail_backend_get_session (backend); account_store = e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session)); + action_group = e_ui_manager_get_action_group (ui_manager, "mail-send-receive"); - menu = gtk_menu_new (); - ui_manager = e_shell_window_get_ui_manager (shell_window); - accel_group = gtk_ui_manager_get_accel_group (ui_manager); + e_ui_manager_freeze (ui_manager); - action = e_shell_window_get_action (shell_window, "mail-send-receive"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); + g_menu_remove_all (self->priv->send_receive_menu); + e_ui_action_group_remove_all (action_group); - action = e_shell_window_get_action ( - shell_window, "mail-send-receive-receive-all"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); + section = g_menu_new (); - action = e_shell_window_get_action ( - shell_window, "mail-send-receive-send-all"); - gtk_action_set_accel_group (action, accel_group); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_action_create_menu_item (action)); + action = ACTION (MAIL_SEND_RECEIVE); + item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (ui_manager, item, action); + g_menu_append_item (section, item); + g_clear_object (&item); - gtk_menu_shell_append ( - GTK_MENU_SHELL (menu), - gtk_separator_menu_item_new ()); + action = ACTION (MAIL_SEND_RECEIVE_RECEIVE_ALL); + item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (ui_manager, item, action); + g_menu_append_item (section, item); + g_clear_object (&item); - data = send_receive_data_new (mail_shell_view, menu); + action = ACTION (MAIL_SEND_RECEIVE_SEND_ALL); + item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (ui_manager, item, action); + g_menu_append_item (section, item); + g_clear_object (&item); + + g_menu_append_section (self->priv->send_receive_menu, NULL, G_MENU_MODEL (section)); + g_clear_object (§ion); + + section = g_menu_new (); + data = send_receive_data_new (self, section); model = GTK_TREE_MODEL (account_store); if (gtk_tree_model_get_iter_first (model, &iter)) { @@ -1448,156 +1492,10 @@ create_send_receive_submenu (EMailShellView *mail_shell_view) } while (gtk_tree_model_iter_next (model, &iter)); } - gtk_widget_show_all (menu); + g_menu_append_section (self->priv->send_receive_menu, NULL, G_MENU_MODEL (section)); + g_clear_object (§ion); - return menu; -} - -void -e_mail_shell_view_update_send_receive_menus (EMailShellView *mail_shell_view) -{ - EMailShellContent *mail_shell_content; - EShellWindow *shell_window; - EShellView *shell_view; - EMailView *mail_view; - EShellHeaderBar *shell_headerbar = NULL; - GtkWidget *widget; - GtkAction *action; - const gchar *action_name; - const gchar *widget_path; - - g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view)); - - shell_view = E_SHELL_VIEW (mail_shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - widget = gtk_window_get_titlebar (GTK_WINDOW (shell_window)); - if (E_IS_SHELL_HEADER_BAR (widget)) - shell_headerbar = E_SHELL_HEADER_BAR (widget); - - if (shell_headerbar) - e_shell_header_bar_clear (shell_headerbar, "e-mail-shell-view"); - - if (!e_shell_view_is_active (shell_view)) { - if (mail_shell_view->priv->send_receive_tool_item) { - GtkWidget *toolbar; - - toolbar = e_shell_window_get_managed_widget ( - shell_window, "/main-toolbar"); - g_return_if_fail (toolbar != NULL); - - gtk_container_remove ( - GTK_CONTAINER (toolbar), - GTK_WIDGET (mail_shell_view->priv->send_receive_tool_item)); - gtk_container_remove ( - GTK_CONTAINER (toolbar), - GTK_WIDGET (mail_shell_view->priv->send_receive_tool_separator)); - - mail_shell_view->priv->send_receive_tool_item = NULL; - mail_shell_view->priv->send_receive_tool_separator = NULL; - } - return; - } - - mail_shell_content = mail_shell_view->priv->mail_shell_content; - mail_view = e_mail_shell_content_get_mail_view (mail_shell_content); - - widget_path = - "/main-menu/file-menu" - "/mail-send-receiver/mail-send-receive-submenu"; - widget = e_shell_window_get_managed_widget (shell_window, widget_path); - if (widget != NULL) - gtk_menu_item_set_submenu ( - GTK_MENU_ITEM (widget), - create_send_receive_submenu (mail_shell_view)); - - if (e_util_get_use_header_bar ()) { - widget = e_header_bar_button_new (_("Send / Receive"), ACTION (MAIL_SEND_RECEIVE)); - gtk_widget_set_name (widget, "e-mail-shell-view-send-receive"); - e_header_bar_button_take_menu ( - E_HEADER_BAR_BUTTON (widget), - create_send_receive_submenu (mail_shell_view)); - gtk_widget_show (widget); - - e_header_bar_pack_start (E_HEADER_BAR (shell_headerbar), widget, 2); - - action_name = "mail-forward"; - action = e_mail_reader_get_action (E_MAIL_READER (mail_view), action_name); - widget = e_header_bar_button_new (_("Forward"), action); - gtk_widget_set_name (widget, "e-mail-shell-view-forward"); - e_header_bar_button_take_menu ( - E_HEADER_BAR_BUTTON (widget), - e_mail_reader_create_forward_menu (E_MAIL_READER (mail_view))); - gtk_widget_show (widget); - - e_header_bar_pack_end (E_HEADER_BAR (shell_headerbar), widget, 3); - - action_name = "mail-reply-group"; - action = e_mail_reader_get_action (E_MAIL_READER (mail_view), action_name); - widget = e_header_bar_button_new (_("Group Reply"), action); - gtk_widget_set_name (widget, "e-mail-shell-view-reply-group"); - gtk_widget_show (widget); - - e_header_bar_button_take_menu ( - E_HEADER_BAR_BUTTON (widget), - e_mail_reader_create_reply_menu (E_MAIL_READER (mail_view))); - - e_header_bar_pack_end (E_HEADER_BAR (shell_headerbar), widget, 1); - - action_name = "mail-reply-sender"; - action = e_mail_reader_get_action (E_MAIL_READER (mail_view), action_name); - widget = e_header_bar_button_new (_("Reply"), action); - gtk_widget_set_name (widget, "e-mail-shell-view-reply-sender"); - gtk_widget_show (widget); - - e_header_bar_pack_end (E_HEADER_BAR (shell_headerbar), widget, 1); - - widget = e_shell_window_get_managed_widget (shell_window, "/main-toolbar/mail-toolbar-common/mail-reply-sender"); - if (widget) - gtk_widget_destroy (widget); - - widget = e_shell_window_get_managed_widget (shell_window, "/main-toolbar/mail-toolbar-common/toolbar-mail-forward-separator"); - if (widget) - gtk_widget_destroy (widget); - } else { - if (!mail_shell_view->priv->send_receive_tool_item) { - GtkWidget *toolbar; - GtkToolItem *tool_item; - gint index; - - toolbar = e_shell_window_get_managed_widget (shell_window, "/main-toolbar"); - g_return_if_fail (toolbar != NULL); - - widget_path = "/main-toolbar/toolbar-actions/mail-send-receiver"; - widget = e_shell_window_get_managed_widget (shell_window, widget_path); - g_return_if_fail (widget != NULL); - - index = gtk_toolbar_get_item_index ( - GTK_TOOLBAR (toolbar), GTK_TOOL_ITEM (widget)); - - tool_item = gtk_separator_tool_item_new (); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, index); - gtk_widget_show (GTK_WIDGET (tool_item)); - mail_shell_view->priv->send_receive_tool_separator = tool_item; - - tool_item = GTK_TOOL_ITEM ( - e_menu_tool_button_new (_("Send / Receive"))); - gtk_tool_item_set_is_important (tool_item, TRUE); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_item, index); - gtk_widget_show (GTK_WIDGET (tool_item)); - mail_shell_view->priv->send_receive_tool_item = tool_item; - - e_binding_bind_property ( - ACTION (MAIL_SEND_RECEIVE), "sensitive", - tool_item, "sensitive", - G_BINDING_SYNC_CREATE); - } - - if (mail_shell_view->priv->send_receive_tool_item) { - gtk_menu_tool_button_set_menu ( - GTK_MENU_TOOL_BUTTON (mail_shell_view->priv->send_receive_tool_item), - create_send_receive_submenu (mail_shell_view)); - } - } + e_ui_manager_thaw (ui_manager); } static void diff --git a/src/modules/mail/e-mail-shell-view-private.h b/src/modules/mail/e-mail-shell-view-private.h index 96335c5595..f8e335d735 100644 --- a/src/modules/mail/e-mail-shell-view-private.h +++ b/src/modules/mail/e-mail-shell-view-private.h @@ -26,8 +26,6 @@ #include #include /* for camel_search_word */ -#include "shell/e-shell-headerbar.h" - #include #include #include @@ -50,11 +48,9 @@ #include "e-mail-shell-sidebar.h" #include "e-mail-shell-view-actions.h" -/* Shorthand, requires a variable named "shell_window". */ +/* Shorthand, requires a variable named "shell_view". */ #define ACTION(name) \ - (E_SHELL_WINDOW_ACTION_##name (shell_window)) -#define ACTION_GROUP(name) \ - (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window)) + (E_SHELL_VIEW_ACTION_##name (shell_view)) /* ETable Specifications */ #define ETSPEC_FILENAME "message-list.etspec" @@ -113,9 +109,6 @@ struct _EMailShellViewPrivate { EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; - /* For UI merging and unmerging. */ - guint merge_id; - /* Filter rules correspond to the search entry menu. */ EFilterRule *search_rules[MAIL_NUM_SEARCH_RULES]; @@ -125,17 +118,17 @@ struct _EMailShellViewPrivate { /* For opening the selected folder. */ GCancellable *opening_folder; + GMenu *send_receive_menu; + /* Search folders for interactive search. */ CamelVeeFolder *search_folder_and_subfolders; CamelVeeFolder *search_account_all; CamelVeeFolder *search_account_current; GCancellable *search_account_cancel; - GtkToolItem *send_receive_tool_item; - GtkToolItem *send_receive_tool_separator; - gboolean vfolder_allow_expunge; gboolean ignore_folder_popup_selection_done; + gboolean web_view_accel_group_added; /* Selected UIDs for MAIL_FILTER_MESSAGE_THREAD filter */ GSList *selected_uids; @@ -154,14 +147,14 @@ void e_mail_shell_view_private_finalize void e_mail_shell_view_actions_init (EMailShellView *mail_shell_view); +void e_mail_shell_view_fill_send_receive_menu + (EMailShellView *self); void e_mail_shell_view_restore_state (EMailShellView *mail_shell_view); void e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view); void e_mail_shell_view_update_sidebar (EMailShellView *mail_shell_view); -void e_mail_shell_view_update_send_receive_menus - (EMailShellView *mail_shell_view); void e_mail_shell_view_rename_folder (EMailShellView *mail_shell_view); diff --git a/src/modules/mail/e-mail-shell-view.c b/src/modules/mail/e-mail-shell-view.c index 3d2bd4301f..7c24e8db17 100644 --- a/src/modules/mail/e-mail-shell-view.c +++ b/src/modules/mail/e-mail-shell-view.c @@ -20,6 +20,8 @@ #include "evolution-config.h" +#include "mail/e-mail-paned-view.h" + #include "e-mail-shell-view-private.h" enum { @@ -470,6 +472,38 @@ mail_shell_view_get_vfolder_allow_expunge (EMailShellView *mail_shell_view) return mail_shell_view->priv->vfolder_allow_expunge; } +static void +mail_shell_view_notify_active_view_cb (GObject *object, + GParamSpec *param, + gpointer user_data) +{ + EMailShellView *self = user_data; + EMailDisplay *mail_display; + EUIManager *ui_manager; + GtkAccelGroup *accel_group; + + mail_display = e_mail_reader_get_mail_display (E_MAIL_READER (e_mail_shell_content_get_mail_view (self->priv->mail_shell_content))); + if (!mail_display) + return; + + ui_manager = e_web_view_get_ui_manager (E_WEB_VIEW (mail_display)); + if (!ui_manager) + return; + + accel_group = e_ui_manager_get_accel_group (ui_manager); + + /* to enable attachment inline toggle actions' accels from the mail display (like "1") */ + if (e_shell_view_is_active (E_SHELL_VIEW (self))) { + if (!self->priv->web_view_accel_group_added) { + self->priv->web_view_accel_group_added = TRUE; + gtk_window_add_accel_group (GTK_WINDOW (object), accel_group); + } + } else if (self->priv->web_view_accel_group_added) { + self->priv->web_view_accel_group_added = FALSE; + gtk_window_remove_accel_group (GTK_WINDOW (object), accel_group); + } +} + static void mail_shell_view_set_property (GObject *object, guint property_id, @@ -526,45 +560,86 @@ mail_shell_view_finalize (GObject *object) static void mail_shell_view_constructed (GObject *object) { + EMailShellView *self = E_MAIL_SHELL_VIEW (object); + EShellView *shell_view = E_SHELL_VIEW (self); + EShellSearchbar *searchbar; + EMailView *mail_view; + EUIManager *ui_manager; + EActionComboBox *combo_box; + GObject *ui_item; + + ui_manager = e_shell_view_get_ui_manager (shell_view); + + e_ui_manager_freeze (ui_manager); + + self->priv->mail_shell_content = g_object_ref_sink (E_MAIL_SHELL_CONTENT (e_mail_shell_content_new (shell_view))); + /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_shell_view_parent_class)->constructed (object); e_mail_shell_view_private_constructed (E_MAIL_SHELL_VIEW (object)); e_mail_shell_view_cleanup_state_key_file (E_SHELL_VIEW (object)); -} -static void -mail_shell_view_toggled (EShellView *shell_view) -{ - EMailShellView *self = E_MAIL_SHELL_VIEW (shell_view); - EShellWindow *shell_window; - EMailReader *reader; - GtkUIManager *ui_manager; - const gchar *basename; - gboolean view_is_active; + mail_view = e_mail_shell_content_get_mail_view (self->priv->mail_shell_content); + searchbar = e_mail_shell_content_get_searchbar (self->priv->mail_shell_content); - shell_window = e_shell_view_get_shell_window (shell_view); - ui_manager = e_shell_window_get_ui_manager (shell_window); - view_is_active = e_shell_view_is_active (shell_view); - reader = E_MAIL_READER (e_mail_shell_content_get_mail_view (self->priv->mail_shell_content)); - basename = E_MAIL_READER_UI_DEFINITION; + combo_box = e_shell_searchbar_get_scope_combo_box (searchbar); + e_action_combo_box_set_action (combo_box, ACTION (MAIL_SCOPE_ALL_ACCOUNTS)); + e_shell_searchbar_set_scope_visible (searchbar, TRUE); - if (view_is_active && self->priv->merge_id == 0) { - self->priv->merge_id = e_load_ui_manager_definition (ui_manager, basename); + /* Advanced Search Action */ + e_shell_searchbar_set_search_option (searchbar, ACTION (MAIL_SEARCH_ADVANCED_HIDDEN)); - e_mail_reader_create_charset_menu (reader, ui_manager, self->priv->merge_id); + e_binding_bind_property ( + ACTION (MAIL_PREVIEW), "active", + mail_view, "preview-visible", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); - /* This also fills the Label menu */ - e_mail_reader_update_actions (reader, e_mail_reader_check_state (reader)); - } else if (!view_is_active && self->priv->merge_id != 0) { - e_mail_reader_remove_ui (reader); - gtk_ui_manager_remove_ui (ui_manager, self->priv->merge_id); - gtk_ui_manager_ensure_update (ui_manager); - self->priv->merge_id = 0; - } + e_binding_bind_property ( + ACTION (MAIL_SHOW_PREVIEW_TOOLBAR), "active", + mail_view, "preview-toolbar-visible", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); - /* Chain up to parent's toggled() method. */ - E_SHELL_VIEW_CLASS (e_mail_shell_view_parent_class)->toggled (shell_view); + e_binding_bind_property ( + ACTION (MAIL_SHOW_DELETED), "active", + mail_view, "show-deleted", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + ACTION (MAIL_SHOW_JUNK), "active", + mail_view, "show-junk", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + ACTION (MAIL_THREADS_GROUP_BY), "active", + mail_view, "group-by-threads", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + /* Keep the sensitivity of "Create Search Folder from Search" + * in sync with "Save Search" so that its only selectable when + * showing search results. */ + e_binding_bind_property ( + E_SHELL_VIEW_ACTION (shell_view, "search-save"), "sensitive", + ACTION (MAIL_CREATE_SEARCH_FOLDER), "sensitive", + G_BINDING_SYNC_CREATE); + + /* WebKitGTK does not support print preview, thus hide the option from the menu; + maybe it'll be supported in the future */ + e_ui_action_set_visible (ACTION (MAIL_PRINT_PREVIEW), FALSE); + + ui_item = e_ui_manager_create_item (ui_manager, "mail-preview-toolbar"); + e_util_setup_toolbar_icon_size (GTK_TOOLBAR (ui_item), GTK_ICON_SIZE_SMALL_TOOLBAR); + e_mail_paned_view_take_preview_toolbar (E_MAIL_PANED_VIEW (e_mail_shell_content_get_mail_view (self->priv->mail_shell_content)), GTK_WIDGET (ui_item)); + + e_ui_manager_thaw (ui_manager); + + e_signal_connect_notify_object (e_shell_view_get_shell_window (shell_view), "notify::active-view", + G_CALLBACK (mail_shell_view_notify_active_view_cb), self, 0); } static gchar * @@ -727,10 +802,9 @@ mail_shell_view_custom_search (EShellView *shell_view, if (custom_rule && custom_rule->threading == E_FILTER_THREAD_NONE && custom_rule->grouping == E_FILTER_GROUP_ANY && custom_rule->parts && custom_rule->parts->data) { - EShellWindow *shell_window = e_shell_view_get_shell_window (shell_view); EShellSearchbar *searchbar = E_SHELL_SEARCHBAR (e_shell_view_get_searchbar (shell_view)); EFilterPart *part = custom_rule->parts->data; - GtkAction *search_action = NULL; + EUIAction *search_action = NULL; gchar *search_text = NULL; if (!custom_rule->parts->next && g_list_length (part->elements) == 2) { @@ -863,7 +937,7 @@ mail_shell_view_custom_search (EShellView *shell_view, if (search_action && search_text) { e_shell_view_block_execute_search (shell_view); e_shell_view_set_search_rule (shell_view, NULL); - gtk_action_activate (search_action); + g_action_activate (G_ACTION (search_action), NULL); e_shell_searchbar_set_search_text (searchbar, search_text); e_shell_view_unblock_execute_search (shell_view); e_shell_view_execute_search (shell_view); @@ -884,7 +958,6 @@ mail_shell_view_execute_search (EShellView *shell_view) EMailShellView *self = E_MAIL_SHELL_VIEW (shell_view); EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; - EShellWindow *shell_window; EShellBackend *shell_backend; EShellContent *shell_content; EShellSidebar *shell_sidebar; @@ -902,8 +975,9 @@ mail_shell_view_execute_search (EShellView *shell_view) CamelFolder *folder; CamelService *service; CamelStore *store; - GtkAction *action; + EUIAction *action; EMailLabelListStore *label_store; + GVariant *state; GtkTreePath *path; GtkTreeIter tree_iter; GString *string; @@ -917,7 +991,6 @@ mail_shell_view_execute_search (EShellView *shell_view) const gchar *use_tag; gint value; - shell_window = e_shell_view_get_shell_window (shell_view); shell_backend = e_shell_view_get_shell_backend (shell_view); shell_content = e_shell_view_get_shell_content (shell_view); shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); @@ -941,7 +1014,9 @@ mail_shell_view_execute_search (EShellView *shell_view) E_MAIL_UI_SESSION (session)); action = ACTION (MAIL_SEARCH_SUBJECT_OR_ADDRESSES_CONTAIN); - value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); + state = g_action_get_state (G_ACTION (action)); + value = g_variant_get_int32 (state); + g_clear_pointer (&state, g_variant_unref); text = e_shell_searchbar_get_search_text (searchbar); if (value == MAIL_SEARCH_ADVANCED || text == NULL || *text == '\0') { @@ -1144,13 +1219,10 @@ filter: * the label list store. That's why we number * the label actions from zero. */ path = gtk_tree_path_new_from_indices (value, -1); - gtk_tree_model_get_iter ( - GTK_TREE_MODEL (label_store), - &tree_iter, path); + g_warn_if_fail (gtk_tree_model_get_iter (GTK_TREE_MODEL (label_store), &tree_iter, path)); gtk_tree_path_free (path); - tag = e_mail_label_list_store_get_tag ( - label_store, &tree_iter); + tag = e_mail_label_list_store_get_tag (label_store, &tree_iter); use_tag = tag; if (g_str_has_prefix (use_tag, "$Label")) use_tag += 6; @@ -1534,12 +1606,11 @@ mail_shell_view_update_actions (EShellView *shell_view) EMailShellContent *mail_shell_content; EMailShellSidebar *mail_shell_sidebar; EShellSidebar *shell_sidebar; - EShellWindow *shell_window; EMFolderTree *folder_tree; EMFolderTreeModel *model; EMailReader *reader; EMailView *mail_view; - GtkAction *action; + EUIAction *action; CamelStore *store = NULL; GList *list, *link; gchar *folder_name = NULL; @@ -1563,10 +1634,7 @@ mail_shell_view_update_actions (EShellView *shell_view) gboolean any_store_is_subscribable = FALSE; /* Chain up to parent's update_actions() method. */ - E_SHELL_VIEW_CLASS (e_mail_shell_view_parent_class)-> - update_actions (shell_view); - - shell_window = e_shell_view_get_shell_window (shell_view); + E_SHELL_VIEW_CLASS (e_mail_shell_view_parent_class)->update_actions (shell_view); mail_shell_view = E_MAIL_SHELL_VIEW (shell_view); mail_shell_content = mail_shell_view->priv->mail_shell_content; @@ -1645,100 +1713,186 @@ mail_shell_view_update_actions (EShellView *shell_view) action = ACTION (MAIL_ACCOUNT_DISABLE); sensitive = folder_is_store && store_can_be_disabled; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_ACCOUNT_EXPUNGE); sensitive = folder_is_trash; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_ACCOUNT_EMPTY_JUNK); sensitive = folder_is_junk; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_ACCOUNT_PROPERTIES); sensitive = folder_is_store && !store_is_builtin; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_ACCOUNT_REFRESH); sensitive = folder_is_store; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FLUSH_OUTBOX); sensitive = folder_is_outbox; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_COPY); sensitive = folder_is_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_DELETE); sensitive = folder_is_selected && folder_can_be_deleted; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_EDIT_SORT_ORDER); sensitive = folder_is_selected || folder_is_store; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_EXPUNGE); sensitive = folder_is_selected && (!folder_is_virtual || mail_shell_view->priv->vfolder_allow_expunge); - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_MOVE); sensitive = folder_is_selected && folder_can_be_deleted; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_NEW); sensitive = folder_allows_children; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (ACTION (MAIL_FOLDER_NEW_FULL), sensitive); action = ACTION (MAIL_FOLDER_PROPERTIES); sensitive = folder_is_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_REFRESH); sensitive = folder_is_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_RENAME); sensitive = folder_is_selected && folder_can_be_deleted; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_SELECT_THREAD); sensitive = folder_is_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_SELECT_SUBTHREAD); sensitive = folder_is_selected; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_UNSUBSCRIBE); sensitive = folder_is_selected && store_is_subscribable && !folder_is_virtual; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_FOLDER_MARK_ALL_AS_READ); sensitive = folder_is_selected && folder_has_unread; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_POPUP_FOLDER_MARK_ALL_AS_READ); sensitive = folder_is_selected && folder_has_unread_rec; - gtk_action_set_visible (action, sensitive); + e_ui_action_set_visible (action, sensitive); action = ACTION (MAIL_MANAGE_SUBSCRIPTIONS); sensitive = folder_is_store && store_is_subscribable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); action = ACTION (MAIL_TOOLS_SUBSCRIPTIONS); sensitive = any_store_is_subscribable; - gtk_action_set_sensitive (action, sensitive); + e_ui_action_set_sensitive (action, sensitive); /* folder_is_store + folder_is_virtual == "Search Folders" */ action = ACTION (MAIL_VFOLDER_UNMATCHED_ENABLE); - gtk_action_set_visible (action, folder_is_store && folder_is_virtual); + e_ui_action_set_visible (action, folder_is_store && folder_is_virtual); +} + +static gboolean +e_mail_shell_view_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EMailShellView *self = user_data; + const gchar *name; + + g_return_val_if_fail (E_IS_MAIL_SHELL_VIEW (self), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "EMailShellView::")) + return FALSE; + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (is_action ("EMailShellView::mail-send-receive")) { + *out_item = e_ui_manager_create_item_from_menu_model (ui_manager, elem, action, for_kind, G_MENU_MODEL (self->priv->send_receive_menu)); + } else if (for_kind == E_UI_ELEMENT_KIND_MENU) { + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + #undef is_action + + return TRUE; +} + +static gboolean +e_mail_shell_view_ui_manager_ignore_accel_cb (EUIManager *ui_manager, + EUIAction *action, + gpointer user_data) +{ + EMailShellView *self = user_data; + EMailView *mail_view; + EShellContent *shell_content; + + g_return_val_if_fail (E_IS_MAIL_SHELL_VIEW (self), FALSE); + + shell_content = e_shell_view_get_shell_content (E_SHELL_VIEW (self)); + mail_view = e_mail_shell_content_get_mail_view (E_MAIL_SHELL_CONTENT (shell_content)); + + return e_mail_reader_ignore_accel (E_MAIL_READER (mail_view)); +} + +static GtkWidget * +e_mail_shell_view_ref_shell_content (EShellView *shell_view) +{ + EMailShellView *self; + + g_return_val_if_fail (E_IS_MAIL_SHELL_VIEW (shell_view), NULL); + + self = E_MAIL_SHELL_VIEW (shell_view); + + return g_object_ref (GTK_WIDGET (self->priv->mail_shell_content)); +} + +static void +mail_shell_view_init_ui_data (EShellView *shell_view) +{ + EMailShellView *self; + + g_return_if_fail (E_IS_MAIL_SHELL_VIEW (shell_view)); + + self = E_MAIL_SHELL_VIEW (shell_view); + + g_signal_connect_object (e_shell_view_get_ui_manager (shell_view), "create-item", + G_CALLBACK (e_mail_shell_view_ui_manager_create_item_cb), shell_view, 0); + g_signal_connect_object (e_shell_view_get_ui_manager (shell_view), "ignore-accel", + G_CALLBACK (e_mail_shell_view_ui_manager_ignore_accel_cb), shell_view, 0); + + e_mail_reader_init_ui_data (E_MAIL_READER (e_mail_shell_content_get_mail_view (self->priv->mail_shell_content))); + e_mail_shell_view_actions_init (self); + e_mail_shell_view_fill_send_receive_menu (self); } static void @@ -1757,17 +1911,16 @@ e_mail_shell_view_class_init (EMailShellViewClass *class) shell_view_class = E_SHELL_VIEW_CLASS (class); shell_view_class->label = _("Mail"); shell_view_class->icon_name = "evolution-mail"; - shell_view_class->ui_definition = "evolution-mail.ui"; + shell_view_class->ui_definition = "evolution-mail.eui"; shell_view_class->ui_manager_id = "org.gnome.evolution.mail"; shell_view_class->search_context_type = EM_SEARCH_TYPE_CONTEXT; - shell_view_class->search_options = "/mail-search-options"; shell_view_class->search_rules = "searchtypes.xml"; - shell_view_class->new_shell_content = e_mail_shell_content_new; + shell_view_class->new_shell_content = e_mail_shell_view_ref_shell_content; shell_view_class->new_shell_sidebar = e_mail_shell_sidebar_new; - shell_view_class->toggled = mail_shell_view_toggled; shell_view_class->custom_search = mail_shell_view_custom_search; shell_view_class->execute_search = mail_shell_view_execute_search; shell_view_class->update_actions = mail_shell_view_update_actions; + shell_view_class->init_ui_data = mail_shell_view_init_ui_data; /* Ensure the GalView types we need are registered. */ g_type_ensure (GAL_TYPE_VIEW_ETABLE); diff --git a/src/modules/mail/em-composer-prefs.c b/src/modules/mail/em-composer-prefs.c index e1530a2fb2..e3bb7039fc 100644 --- a/src/modules/mail/em-composer-prefs.c +++ b/src/modules/mail/em-composer-prefs.c @@ -1595,7 +1595,6 @@ em_composer_prefs_construct (EMComposerPrefs *prefs, GSettings *settings; EActionComboBox *action_combo_box; ESourceRegistry *registry; - GtkRadioAction *radio_action; GtkTreeView *view; GtkListStore *store; GtkTreeSelection *selection; @@ -1645,10 +1644,9 @@ em_composer_prefs_construct (EMComposerPrefs *prefs, gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); widget = e_builder_get_widget (prefs->builder, "lblSendMode"); gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (action_combo_box)); - radio_action = e_action_combo_box_get_action (action_combo_box); g_settings_bind_with_mapping ( settings, "composer-mode", - radio_action, "current-value", + action_combo_box, "current-value", G_SETTINGS_BIND_DEFAULT, emcp_composer_mode_to_current_value_cb, emcp_current_value_to_composer_mode_cb, diff --git a/src/modules/mdn/evolution-mdn.c b/src/modules/mdn/evolution-mdn.c index 0e1cc7b519..f23e124d16 100644 --- a/src/modules/mdn/evolution-mdn.c +++ b/src/modules/mdn/evolution-mdn.c @@ -429,9 +429,12 @@ mdn_notify_sender (ESource *identity_source, } static void -mdn_notify_action_cb (GtkAction *action, - MdnContext *context) +mdn_notify_action_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + MdnContext *context = user_data; + mdn_notify_sender ( context->source, context->reader, @@ -523,7 +526,7 @@ mdn_message_loaded_cb (EMailReader *reader, if (response_policy == E_MDN_RESPONSE_POLICY_ASK) { MdnContext *context; - GtkAction *action; + EUIAction *action; gchar *tooltip; context = g_slice_new0 (MdnContext); @@ -542,10 +545,9 @@ mdn_message_loaded_cb (EMailReader *reader, _("Send a read receipt to “%s”"), context->notify_to); - action = gtk_action_new ( - "notify-sender", /* name doesn't matter */ - _("_Notify Sender"), - tooltip, NULL); + action = e_ui_action_new ("mdn-map", "notify-sender", NULL); + e_ui_action_set_label (action, _("_Notify Sender")); + e_ui_action_set_tooltip (action, tooltip); g_signal_connect_data ( action, "activate", diff --git a/src/modules/offline-alert/evolution-offline-alert.c b/src/modules/offline-alert/evolution-offline-alert.c index 395fbcca08..7e39e494e3 100644 --- a/src/modules/offline-alert/evolution-offline-alert.c +++ b/src/modules/offline-alert/evolution-offline-alert.c @@ -104,7 +104,7 @@ offline_alert_window_added_cb (GtkApplication *application, EOfflineAlert *extension) { EShell *shell = E_SHELL (application); - GtkAction *action; + EUIAction *action; const gchar *alert_id; if (!E_IS_SHELL_WINDOW (window)) diff --git a/src/modules/prefer-plain/e-mail-display-popup-prefer-plain.c b/src/modules/prefer-plain/e-mail-display-popup-prefer-plain.c index 7284e6381b..dc3321fc5e 100644 --- a/src/modules/prefer-plain/e-mail-display-popup-prefer-plain.c +++ b/src/modules/prefer-plain/e-mail-display-popup-prefer-plain.c @@ -20,6 +20,7 @@ #include #include #include "mail/e-mail-browser.h" +#include "mail/e-mail-reader.h" #include @@ -38,7 +39,7 @@ struct _EMailDisplayPopupPreferPlain { gchar *iframe_src; gchar *iframe_id; - GtkActionGroup *action_group; + EUIActionGroup *action_group; }; struct _EMailDisplayPopupPreferPlainClass { @@ -63,34 +64,12 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED ( E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION, e_mail_display_popup_extension_interface_init)); -static const gchar *ui_webview = -"" -" " -" " -" " -" " -" " -" " -" " -" " -""; - -static const gchar *ui_reader = -"" -" " -" " -" " -" " -" " -" " -" " -" " -""; - static void -toggle_part (GtkAction *action, - EMailDisplayPopupExtension *extension) +toggle_part (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailDisplayPopupExtension *extension = user_data; EMailDisplayPopupPreferPlain *pp_extension = (EMailDisplayPopupPreferPlain *) extension; GUri *guri; GHashTable *query; @@ -133,25 +112,6 @@ toggle_part (GtkAction *action, g_free (uri); } -GtkActionEntry entries[] = { - - { "show-plain-text-part", - NULL, - N_("Display plain text version"), - NULL, - N_("Display plain text version of multipart/alternative message"), - NULL - }, - - { "show-text-html-part", - NULL, - N_("Display HTML version"), - NULL, - N_("Display HTML version of multipart/alternative message"), - NULL - } -}; - const gint ID_LEN = G_N_ELEMENTS (".alternative-prefer-plain."); static void @@ -186,49 +146,81 @@ set_popup_place (EMailDisplayPopupPreferPlain *extension, } } -static GtkActionGroup * +static EUIActionGroup * create_group (EMailDisplayPopupExtension *extension) { + static const gchar *eui_webview = + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry entries[] = { + + { "show-plain-text-part", + NULL, + N_("Display plain text version"), + NULL, + N_("Display plain text version of multipart/alternative message"), + toggle_part, NULL, NULL, NULL }, + + { "show-text-html-part", + NULL, + N_("Display HTML version"), + NULL, + N_("Display HTML version of multipart/alternative message"), + toggle_part, NULL, NULL, NULL } + }; + EExtensible *extensible; EWebView *web_view; - GtkUIManager *ui_manager; - GtkActionGroup *group; - GtkAction *action; - EShell *shell; - GtkWindow *shell_window; + EMailReader *mail_reader; + EUIManager *ui_manager; + EUIActionGroup *group; extensible = e_extension_get_extensible (E_EXTENSION (extension)); web_view = E_WEB_VIEW (extensible); - - shell = e_shell_get_default (); - shell_window = e_shell_get_active_window (shell); - if (E_IS_SHELL_WINDOW (shell_window)) { - ui_manager = e_shell_window_get_ui_manager (E_SHELL_WINDOW (shell_window)); - } else if (E_IS_MAIL_BROWSER (shell_window)) { - ui_manager = e_mail_browser_get_ui_manager (E_MAIL_BROWSER (shell_window)); - } else { - return NULL; - } - - group = gtk_action_group_new ("prefer-plain"); - gtk_action_group_add_actions (group, entries, G_N_ELEMENTS (entries), NULL); - - gtk_ui_manager_insert_action_group (ui_manager, group, 0); - gtk_ui_manager_add_ui_from_string (ui_manager, ui_reader, -1, NULL); - ui_manager = e_web_view_get_ui_manager (web_view); - gtk_ui_manager_insert_action_group (ui_manager, group, 0); - gtk_ui_manager_add_ui_from_string (ui_manager, ui_webview, -1, NULL); + g_return_val_if_fail (ui_manager != NULL, NULL); - action = gtk_action_group_get_action (group, "show-plain-text-part"); - g_signal_connect ( - action, "activate", - G_CALLBACK (toggle_part), extension); + e_ui_manager_add_actions_with_eui_data (ui_manager, "prefer-plain", NULL, + entries, G_N_ELEMENTS (entries), extension, eui_webview); - action = gtk_action_group_get_action (group, "show-text-html-part"); - g_signal_connect ( - action, "activate", - G_CALLBACK (toggle_part), extension); + group = e_ui_manager_get_action_group (ui_manager, "prefer-plain"); + + mail_reader = e_mail_display_ref_mail_reader (E_MAIL_DISPLAY (web_view)); + if (mail_reader) { + static const gchar *eui_reader = + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + GError *local_error = NULL; + + /* share the group with the reader */ + ui_manager = e_mail_reader_get_ui_manager (mail_reader); + + e_ui_manager_add_action_group (ui_manager, group); + + if (!e_ui_parser_merge_data (e_ui_manager_get_parser (ui_manager), eui_reader, -1, &local_error)) + g_critical ("%s: Failed to merge built-in UI definition: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error"); + + g_clear_error (&local_error); + g_clear_object (&mail_reader); + } return group; } @@ -240,7 +232,7 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte { EMailDisplay *display; EMailDisplayPopupPreferPlain *pp_extension; - GtkAction *action; + EUIAction *action; gchar *part_id, *pos, *prefix; GUri *guri; GHashTable *query; @@ -269,7 +261,7 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte guri = NULL; if (!guri || !g_uri_get_query (guri)) { - gtk_action_group_set_visible (pp_extension->action_group, FALSE); + e_ui_action_group_set_visible (pp_extension->action_group, FALSE); if (guri) g_uri_unref (guri); return; @@ -278,19 +270,19 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte query = soup_form_decode (g_uri_get_query (guri)); part_id = g_hash_table_lookup (query, "part_id"); if (part_id == NULL) { - gtk_action_group_set_visible (pp_extension->action_group, FALSE); + e_ui_action_group_set_visible (pp_extension->action_group, FALSE); goto out; } pos = strstr (part_id, ".alternative-prefer-plain."); if (!pos) { - gtk_action_group_set_visible (pp_extension->action_group, FALSE); + e_ui_action_group_set_visible (pp_extension->action_group, FALSE); goto out; } /* Don't display the actions on any other than text/plain or text/html parts */ if (!strstr (pos, "plain_text") && !strstr (pos, "text_html")) { - gtk_action_group_set_visible (pp_extension->action_group, FALSE); + e_ui_action_group_set_visible (pp_extension->action_group, FALSE); goto out; } @@ -299,13 +291,11 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte /* It is! Hide the menu action */ if (is_text_plain) { - action = gtk_action_group_get_action ( - pp_extension->action_group, "show-plain-text-part"); - gtk_action_set_visible (action, FALSE); + action = e_ui_action_group_get_action (pp_extension->action_group, "show-plain-text-part"); + e_ui_action_set_visible (action, FALSE); } else { - action = gtk_action_group_get_action ( - pp_extension->action_group, "show-text-html-part"); - gtk_action_set_visible (action, FALSE); + action = e_ui_action_group_get_action (pp_extension->action_group, "show-text-html-part"); + e_ui_action_set_visible (action, FALSE); } /* Now check whether HTML version exists, if it does enable the action */ @@ -350,12 +340,11 @@ mail_display_popup_prefer_plain_update_actions (EMailDisplayPopupExtension *exte g_object_unref (g_queue_pop_head (&queue)); if (action_name) { - action = gtk_action_group_get_action ( - pp_extension->action_group, action_name); - gtk_action_group_set_visible (pp_extension->action_group, TRUE); - gtk_action_set_visible (action, TRUE); + action = e_ui_action_group_get_action (pp_extension->action_group, action_name); + e_ui_action_group_set_visible (pp_extension->action_group, TRUE); + e_ui_action_set_visible (action, TRUE); } else { - gtk_action_group_set_visible (pp_extension->action_group, FALSE); + e_ui_action_group_set_visible (pp_extension->action_group, FALSE); } g_free (prefix); diff --git a/src/modules/rss/evolution/e-rss-shell-view-extension.c b/src/modules/rss/evolution/e-rss-shell-view-extension.c index 948bd4eb61..71e7d63592 100644 --- a/src/modules/rss/evolution/e-rss-shell-view-extension.c +++ b/src/modules/rss/evolution/e-rss-shell-view-extension.c @@ -10,6 +10,7 @@ #include #include "mail/e-mail-reader-utils.h" +#include "mail/e-mail-view.h" #include "mail/em-folder-tree.h" #include "shell/e-shell-content.h" #include "shell/e-shell-view.h" @@ -19,21 +20,12 @@ #include "module-rss.h" -static const gchar *mail_ui_def = - "\n" - " \n" - " \n" - " \n" - "\n"; - #define E_TYPE_RSS_SHELL_VIEW_EXTENSION (e_rss_shell_view_extension_get_type ()) GType e_rss_shell_view_extension_get_type (void); typedef struct _ERssShellViewExtension { EExtension parent; - guint current_ui_id; - gboolean actions_added; } ERssShellViewExtension; typedef struct _ERssShellViewExtensionClass { @@ -97,11 +89,15 @@ e_rss_mail_folder_reload_got_folder_cb (GObject *source_object, if (folder) { EShellContent *shell_content; + EMailView *mail_view = NULL; shell_content = e_shell_view_get_shell_content (shell_view); + g_object_get (shell_content, "mail-view", &mail_view, NULL); - e_mail_reader_refresh_folder (E_MAIL_READER (shell_content), folder); + if (mail_view) + e_mail_reader_refresh_folder (E_MAIL_READER (mail_view), folder); + g_clear_object (&mail_view); g_object_unref (folder); } else { g_warning ("%s: Failed to get folder: %s", G_STRFUNC, error ? error->message : "Unknown error"); @@ -109,9 +105,11 @@ e_rss_mail_folder_reload_got_folder_cb (GObject *source_object, } static void -action_rss_mail_folder_reload_cb (GtkAction *action, - EShellView *shell_view) +action_rss_mail_folder_reload_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; CamelStore *store = NULL; CamelRssStoreSummary *store_summary = NULL; gchar *folder_path = NULL; @@ -136,34 +134,27 @@ action_rss_mail_folder_reload_cb (GtkAction *action, } static void -e_rss_shell_view_update_actions_cb (EShellView *shell_view, - GtkActionEntry *entries) +e_rss_shell_view_update_actions_cb (EShellView *shell_view) { CamelStore *store = NULL; - EShellWindow *shell_window; - GtkActionGroup *action_group; - GtkAction *action; - GtkUIManager *ui_manager; + EUIAction *action; gboolean is_rss_folder = FALSE; is_rss_folder = e_rss_check_rss_folder_selected (shell_view, &store, NULL); - shell_window = e_shell_view_get_shell_window (shell_view); - ui_manager = e_shell_window_get_ui_manager (shell_window); - action_group = e_lookup_action_group (ui_manager, "mail"); - action = gtk_action_group_get_action (action_group, "e-rss-mail-folder-reload-action"); + action = e_shell_view_get_action (shell_view, "e-rss-mail-folder-reload-action"); if (action) { - gtk_action_set_visible (action, is_rss_folder); + e_ui_action_set_visible (action, is_rss_folder); if (store) { CamelSession *session; session = camel_service_ref_session (CAMEL_SERVICE (store)); - gtk_action_set_sensitive (action, session && camel_session_get_online (session)); + e_ui_action_set_sensitive (action, session && camel_session_get_online (session)); g_clear_object (&session); } else { - gtk_action_set_sensitive (action, FALSE); + e_ui_action_set_sensitive (action, FALSE); } } @@ -171,82 +162,43 @@ e_rss_shell_view_update_actions_cb (EShellView *shell_view, } static void -e_rss_shell_view_toggled_cb (EShellView *shell_view, - ERssShellViewExtension *extension) +e_rss_shell_view_extension_constructed (GObject *object) { EShellViewClass *shell_view_class; - EShellWindow *shell_window; - GtkUIManager *ui_manager; - gboolean is_active, need_update; - GError *error = NULL; + EShellView *shell_view; - g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); - g_return_if_fail (extension != NULL); + /* Chain up to parent's method */ + G_OBJECT_CLASS (e_rss_shell_view_extension_parent_class)->constructed (object); + shell_view = E_SHELL_VIEW (e_extension_get_extensible (E_EXTENSION (object))); shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view); g_return_if_fail (shell_view_class != NULL); - shell_window = e_shell_view_get_shell_window (shell_view); - ui_manager = e_shell_window_get_ui_manager (shell_window); + if (g_strcmp0 (shell_view_class->ui_manager_id, "org.gnome.evolution.mail") == 0) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + ""; - need_update = extension->current_ui_id != 0; - - if (extension->current_ui_id) { - gtk_ui_manager_remove_ui (ui_manager, extension->current_ui_id); - extension->current_ui_id = 0; - } - - is_active = e_shell_view_is_active (shell_view); - - if (!is_active || g_strcmp0 (shell_view_class->ui_manager_id, "org.gnome.evolution.mail") != 0) { - if (need_update) - gtk_ui_manager_ensure_update (ui_manager); - - return; - } - - if (!extension->actions_added) { - GtkActionEntry mail_folder_context_entries[] = { + static const EUIActionEntry entries[] = { { "e-rss-mail-folder-reload-action", NULL, N_("Re_load feed articles"), NULL, N_("Reload all feed articles from the server, updating existing and adding any missing"), - G_CALLBACK (action_rss_mail_folder_reload_cb) } + action_rss_mail_folder_reload_cb, NULL, NULL, NULL } }; - GtkActionGroup *action_group; - - action_group = e_shell_window_get_action_group (shell_window, "mail"); - - e_action_group_add_actions_localized ( - action_group, GETTEXT_PACKAGE, - mail_folder_context_entries, G_N_ELEMENTS (mail_folder_context_entries), shell_view); + e_ui_manager_add_actions_with_eui_data (e_shell_view_get_ui_manager (shell_view), "mail", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), shell_view, eui); g_signal_connect (shell_view, "update-actions", G_CALLBACK (e_rss_shell_view_update_actions_cb), NULL); - - extension->actions_added = TRUE; } - - extension->current_ui_id = gtk_ui_manager_add_ui_from_string (ui_manager, mail_ui_def, -1, &error); - - if (error) { - g_warning ("%s: Failed to add ui definition: %s", G_STRFUNC, error->message); - g_error_free (error); - } - - gtk_ui_manager_ensure_update (ui_manager); -} - -static void -e_rss_shell_view_extension_constructed (GObject *object) -{ - /* Chain up to parent's method */ - G_OBJECT_CLASS (e_rss_shell_view_extension_parent_class)->constructed (object); - - g_signal_connect_object (e_extension_get_extensible (E_EXTENSION (object)), "toggled", - G_CALLBACK (e_rss_shell_view_toggled_cb), object, 0); } static void diff --git a/src/modules/settings/e-settings-mail-reader.c b/src/modules/settings/e-settings-mail-reader.c index fc78e8725f..d4f4efafbf 100644 --- a/src/modules/settings/e-settings-mail-reader.c +++ b/src/modules/settings/e-settings-mail-reader.c @@ -33,7 +33,8 @@ static gboolean settings_mail_reader_idle_cb (EExtension *extension) { EExtensible *extensible; - GtkActionGroup *action_group; + EUIManager *ui_manager; + EUIActionGroup *action_group; ESourceRegistry *registry; GSettings *settings; ESource *source; @@ -67,9 +68,8 @@ settings_mail_reader_idle_cb (EExtension *extension) g_object_unref (settings); - action_group = e_mail_reader_get_action_group ( - E_MAIL_READER (extensible), - E_MAIL_READER_ACTION_GROUP_SEARCH_FOLDERS); + ui_manager = e_mail_reader_get_ui_manager (E_MAIL_READER (extensible)); + action_group = e_ui_manager_get_action_group (ui_manager, "search-folders"); shell = e_shell_get_default (); registry = e_shell_get_registry (shell); diff --git a/src/modules/text-highlight/e-mail-display-popup-text-highlight.c b/src/modules/text-highlight/e-mail-display-popup-text-highlight.c index 656fd5a00a..93f8ee68e6 100644 --- a/src/modules/text-highlight/e-mail-display-popup-text-highlight.c +++ b/src/modules/text-highlight/e-mail-display-popup-text-highlight.c @@ -20,6 +20,7 @@ #include #include #include "mail/e-mail-browser.h" +#include "mail/e-mail-reader.h" #include @@ -32,9 +33,13 @@ typedef struct _EMailDisplayPopupTextHighlight { EExtension parent; - GtkActionGroup *action_group; + EUIAction *menu_action_webview; + EUIAction *item_action_webview; + EUIAction *menu_action_reader; + EUIAction *item_action_reader; + GMenu *menu; - volatile gint updating; + gint updating; gchar *iframe_src; gchar *iframe_id; } EMailDisplayPopupTextHighlight; @@ -59,53 +64,6 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED ( E_TYPE_MAIL_DISPLAY_POPUP_EXTENSION, e_mail_display_popup_extension_interface_init)); -static const gchar *ui = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; - -static const gchar *ui_reader = -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -""; - -static GtkActionEntry entries[] = { - - { "format-as-menu", - NULL, - N_("_Format as…"), - NULL, - NULL, - NULL - }, - - { "format-as-other-menu", - NULL, - N_("_Other languages"), - NULL, - NULL, - NULL - } -}; - static void set_popup_place (EMailDisplayPopupTextHighlight *extension, const gchar *iframe_src, @@ -123,22 +81,22 @@ set_popup_place (EMailDisplayPopupTextHighlight *extension, } static void -reformat (GtkAction *old, - GtkAction *action, - gpointer user_data) +text_hightlight_format_as_menu_item_set_state_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - EMailDisplayPopupTextHighlight *th_extension; + EMailDisplayPopupTextHighlight *self = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (user_data); GUri *guri; GHashTable *query; gchar *uri, *query_str; - th_extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (user_data); + e_ui_action_set_state (action, parameter); - if (g_atomic_int_get (&th_extension->updating)) + if (g_atomic_int_get (&self->updating)) return; - if (th_extension->iframe_src) - guri = g_uri_parse (th_extension->iframe_src, SOUP_HTTP_URI_FLAGS | G_URI_FLAGS_PARSE_RELAXED, NULL); + if (self->iframe_src) + guri = g_uri_parse (self->iframe_src, SOUP_HTTP_URI_FLAGS | G_URI_FLAGS_PARSE_RELAXED, NULL); else guri = NULL; @@ -151,15 +109,12 @@ reformat (GtkAction *old, } query = soup_form_decode (g_uri_get_query (guri)); - g_hash_table_replace ( - query, g_strdup ("__formatas"), (gpointer) gtk_action_get_name (action)); - g_hash_table_replace ( - query, g_strdup ("mime_type"), (gpointer) "text/plain"); - g_hash_table_replace ( - query, g_strdup ("__force_highlight"), (gpointer) "true"); + g_hash_table_replace (query, g_strdup ("__formatas"), (gpointer) g_variant_get_string (parameter, NULL)); + g_hash_table_replace (query, g_strdup ("mime_type"), (gpointer) "text/plain"); + g_hash_table_replace (query, g_strdup ("__force_highlight"), (gpointer) "true"); #ifdef HAVE_MARKDOWN - if (g_strcmp0 (gtk_action_get_name (action), "markdown") == 0) { + if (g_strcmp0 (g_variant_get_string (parameter, NULL), "markdown") == 0) { g_hash_table_remove (query, "__formatas"); g_hash_table_remove (query, "__force_highlight"); g_hash_table_replace (query, g_strdup ("mime_type"), (gpointer) "text/markdown"); @@ -174,124 +129,123 @@ reformat (GtkAction *old, uri = g_uri_to_string_partial (guri, G_URI_HIDE_PASSWORD); g_uri_unref (guri); - e_web_view_set_iframe_src (E_WEB_VIEW (e_extension_get_extensible (E_EXTENSION (th_extension))), - th_extension->iframe_id, uri); + e_web_view_set_iframe_src (E_WEB_VIEW (e_extension_get_extensible (E_EXTENSION (self))), + self->iframe_id, uri); g_free (uri); } -static GtkActionGroup * -create_group (EMailDisplayPopupExtension *extension) +static gboolean +text_highlight_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) { + GMenuModel *format_as_menu = user_data; + const gchar *name; + + g_return_val_if_fail (G_IS_MENU (format_as_menu), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "EPluginTextHighlight::")) + return FALSE; + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (is_action ("EPluginTextHighlight::format-as-menu")) { + *out_item = e_ui_manager_create_item_from_menu_model (ui_manager, elem, action, for_kind, format_as_menu); + } else if (for_kind == E_UI_ELEMENT_KIND_MENU) { + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + #undef is_action + + return TRUE; +} + +static void +create_actions (EMailDisplayPopupExtension *extension) +{ + static const gchar *eui_webview = + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry entries[] = { + { "format-as-menu-item", + NULL, + N_("_Format as…"), + NULL, + NULL, + NULL, "s", "'txt'", text_hightlight_format_as_menu_item_set_state_cb }, + + { "EPluginTextHighlight::format-as-menu", NULL, N_("_Format as…"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + + EMailDisplayPopupTextHighlight *self = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (extension); EExtensible *extensible; + EUIManager *ui_manager; + EUIActionGroup *group; EWebView *web_view; - GtkUIManager *ui_manager, *shell_ui_manager; - GtkActionGroup *group; - EShell *shell; - GtkWindow *shell_window; - gint i; - gsize len; - guint merge_id, shell_merge_id; - Language *languages; - GSList *radio_group; - gint action_index; + EMailReader *mail_reader; extensible = e_extension_get_extensible (E_EXTENSION (extension)); web_view = E_WEB_VIEW (extensible); - ui_manager = e_web_view_get_ui_manager (web_view); - shell = e_shell_get_default (); - shell_window = e_shell_get_active_window (shell); - if (E_IS_SHELL_WINDOW (shell_window)) { - shell_ui_manager = e_shell_window_get_ui_manager (E_SHELL_WINDOW (shell_window)); - } else if (E_IS_MAIL_BROWSER (shell_window)) { - shell_ui_manager = e_mail_browser_get_ui_manager (E_MAIL_BROWSER (shell_window)); - } else { - return NULL; + g_return_if_fail (ui_manager != NULL); + + g_signal_connect_data (ui_manager, "create-item", + G_CALLBACK (text_highlight_ui_manager_create_item_cb), g_object_ref (self->menu), + (GClosureNotify) g_object_unref, 0); + + e_ui_manager_add_actions_with_eui_data (ui_manager, "EPluginTextHighlight", NULL, + entries, G_N_ELEMENTS (entries), extension, eui_webview); + + group = e_ui_manager_get_action_group (ui_manager, "EPluginTextHighlight"); + self->menu_action_webview = g_object_ref (e_ui_action_group_get_action (group, "EPluginTextHighlight::format-as-menu")); + self->item_action_webview = g_object_ref (e_ui_action_group_get_action (group, "format-as-menu-item")); + + mail_reader = e_mail_display_ref_mail_reader (E_MAIL_DISPLAY (web_view)); + if (mail_reader) { + static const gchar *eui_reader = + "" + "" + "" + "" + "" + "" + "" + ""; + + ui_manager = e_mail_reader_get_ui_manager (mail_reader); + + g_signal_connect_data (ui_manager, "create-item", + G_CALLBACK (text_highlight_ui_manager_create_item_cb), g_object_ref (self->menu), + (GClosureNotify) g_object_unref, 0); + + e_ui_manager_add_actions_with_eui_data (ui_manager, "EPluginTextHighlight", NULL, + entries, G_N_ELEMENTS (entries), extension, eui_reader); + + group = e_ui_manager_get_action_group (ui_manager, "EPluginTextHighlight"); + self->menu_action_reader = g_object_ref (e_ui_action_group_get_action (group, "EPluginTextHighlight::format-as-menu")); + self->item_action_reader = g_object_ref (e_ui_action_group_get_action (group, "format-as-menu-item")); + + g_clear_object (&mail_reader); } - - group = gtk_action_group_new ("format-as"); - gtk_action_group_add_actions (group, entries, G_N_ELEMENTS (entries), NULL); - - gtk_ui_manager_insert_action_group (ui_manager, group, 0); - gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, NULL); - - gtk_ui_manager_insert_action_group (shell_ui_manager, group, 0); - gtk_ui_manager_add_ui_from_string (shell_ui_manager, ui_reader, -1, NULL); - - merge_id = gtk_ui_manager_new_merge_id (ui_manager); - shell_merge_id = gtk_ui_manager_new_merge_id (shell_ui_manager); - - languages = get_default_langauges (&len); - radio_group = NULL; - action_index = 0; - for (i = 0; i < len; i++) { - - GtkRadioAction *action; - action = gtk_radio_action_new ( - languages[i].action_name, - languages[i].action_label, - NULL, NULL, action_index); - action_index++; - gtk_action_group_add_action (group, GTK_ACTION (action)); - if (radio_group) - gtk_radio_action_set_group (action, radio_group); - else - g_signal_connect ( - action, "changed", - G_CALLBACK (reformat), extension); - radio_group = gtk_radio_action_get_group (action); - - g_object_unref (action); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, - "/context/custom-actions-2/format-as-menu/format-as-actions", - languages[i].action_name, languages[i].action_name, - GTK_UI_MANAGER_AUTO, FALSE); - - gtk_ui_manager_add_ui ( - shell_ui_manager, shell_merge_id, - "/mail-preview-popup/mail-preview-popup-actions/format-as-menu/format-as-actions", - languages[i].action_name, languages[i].action_name, - GTK_UI_MANAGER_AUTO, FALSE); - } - - languages = get_additinal_languages (&len); - for (i = 0; i < len; i++) { - GtkRadioAction *action; - - action = gtk_radio_action_new ( - languages[i].action_name, - languages[i].action_label, - NULL, NULL, action_index); - action_index++; - gtk_action_group_add_action (group, GTK_ACTION (action)); - - if (radio_group) - gtk_radio_action_set_group (action, radio_group); - else - g_signal_connect ( - action, "changed", - G_CALLBACK (reformat), extension); - radio_group = gtk_radio_action_get_group (action); - - g_object_unref (action); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, - "/context/custom-actions-2/format-as-menu/format-as-other-menu", - languages[i].action_name, languages[i].action_name, - GTK_UI_MANAGER_AUTO, FALSE); - - gtk_ui_manager_add_ui ( - shell_ui_manager, shell_merge_id, - "/mail-preview-popup/mail-preview-popup-actions/format-as-menu/format-as-other-menu", - languages[i].action_name, languages[i].action_name, - GTK_UI_MANAGER_AUTO, FALSE); - } - - return group; } static gboolean @@ -316,9 +270,9 @@ update_actions (EMailDisplayPopupExtension *extension, th_extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (extension); - if (!th_extension->action_group) { - th_extension->action_group = create_group (extension); - if (!th_extension->action_group) + if (!th_extension->menu_action_webview) { + create_actions (extension); + if (!th_extension->menu_action_webview) return; } @@ -328,9 +282,12 @@ update_actions (EMailDisplayPopupExtension *extension, * then try to check what formatter it's using at the moment and set * it as active in the popup menu */ if (th_extension->iframe_src && strstr (th_extension->iframe_src, ".text-highlight") != NULL) { + GVariant *state = NULL; GUri *guri; - gtk_action_group_set_visible ( - th_extension->action_group, TRUE); + + e_ui_action_set_visible (th_extension->menu_action_webview, TRUE); + if (th_extension->menu_action_reader) + e_ui_action_set_visible (th_extension->menu_action_reader, TRUE); guri = g_uri_parse (th_extension->iframe_src, SOUP_HTTP_URI_FLAGS | G_URI_FLAGS_PARSE_RELAXED, NULL); if (guri && g_uri_get_query (guri)) { @@ -344,27 +301,29 @@ update_actions (EMailDisplayPopupExtension *extension, highlighter = g_hash_table_lookup (query, "__formatas"); } - if (highlighter && *highlighter) { - GtkAction *action = gtk_action_group_get_action ( - th_extension->action_group, highlighter); - if (action) { - gint value; - g_atomic_int_add (&th_extension->updating, 1); - g_object_get ( - G_OBJECT (action), "value", - &value, NULL); - gtk_radio_action_set_current_value ( - GTK_RADIO_ACTION (action), value); - g_atomic_int_add (&th_extension->updating, -1); - } - } + if (highlighter && *highlighter) + state = g_variant_new_string (highlighter); + g_hash_table_destroy (query); } if (guri) g_uri_unref (guri); + + if (!state) + state = g_variant_new_string ("txt"); + + g_variant_ref_sink (state); + g_atomic_int_add (&th_extension->updating, 1); + e_ui_action_set_state (th_extension->item_action_webview, state); + if (th_extension->item_action_reader) + e_ui_action_set_state (th_extension->item_action_reader, state); + g_atomic_int_add (&th_extension->updating, -1); + g_variant_unref (state); } else { - gtk_action_group_set_visible (th_extension->action_group, FALSE); + e_ui_action_set_visible (th_extension->menu_action_webview, FALSE); + if (th_extension->menu_action_reader) + e_ui_action_set_visible (th_extension->menu_action_reader, FALSE); } } @@ -375,7 +334,11 @@ e_mail_display_popup_text_highlight_finalize (GObject *object) extension = E_MAIL_DISPLAY_POPUP_TEXT_HIGHLIGHT (object); - g_clear_object (&extension->action_group); + g_clear_object (&extension->menu_action_webview); + g_clear_object (&extension->menu_action_reader); + g_clear_object (&extension->item_action_webview); + g_clear_object (&extension->item_action_reader); + g_clear_object (&extension->menu); g_free (extension->iframe_src); g_free (extension->iframe_id); @@ -418,7 +381,37 @@ e_mail_display_popup_text_highlight_class_finalize (EMailDisplayPopupTextHighlig static void e_mail_display_popup_text_highlight_init (EMailDisplayPopupTextHighlight *extension) { - extension->action_group = NULL; - extension->iframe_src = NULL; - extension->iframe_id = NULL; + Language *languages; + GMenu *others_menu; + gsize ii, len; + + extension->menu = g_menu_new (); + + languages = get_default_langauges (&len); + for (ii = 0; ii < len; ii++) { + gchar *detailed_action; + + detailed_action = g_strdup_printf ("EPluginTextHighlight.format-as-menu-item('%s')", languages[ii].action_name); + + g_menu_append (extension->menu, languages[ii].action_label, detailed_action); + + g_free (detailed_action); + } + + others_menu = g_menu_new (); + + languages = get_additinal_languages (&len); + for (ii = 0; ii < len; ii++) { + gchar *detailed_action; + + detailed_action = g_strdup_printf ("EPluginTextHighlight.format-as-menu-item('%s')", languages[ii].action_name); + + g_menu_append (others_menu, languages[ii].action_label, detailed_action); + + g_free (detailed_action); + } + + g_menu_append_submenu (extension->menu, N_("_Other languages"), G_MENU_MODEL (others_menu)); + + g_clear_object (&others_menu); } diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c index 6631a81bcd..04fc1fae41 100644 --- a/src/modules/webkit-editor/e-webkit-editor.c +++ b/src/modules/webkit-editor/e-webkit-editor.c @@ -2312,7 +2312,7 @@ webkit_editor_move_caret_on_coordinates (EContentEditor *editor, static void webkit_editor_insert_emoticon (EContentEditor *editor, - EEmoticon *emoticon) + const EEmoticon *emoticon) { EWebKitEditor *wk_editor; GSettings *settings; @@ -2329,7 +2329,7 @@ webkit_editor_insert_emoticon (EContentEditor *editor, text = emoticon->unicode_character; } else { text = emoticon->text_face; - image_uri = e_emoticon_get_uri (emoticon); + image_uri = e_emoticon_dup_uri (emoticon); if (image_uri) { width = 16; diff --git a/src/modules/webkit-editor/web-extension/e-editor-web-extension.c b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c index f3c460cd86..7bb46f8aad 100644 --- a/src/modules/webkit-editor/web-extension/e-editor-web-extension.c +++ b/src/modules/webkit-editor/web-extension/e-editor-web-extension.c @@ -434,7 +434,7 @@ evo_editor_jsc_lookup_emoticon (const gchar *iconName, jsc_value_object_set_property (object, "text", value); g_clear_object (&value); - image_uri = e_emoticon_get_uri ((EEmoticon *) emoticon); + image_uri = e_emoticon_dup_uri (emoticon); if (image_uri) { value = jsc_value_new_string (jsc_context, image_uri); diff --git a/src/plugins/attachment-reminder/attachment-reminder.c b/src/plugins/attachment-reminder/attachment-reminder.c index 3a7e22e09c..800cca7e74 100644 --- a/src/plugins/attachment-reminder/attachment-reminder.c +++ b/src/plugins/attachment-reminder/attachment-reminder.c @@ -178,7 +178,7 @@ ask_for_missing_attachment (EPlugin *ep, gtk_widget_destroy (dialog); if (response == GTK_RESPONSE_OK) - gtk_action_activate (E_COMPOSER_ACTION_ATTACH (window)); + g_action_activate (G_ACTION (E_COMPOSER_ACTION_ATTACH (window)), NULL); return response == GTK_RESPONSE_YES; } diff --git a/src/plugins/email-custom-header/email-custom-header.c b/src/plugins/email-custom-header/email-custom-header.c index fbd446fd31..bb05749180 100644 --- a/src/plugins/email-custom-header/email-custom-header.c +++ b/src/plugins/email-custom-header/email-custom-header.c @@ -68,11 +68,10 @@ struct _CustomHeaderOptionsDialogPrivate { GType custom_header_options_dialog_get_type (void); static void epech_dialog_finalize (GObject *object); static void epech_setup_widgets (CustomHeaderOptionsDialog *mch); -static gint epech_check_existing_composer_window (gconstpointer a, gconstpointer b); static void commit_changes (ConfigData *cd); gint e_plugin_lib_enable (EPlugin *ep, gint enable); GtkWidget *e_plugin_lib_get_configure_widget (EPlugin *epl); -gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer); +gboolean e_plugin_ui_init (EUIManager *manager, EMsgComposer *composer); GtkWidget *org_gnome_email_custom_header_config_option (EPlugin *epl, struct _EConfigHookItemFactoryData *data); G_DEFINE_TYPE_WITH_PRIVATE (CustomHeaderOptionsDialog, custom_header_options_dialog, G_TYPE_OBJECT) @@ -428,110 +427,73 @@ epech_append_to_custom_header (CustomHeaderOptionsDialog *dialog, } static void -epech_custom_header_options_commit (EMsgComposer *comp, +epech_custom_header_options_commit (EMsgComposer *composer, gpointer user_data) { - EMsgComposer *composer; - EmailCustomHeaderWindow *new_email_custom_header_window = NULL; - CustomHeaderOptionsDialog *current_dialog = NULL; - - composer = (EMsgComposer *) user_data; - - if (!user_data || !E_IS_MAIL_CUSTOM_HEADER_OPTIONS_DIALOG (user_data)) - return; - - new_email_custom_header_window = g_object_get_data ((GObject *) composer, "compowindow"); - - if (new_email_custom_header_window) { - current_dialog = new_email_custom_header_window->epech_dialog; - } - - g_clear_pointer (¤t_dialog, g_free); - g_clear_pointer (&new_email_custom_header_window, g_free); -} - -static gint -epech_check_existing_composer_window (gconstpointer compowindow, - gconstpointer other_compowindow) -{ - if ((compowindow) && (other_compowindow)) { - if (((EmailCustomHeaderWindow *) compowindow)->epech_window == (GdkWindow *) other_compowindow) { - return 0; - } - } - - return -1; + g_object_set_data ((GObject *) composer, "epech_dialog", NULL); } static void -destroy_compo_data (gpointer data) +action_email_custom_header_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - EmailCustomHeaderWindow *compo_data = (EmailCustomHeaderWindow *) data; - - g_free (compo_data); -} - -static void -action_email_custom_header_cb (GtkAction *action, - EMsgComposer *composer) -{ - GtkUIManager *ui_manager; - GtkWidget *menuitem; - GdkWindow *window; + EMsgComposer *composer = user_data; CustomHeaderOptionsDialog *dialog = NULL; - EmailCustomHeaderWindow *new_email_custom_header_window = NULL; - EHTMLEditor *editor; - editor = e_msg_composer_get_editor (composer); - ui_manager = e_html_editor_get_ui_manager (editor); - menuitem = gtk_ui_manager_get_widget (ui_manager, "/main-menu/insert-menu/insert-menu-top/Custom Header"); + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); - new_email_custom_header_window = g_object_get_data ((GObject *) composer, "compowindow"); + dialog = g_object_get_data ((GObject *) composer, "epech_dialog"); - window = gtk_widget_get_window (menuitem); - if (epech_check_existing_composer_window (new_email_custom_header_window,window) == 0) { - dialog = new_email_custom_header_window->epech_dialog; - } else { + if (!dialog) { dialog = epech_dialog_new (); if (dialog) { - new_email_custom_header_window = g_new0 (EmailCustomHeaderWindow, 1); - new_email_custom_header_window->epech_window = window; - new_email_custom_header_window->epech_dialog = dialog; - g_object_set_data_full ((GObject *) composer, "compowindow", new_email_custom_header_window, destroy_compo_data); + g_object_set_data ((GObject *) composer, "epech_dialog", dialog); + + g_signal_connect ( + dialog, "emch_response", + G_CALLBACK (epech_append_to_custom_header), composer); + g_signal_connect ( + composer, "destroy", + G_CALLBACK (epech_custom_header_options_commit), composer); } } epech_dialog_run (dialog, GTK_WIDGET (composer)); - g_signal_connect ( - dialog, "emch_response", - G_CALLBACK (epech_append_to_custom_header), composer); - g_signal_connect ( - composer, "destroy", - G_CALLBACK (epech_custom_header_options_commit), composer); } -static GtkActionEntry entries[] = { - - { "Custom Header", - NULL, - N_("_Custom Header"), - NULL, - NULL, - G_CALLBACK (action_email_custom_header_cb) } -}; - gboolean -e_plugin_ui_init (GtkUIManager *ui_manager, +e_plugin_ui_init (EUIManager *manager, EMsgComposer *composer) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + ""; + static const EUIActionEntry entries[] = { + + { "custom-header", + NULL, + N_("_Custom Header"), + NULL, + NULL, + action_email_custom_header_cb, NULL, NULL, NULL } + }; + EHTMLEditor *editor; + EUIManager *ui_manager; editor = e_msg_composer_get_editor (composer); + ui_manager = e_html_editor_get_ui_manager (editor); - /* Add actions to the "composer" action group. */ - gtk_action_group_add_actions ( - e_html_editor_get_action_group (editor, "composer"), - entries, G_N_ELEMENTS (entries), composer); + e_ui_manager_add_actions_with_eui_data (ui_manager, "composer", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), composer, eui); return TRUE; } diff --git a/src/plugins/email-custom-header/email-custom-header.h b/src/plugins/email-custom-header/email-custom-header.h index 468a42c4dc..3965517e61 100644 --- a/src/plugins/email-custom-header/email-custom-header.h +++ b/src/plugins/email-custom-header/email-custom-header.h @@ -70,12 +70,6 @@ struct _CustomHeaderOptionsDialogClass { void (* emch_response) (CustomHeaderOptionsDialog *esd, gint status); }; -typedef struct _EmailCustomHeaderWindow -{ - GdkWindow *epech_window; - CustomHeaderOptionsDialog *epech_dialog; -}EmailCustomHeaderWindow; - enum { MCH_RESPONSE, LAST_SIGNAL diff --git a/src/plugins/email-custom-header/org-gnome-email-custom-header.eplug.xml b/src/plugins/email-custom-header/org-gnome-email-custom-header.eplug.xml index 3eb1f0a5a5..b66f860bac 100644 --- a/src/plugins/email-custom-header/org-gnome-email-custom-header.eplug.xml +++ b/src/plugins/email-custom-header/org-gnome-email-custom-header.eplug.xml @@ -6,18 +6,6 @@ <_description>Add custom headers to outgoing mail messages. - - - - - - - - - - - - @@ -25,5 +13,9 @@ + + + + diff --git a/src/plugins/external-editor/external-editor.c b/src/plugins/external-editor/external-editor.c index a4c7ce17f3..21935beee3 100644 --- a/src/plugins/external-editor/external-editor.c +++ b/src/plugins/external-editor/external-editor.c @@ -43,7 +43,7 @@ #define d(x) -gboolean e_plugin_ui_init (GtkUIManager *manager, +gboolean e_plugin_ui_init (EUIManager *manager, EMsgComposer *composer); GtkWidget * e_plugin_lib_get_configure_widget (EPlugin *epl); @@ -146,27 +146,25 @@ enable_disable_composer (EMsgComposer *composer, { EHTMLEditor *editor; EContentEditor *cnt_editor; - GtkAction *action; - GtkActionGroup *action_group; + EUIActionGroup *action_group; + EUIManager *ui_manager; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); editor = e_msg_composer_get_editor (composer); cnt_editor = e_html_editor_get_content_editor (editor); + ui_manager = e_html_editor_get_ui_manager (editor); e_content_editor_set_editable (cnt_editor, enable); - action = E_HTML_EDITOR_ACTION_EDIT_MENU (editor); - gtk_action_set_sensitive (action, enable); + e_ui_action_set_sensitive (E_HTML_EDITOR_ACTION_EDIT_MENU (editor), enable); + e_ui_action_set_sensitive (E_HTML_EDITOR_ACTION_FORMAT_MENU (editor), enable); + e_ui_action_set_sensitive (E_HTML_EDITOR_ACTION_INSERT_MENU (editor), enable); - action = E_HTML_EDITOR_ACTION_FORMAT_MENU (editor); - gtk_action_set_sensitive (action, enable); + g_return_if_fail (e_ui_manager_has_action_group (ui_manager, "composer")); - action = E_HTML_EDITOR_ACTION_INSERT_MENU (editor); - gtk_action_set_sensitive (action, enable); - - action_group = e_html_editor_get_action_group (editor, "composer"); - gtk_action_group_set_sensitive (action_group, enable); + action_group = e_ui_manager_get_action_group (ui_manager, "composer"); + e_ui_action_group_set_sensitive (action_group, enable); } static void @@ -452,15 +450,19 @@ launch_editor_content_ready_cb (GObject *source_object, } static void -launch_editor (GtkAction *action, - EMsgComposer *composer) +launch_editor_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; struct ExternalEditorData *eed; EHTMLEditor *editor; EContentEditor *cnt_editor; d (printf ("\n\nexternal_editor plugin is launched \n\n")); + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + if (editor_running ()) { d (printf ("not opening editor, because it's still running\n")); return; @@ -483,15 +485,6 @@ launch_editor (GtkAction *action, launch_editor_content_ready_cb, eed); } -static GtkActionEntry entries[] = { - { "ExternalEditor", - NULL, - N_("Compose in External Editor"), - "e", - N_("Compose in External Editor"), - G_CALLBACK (launch_editor) } -}; - static gboolean key_press_cb (GtkWidget *widget, GdkEventKey *event, @@ -519,7 +512,7 @@ key_press_cb (GtkWidget *widget, if (!immediately) return FALSE; - launch_editor (NULL, composer); + launch_editor_cb (NULL, NULL, composer); return TRUE; } @@ -551,19 +544,41 @@ delete_cb (GtkWidget *widget, } gboolean -e_plugin_ui_init (GtkUIManager *manager, +e_plugin_ui_init (EUIManager *manager, EMsgComposer *composer) { + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry entries[] = { + { "external-editor", + NULL, + N_("Compose in External Editor"), + "e", + N_("Compose in External Editor"), + launch_editor_cb, NULL, NULL, NULL } + }; + EHTMLEditor *editor; + EUIManager *ui_manager; EContentEditor *cnt_editor; editor = e_msg_composer_get_editor (composer); cnt_editor = e_html_editor_get_content_editor (editor); + ui_manager = e_html_editor_get_ui_manager (editor); - /* Add actions to the "composer" action group. */ - gtk_action_group_add_actions ( - e_html_editor_get_action_group (editor, "composer"), - entries, G_N_ELEMENTS (entries), composer); + e_ui_manager_add_actions_with_eui_data (ui_manager, "composer", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), composer, eui); g_signal_connect ( cnt_editor, "key_press_event", diff --git a/src/plugins/external-editor/org-gnome-external-editor.eplug.xml b/src/plugins/external-editor/org-gnome-external-editor.eplug.xml index 20cbf91487..535f9b1c86 100644 --- a/src/plugins/external-editor/org-gnome-external-editor.eplug.xml +++ b/src/plugins/external-editor/org-gnome-external-editor.eplug.xml @@ -8,17 +8,7 @@ <_description>Use an external editor to compose plain-text mail messages. - - - - - - - - - - - + diff --git a/src/plugins/face/face.c b/src/plugins/face/face.c index 8d6dfe4a6f..b092d517b4 100644 --- a/src/plugins/face/face.c +++ b/src/plugins/face/face.c @@ -479,10 +479,17 @@ face_change_image_in_composer_cb (GtkButton *button, } static void -action_toggle_face_cb (GtkToggleAction *action, - EMsgComposer *composer) +action_toggle_face_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { - if (gtk_toggle_action_get_active (action)) { + EMsgComposer *composer = user_data; + + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + + e_ui_action_set_state (action, parameter); + + if (e_ui_action_get_active (action)) { gsize image_data_length = 0; gchar *face = get_face_base64 (); @@ -493,7 +500,7 @@ action_toggle_face_cb (GtkToggleAction *action, g_object_unref (pixbuf); } else { /* cannot load a face image, uncheck the option */ - gtk_toggle_action_set_active (action, FALSE); + e_ui_action_set_active (action, FALSE); } } else { g_free (g_base64_decode (face, &image_data_length)); @@ -509,7 +516,7 @@ action_toggle_face_cb (GtkToggleAction *action, /* ----------------------------------------------------------------- */ gint e_plugin_lib_enable (EPlugin *ep, gint enable); -gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer); +gboolean e_plugin_ui_init (EUIManager *manager, EMsgComposer *composer); GtkWidget *e_plugin_lib_get_configure_widget (EPlugin *epl); void face_handle_send (EPlugin *ep, EMEventTargetComposer *target); @@ -523,42 +530,47 @@ e_plugin_lib_enable (EPlugin *ep, } gboolean -e_plugin_ui_init (GtkUIManager *ui_manager, +e_plugin_ui_init (EUIManager *manager, EMsgComposer *composer) { - EHTMLEditor *editor; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + ""; - GtkToggleActionEntry entries[] = { + static const EUIActionEntry entries[] = { { "face-plugin", NULL, N_("Include _Face"), NULL, NULL, - G_CALLBACK (action_toggle_face_cb), - FALSE } + NULL, NULL, "false", action_toggle_face_cb } }; - if (get_include_face_by_default ()) { - gchar *face = get_face_base64 (); - - /* activate it only if has a face image available */ - entries[0].is_active = face && *face; - - g_free (face); - } + EHTMLEditor *editor; + EUIManager *ui_manager; editor = e_msg_composer_get_editor (composer); + ui_manager = e_html_editor_get_ui_manager (editor); - /* Add actions to the "composer" action group. */ - gtk_action_group_add_toggle_actions ( - e_html_editor_get_action_group (editor, "composer"), - entries, G_N_ELEMENTS (entries), composer); + e_ui_manager_add_actions_with_eui_data (ui_manager, "composer", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), composer, eui); - if (entries[0].is_active) { + if (get_include_face_by_default ()) { + EUIAction *action; gsize image_data_length = 0; gchar *face = get_face_base64 (); if (face) { + action = e_html_editor_get_action (editor, "face-plugin"); + e_ui_action_set_active (action, TRUE); + g_free (g_base64_decode (face, &image_data_length)); g_free (face); } @@ -580,14 +592,14 @@ face_handle_send (EPlugin *ep, EMEventTargetComposer *target) { EHTMLEditor *editor; - GtkAction *action; + EUIAction *action; editor = e_msg_composer_get_editor (target->composer); action = e_html_editor_get_action (editor, "face-plugin"); g_return_if_fail (action != NULL); - if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))) { + if (e_ui_action_get_active (action)) { gchar *face = get_face_base64 (); if (face) diff --git a/src/plugins/face/org-gnome-face.eplug.xml b/src/plugins/face/org-gnome-face.eplug.xml index da3159ae1b..3c6bbad157 100644 --- a/src/plugins/face/org-gnome-face.eplug.xml +++ b/src/plugins/face/org-gnome-face.eplug.xml @@ -6,15 +6,7 @@ <_description xml:space="preserve">Attach a small picture of your face to outgoing messages. - - - - - - - - - + diff --git a/src/plugins/mail-notification/mail-notification.c b/src/plugins/mail-notification/mail-notification.c index 8ff1d8b1d1..001d82204b 100644 --- a/src/plugins/mail-notification/mail-notification.c +++ b/src/plugins/mail-notification/mail-notification.c @@ -36,14 +36,15 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include +#include "mail/e-mail-account-store.h" +#include "mail/e-mail-backend.h" +#include "mail/e-mail-ui-session.h" +#include "mail/e-mail-view.h" +#include "mail/em-utils.h" +#include "mail/em-event.h" +#include "mail/em-folder-tree.h" +#include "mail/message-list.h" +#include "shell/e-shell-view.h" #ifdef HAVE_LIBNOTIFY #include @@ -415,11 +416,9 @@ notify_default_action_cb (NotifyNotification *notification, EShellView *shell_view; EShellWindow *shell_window; EShellSidebar *shell_sidebar; - EMailReader *shell_reader; EMFolderTree *folder_tree; - MessageList *message_list; + EUIAction *action; GtkApplication *application; - GtkAction *action; GList *list, *fallback = NULL; shell = e_shell_get_default (); @@ -453,8 +452,8 @@ notify_default_action_cb (NotifyNotification *notification, /* Switch to the mail view. */ shell_view = e_shell_window_get_shell_view (shell_window, "mail"); - action = e_shell_view_get_action (shell_view); - gtk_action_activate (action); + action = e_shell_view_get_switcher_action (shell_view); + g_action_activate (G_ACTION (action), NULL); /* Select the latest folder with new mail. */ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); @@ -462,10 +461,18 @@ notify_default_action_cb (NotifyNotification *notification, em_folder_tree_set_selected (folder_tree, data->folder_uri, FALSE); if (data->msg_uid) { - /* Select the message. */ - shell_reader = E_MAIL_READER (e_shell_view_get_shell_content (shell_view)); - message_list = MESSAGE_LIST (e_mail_reader_get_message_list (shell_reader)); - message_list_select_uid (message_list, data->msg_uid, TRUE); + EMailView *mail_view = NULL; + + g_object_get (e_shell_view_get_shell_content (shell_view), "mail-view", &mail_view, NULL); + if (mail_view) { + MessageList *message_list; + + /* Select the message. */ + message_list = MESSAGE_LIST (e_mail_reader_get_message_list (E_MAIL_READER (mail_view))); + message_list_select_uid (message_list, data->msg_uid, TRUE); + + g_clear_object (&mail_view); + } } remove_notification (); diff --git a/src/plugins/mail-to-task/mail-to-task.c b/src/plugins/mail-to-task/mail-to-task.c index 7704743d43..b668efb810 100644 --- a/src/plugins/mail-to-task/mail-to-task.c +++ b/src/plugins/mail-to-task/mail-to-task.c @@ -31,12 +31,13 @@ #include -#include -#include +#include "shell/e-shell-view.h" +#include "shell/e-shell-window-actions.h" -#include -#include -#include +#include "mail/e-mail-browser.h" +#include "mail/e-mail-view.h" +#include "mail/em-utils.h" +#include "mail/message-list.h" #include "calendar/gui/calendar-config.h" #include "calendar/gui/comp-util.h" @@ -54,9 +55,10 @@ #define E_SHELL_WINDOW_ACTION_CONVERT_TO_TASK(window) \ E_SHELL_WINDOW_ACTION ((window), "mail-convert-to-task") -gboolean mail_browser_init (GtkUIManager *ui_manager, +gboolean mail_to_task_mail_browser_init (EUIManager *ui_manager, EMailBrowser *browser); -gboolean mail_shell_view_init (GtkUIManager *ui_manager, +gboolean mail_to_task_mail_shell_view_init + (EUIManager *ui_manager, EShellView *shell_view); static ECompEditor * @@ -1335,142 +1337,149 @@ mail_to_event (ECalClientSourceType source_type, } static void -action_mail_convert_to_event_cb (GtkAction *action, - EMailReader *reader) +action_mail_convert_to_event_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; mail_to_event (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, FALSE, reader); } static void -action_mail_convert_to_meeting_cb (GtkAction *action, - EMailReader *reader) +action_mail_convert_to_meeting_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; mail_to_event (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, TRUE, reader); } static void -action_mail_convert_to_memo_cb (GtkAction *action, - EMailReader *reader) +action_mail_convert_to_memo_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; mail_to_event (E_CAL_CLIENT_SOURCE_TYPE_MEMOS, FALSE, reader); } static void -action_mail_convert_to_task_cb (GtkAction *action, - EMailReader *reader) +action_mail_convert_to_task_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; mail_to_event (E_CAL_CLIENT_SOURCE_TYPE_TASKS, FALSE, reader); } -/* Note, we're not using EPopupActions here because we update the state - * of entire actions groups instead of individual actions. EPopupActions - * just proxy the state of individual actions. */ - -static GtkActionEntry multi_selection_entries[] = { - - { "mail-convert-to-appointment", - "appointment-new", - N_("Create an _Appointment"), - NULL, - N_("Create a new event from the selected message"), - G_CALLBACK (action_mail_convert_to_event_cb) }, - - { "mail-convert-to-memo", - "stock_insert-note", - N_("Create a Mem_o"), - NULL, - N_("Create a new memo from the selected message"), - G_CALLBACK (action_mail_convert_to_memo_cb) }, - - { "mail-convert-to-task", - "stock_todo", - N_("Create a _Task"), - NULL, - N_("Create a new task from the selected message"), - G_CALLBACK (action_mail_convert_to_task_cb) } -}; - -static GtkActionEntry single_selection_entries[] = { - - { "mail-convert-to-meeting", - "stock_people", - N_("Create a _Meeting"), - NULL, - N_("Create a new meeting from the selected message"), - G_CALLBACK (action_mail_convert_to_meeting_cb) } -}; - static void -update_actions_any_cb (EMailReader *reader, - guint32 state, - GtkActionGroup *action_group) +update_actions_cb (EMailReader *reader, + guint32 state, + EUIManager *ui_manager) { + EUIActionGroup *action_group; gboolean sensitive; sensitive = (state & E_MAIL_READER_SELECTION_SINGLE) || (state & E_MAIL_READER_SELECTION_MULTIPLE); - gtk_action_group_set_sensitive (action_group, sensitive); -} - -static void -update_actions_one_cb (EMailReader *reader, - guint32 state, - GtkActionGroup *action_group) -{ - gboolean sensitive; + action_group = e_ui_manager_get_action_group (ui_manager, "mail-convert-any"); + e_ui_action_group_set_sensitive (action_group, sensitive); sensitive = (state & E_MAIL_READER_SELECTION_SINGLE); - gtk_action_group_set_sensitive (action_group, sensitive); + action_group = e_ui_manager_get_action_group (ui_manager, "mail-convert-one"); + e_ui_action_group_set_sensitive (action_group, sensitive); } static void setup_actions (EMailReader *reader, - GtkUIManager *ui_manager) + EUIManager *ui_manager) { - GtkActionGroup *action_group; - const gchar *domain = GETTEXT_PACKAGE; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - action_group = gtk_action_group_new ("mail-convert-any"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, multi_selection_entries, - G_N_ELEMENTS (multi_selection_entries), reader); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); + static const EUIActionEntry multi_selection_entries[] = { - /* GtkUIManager now owns the action group reference. - * The signal we're connecting to will only be emitted - * during the GtkUIManager's lifetime, so the action - * group will not disappear on us. */ + { "mail-convert-to-appointment", + "appointment-new", + N_("Create an _Appointment"), + NULL, + N_("Create a new event from the selected message"), + action_mail_convert_to_event_cb, NULL, NULL, NULL }, - g_signal_connect ( + { "mail-convert-to-memo", + "stock_insert-note", + N_("Create a Mem_o"), + NULL, + N_("Create a new memo from the selected message"), + action_mail_convert_to_memo_cb, NULL, NULL, NULL }, + + { "mail-convert-to-task", + "stock_todo", + N_("Create a _Task"), + NULL, + N_("Create a new task from the selected message"), + action_mail_convert_to_task_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry single_selection_entries[] = { + + { "mail-convert-to-meeting", + "stock_people", + N_("Create a _Meeting"), + NULL, + N_("Create a new meeting from the selected message"), + action_mail_convert_to_meeting_cb, NULL, NULL, NULL } + }; + + e_ui_manager_add_actions (ui_manager, "mail-convert-any", NULL, + multi_selection_entries, G_N_ELEMENTS (multi_selection_entries), reader); + e_ui_manager_add_actions_with_eui_data (ui_manager, "mail-convert-one", NULL, + single_selection_entries, G_N_ELEMENTS (single_selection_entries), reader, eui); + + g_signal_connect_object ( reader, "update-actions", - G_CALLBACK (update_actions_any_cb), action_group); - - action_group = gtk_action_group_new ("mail-convert-one"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, single_selection_entries, - G_N_ELEMENTS (single_selection_entries), reader); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - /* GtkUIManager now owns the action group reference. - * The signal we're connecting to will only be emitted - * during the GtkUIManager's lifetime, so the action - * group will not disappear on us. */ - - g_signal_connect ( - reader, "update-actions", - G_CALLBACK (update_actions_one_cb), action_group); + G_CALLBACK (update_actions_cb), ui_manager, 0); } gboolean -mail_browser_init (GtkUIManager *ui_manager, - EMailBrowser *browser) +mail_to_task_mail_browser_init (EUIManager *ui_manager, + EMailBrowser *browser) { setup_actions (E_MAIL_READER (browser), ui_manager); @@ -1478,14 +1487,19 @@ mail_browser_init (GtkUIManager *ui_manager, } gboolean -mail_shell_view_init (GtkUIManager *ui_manager, - EShellView *shell_view) +mail_to_task_mail_shell_view_init (EUIManager *ui_manager, + EShellView *shell_view) { EShellContent *shell_content; + EMailView *mail_view = NULL; shell_content = e_shell_view_get_shell_content (shell_view); + g_object_get (shell_content, "mail-view", &mail_view, NULL); - setup_actions (E_MAIL_READER (shell_content), ui_manager); + if (mail_view) { + setup_actions (E_MAIL_READER (mail_view), ui_manager); + g_clear_object (&mail_view); + } return TRUE; } diff --git a/src/plugins/mail-to-task/org-gnome-mail-to-task.eplug.xml b/src/plugins/mail-to-task/org-gnome-mail-to-task.eplug.xml index 3882c2f7ec..0a070391a9 100644 --- a/src/plugins/mail-to-task/org-gnome-mail-to-task.eplug.xml +++ b/src/plugins/mail-to-task/org-gnome-mail-to-task.eplug.xml @@ -5,66 +5,8 @@ <_description>Convert a mail message to a task. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/src/plugins/mailing-list-actions/mailing-list-actions.c b/src/plugins/mailing-list-actions/mailing-list-actions.c index c5fade24e0..571a981a3d 100644 --- a/src/plugins/mailing-list-actions/mailing-list-actions.c +++ b/src/plugins/mailing-list-actions/mailing-list-actions.c @@ -28,18 +28,19 @@ #include -#include -#include -#include +#include "shell/e-shell-view.h" +#include "shell/e-shell-window.h" +#include "shell/e-shell-window-actions.h" -#include +#include "composer/e-msg-composer.h" -#include -#include -#include -#include -#include -#include +#include "mail/e-mail-browser.h" +#include "mail/e-mail-reader.h" +#include "mail/e-mail-view.h" +#include "mail/em-composer-utils.h" +#include "mail/em-config.h" +#include "mail/em-utils.h" +#include "mail/message-list.h" /* EAlert Message IDs */ #define MESSAGE_PREFIX "org.gnome.mailing-list-actions:" @@ -81,11 +82,14 @@ const EmlaActionHeader emla_action_headers[] = { { EMLA_ACTION_ARCHIVED_AT, FALSE, "Archived-At" } }; -gboolean mail_browser_init (GtkUIManager *ui_manager, +gboolean mailing_list_actions_mail_browser_init + (EUIManager *ui_manager, EMailBrowser *browser); -gboolean mail_shell_view_init (GtkUIManager *ui_manager, +gboolean mailing_list_actions_mail_shell_view_init + (EUIManager *ui_manager, EShellView *shell_view); -gint e_plugin_lib_enable (EPlugin *ep, gint enable); +gint e_plugin_lib_enable (EPlugin *ep, + gint enable); gint e_plugin_lib_enable (EPlugin *ep, @@ -362,131 +366,87 @@ emla_list_action (EMailReader *reader, } static void -action_mailing_list_archive_cb (GtkAction *action, - EMailReader *reader) +action_mailing_list_archive_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; emla_list_action (reader, EMLA_ACTION_ARCHIVE); } static void -action_mailing_list_archived_at_cb (GtkAction *action, - EMailReader *reader) +action_mailing_list_archived_at_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; emla_list_action (reader, EMLA_ACTION_ARCHIVED_AT); } static void -action_mailing_list_help_cb (GtkAction *action, - EMailReader *reader) +action_mailing_list_help_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; emla_list_action (reader, EMLA_ACTION_HELP); } static void -action_mailing_list_owner_cb (GtkAction *action, - EMailReader *reader) +action_mailing_list_owner_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; emla_list_action (reader, EMLA_ACTION_OWNER); } static void -action_mailing_list_post_cb (GtkAction *action, - EMailReader *reader) +action_mailing_list_post_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; emla_list_action (reader, EMLA_ACTION_POST); } static void -action_mailing_list_subscribe_cb (GtkAction *action, - EMailReader *reader) +action_mailing_list_subscribe_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; emla_list_action (reader, EMLA_ACTION_SUBSCRIBE); } static void -action_mailing_list_unsubscribe_cb (GtkAction *action, - EMailReader *reader) +action_mailing_list_unsubscribe_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMailReader *reader = user_data; emla_list_action (reader, EMLA_ACTION_UNSUBSCRIBE); } -static GtkActionEntry mailing_list_entries[] = { - - { "mailing-list-archive", - NULL, - N_("Get List _Archive"), - NULL, - N_("Get an archive of the list this message belongs to"), - G_CALLBACK (action_mailing_list_archive_cb) }, - - { "mailing-list-archived-at", - NULL, - N_("Copy _Message Archive URL"), - NULL, - N_("Copy direct URL for the selected message in its archive"), - G_CALLBACK (action_mailing_list_archived_at_cb) }, - - { "mailing-list-help", - NULL, - N_("Get List _Usage Information"), - NULL, - N_("Get information about the usage of the list this message belongs to"), - G_CALLBACK (action_mailing_list_help_cb) }, - - { "mailing-list-owner", - NULL, - N_("Contact List _Owner"), - NULL, - N_("Contact the owner of the mailing list this message belongs to"), - G_CALLBACK (action_mailing_list_owner_cb) }, - - { "mailing-list-post", - NULL, - N_("_Post Message to List"), - NULL, - N_("Post a message to the mailing list this message belongs to"), - G_CALLBACK (action_mailing_list_post_cb) }, - - { "mailing-list-subscribe", - NULL, - N_("_Subscribe to List"), - NULL, - N_("Subscribe to the mailing list this message belongs to"), - G_CALLBACK (action_mailing_list_subscribe_cb) }, - - { "mailing-list-unsubscribe", - NULL, - N_("_Unsubscribe from List"), - NULL, - N_("Unsubscribe from the mailing list this message belongs to"), - G_CALLBACK (action_mailing_list_unsubscribe_cb) }, - - /*** Menus ***/ - - { "mailing-list-menu", - NULL, - N_("Mailing _List"), - NULL, - NULL, - NULL } -}; - static void update_actions_cb (EMailReader *reader, guint32 state, - GtkActionGroup *action_group) + EUIManager *ui_manager) { + EUIActionGroup *action_group; gboolean sensitive; + action_group = e_ui_manager_get_action_group (ui_manager, "mailing-list"); + sensitive = (state & E_MAIL_READER_SELECTION_IS_MAILING_LIST) != 0 && (state & E_MAIL_READER_SELECTION_SINGLE) != 0; - gtk_action_group_set_sensitive (action_group, sensitive); + + e_ui_action_group_set_sensitive (action_group, sensitive); if (sensitive) { EMailDisplay *mail_display; EMailPartList *part_list; CamelMimeMessage *message; - GtkAction *action; mail_display = e_mail_reader_get_mail_display (reader); part_list = mail_display ? e_mail_display_get_part_list (mail_display) : NULL; @@ -499,39 +459,108 @@ update_actions_cb (EMailReader *reader, sensitive = header && *header; } - action = gtk_action_group_get_action (action_group, "mailing-list-archived-at"); - gtk_action_set_sensitive (action, message && sensitive); + e_ui_action_set_sensitive (e_ui_action_group_get_action (action_group, "mailing-list-archived-at"), message && sensitive); } } static void setup_actions (EMailReader *reader, - GtkUIManager *ui_manager) + EUIManager *ui_manager) { - GtkActionGroup *action_group; - const gchar *domain = GETTEXT_PACKAGE; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - action_group = gtk_action_group_new ("mailing-list"); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_action_group_add_actions ( - action_group, mailing_list_entries, - G_N_ELEMENTS (mailing_list_entries), reader); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); + static const EUIActionEntry entries[] = { - /* GtkUIManager now owns the action group reference. - * The signal we're connecting to will only be emitted - * during the GtkUIManager's lifetime, so the action - * group will not disappear on us. */ + { "mailing-list-archive", + NULL, + N_("Get List _Archive"), + NULL, + N_("Get an archive of the list this message belongs to"), + action_mailing_list_archive_cb, NULL, NULL, NULL }, - g_signal_connect ( + { "mailing-list-archived-at", + NULL, + N_("Copy _Message Archive URL"), + NULL, + N_("Copy direct URL for the selected message in its archive"), + action_mailing_list_archived_at_cb, NULL, NULL, NULL }, + + { "mailing-list-help", + NULL, + N_("Get List _Usage Information"), + NULL, + N_("Get information about the usage of the list this message belongs to"), + action_mailing_list_help_cb, NULL, NULL, NULL }, + + { "mailing-list-owner", + NULL, + N_("Contact List _Owner"), + NULL, + N_("Contact the owner of the mailing list this message belongs to"), + action_mailing_list_owner_cb, NULL, NULL, NULL }, + + { "mailing-list-post", + NULL, + N_("_Post Message to List"), + NULL, + N_("Post a message to the mailing list this message belongs to"), + action_mailing_list_post_cb, NULL, NULL, NULL }, + + { "mailing-list-subscribe", + NULL, + N_("_Subscribe to List"), + NULL, + N_("Subscribe to the mailing list this message belongs to"), + action_mailing_list_subscribe_cb, NULL, NULL, NULL }, + + { "mailing-list-unsubscribe", + NULL, + N_("_Unsubscribe from List"), + NULL, + N_("Unsubscribe from the mailing list this message belongs to"), + action_mailing_list_unsubscribe_cb, NULL, NULL, NULL }, + + /*** Menus ***/ + + { "mailing-list-menu", + NULL, + N_("Mailing _List"), + NULL, + NULL, + NULL, NULL, NULL, NULL } + }; + + e_ui_manager_add_actions_with_eui_data (ui_manager, "mailing-list", NULL, + entries, G_N_ELEMENTS (entries), reader, eui); + + g_signal_connect_object ( reader, "update-actions", - G_CALLBACK (update_actions_cb), action_group); + G_CALLBACK (update_actions_cb), ui_manager, 0); } gboolean -mail_browser_init (GtkUIManager *ui_manager, - EMailBrowser *browser) +mailing_list_actions_mail_browser_init (EUIManager *ui_manager, + EMailBrowser *browser) { setup_actions (E_MAIL_READER (browser), ui_manager); @@ -539,14 +568,19 @@ mail_browser_init (GtkUIManager *ui_manager, } gboolean -mail_shell_view_init (GtkUIManager *ui_manager, - EShellView *shell_view) +mailing_list_actions_mail_shell_view_init (EUIManager *ui_manager, + EShellView *shell_view) { EShellContent *shell_content; + EMailView *mail_view = NULL; shell_content = e_shell_view_get_shell_content (shell_view); + g_object_get (shell_content, "mail-view", &mail_view, NULL); - setup_actions (E_MAIL_READER (shell_content), ui_manager); + if (mail_view) { + setup_actions (E_MAIL_READER (mail_view), ui_manager); + g_clear_object (&mail_view); + } return TRUE; } diff --git a/src/plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.xml b/src/plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.xml index 9cd960bab3..20c3d85f0e 100644 --- a/src/plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.xml +++ b/src/plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.xml @@ -10,48 +10,8 @@ <_description>Perform common mailing list actions (subscribe, unsubscribe, etc.). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/src/plugins/publish-calendar/org-gnome-publish-calendar.eplug.xml b/src/plugins/publish-calendar/org-gnome-publish-calendar.eplug.xml index c9e514bc27..cd427e9feb 100644 --- a/src/plugins/publish-calendar/org-gnome-publish-calendar.eplug.xml +++ b/src/plugins/publish-calendar/org-gnome-publish-calendar.eplug.xml @@ -9,15 +9,7 @@ - - - - - - - - - + diff --git a/src/plugins/publish-calendar/publish-calendar.c b/src/plugins/publish-calendar/publish-calendar.c index 27067cb608..b0fdd26fc7 100644 --- a/src/plugins/publish-calendar/publish-calendar.c +++ b/src/plugins/publish-calendar/publish-calendar.c @@ -1082,9 +1082,11 @@ error_queue_add (gchar *description, } static void -action_calendar_publish_cb (GtkAction *action, - EShellView *shell_view) +action_calendar_publish_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + /* EShellView *shell_view = user_data; */ GThread *thread = NULL; GError *error = NULL; @@ -1099,31 +1101,35 @@ action_calendar_publish_cb (GtkAction *action, } } -static GtkActionEntry entries[] = { - - { "calendar-publish", - NULL, - N_("_Publish Calendar Information"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_calendar_publish_cb) } -}; - -gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EShellView *shell_view); +gboolean e_plugin_ui_init (EUIManager *ui_manager, EShellView *shell_view); gboolean -e_plugin_ui_init (GtkUIManager *ui_manager, +e_plugin_ui_init (EUIManager *ui_manager, EShellView *shell_view) { - EShellWindow *shell_window; - GtkActionGroup *action_group; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + ""; - shell_window = e_shell_view_get_shell_window (shell_view); - action_group = e_shell_window_get_action_group (shell_window, "calendar"); + static const EUIActionEntry entries[] = { - gtk_action_group_add_actions ( - action_group, entries, - G_N_ELEMENTS (entries), shell_view); + { "calendar-publish", + NULL, + N_("_Publish Calendar Information"), + NULL, + NULL, + action_calendar_publish_cb, NULL, NULL, NULL } + }; + + e_ui_manager_add_actions_with_eui_data (ui_manager, "calendar", NULL, + entries, G_N_ELEMENTS (entries), shell_view, eui); return TRUE; } diff --git a/src/plugins/save-calendar/org-gnome-save-calendar.eplug.xml b/src/plugins/save-calendar/org-gnome-save-calendar.eplug.xml index a293c33c60..560cdb55e2 100644 --- a/src/plugins/save-calendar/org-gnome-save-calendar.eplug.xml +++ b/src/plugins/save-calendar/org-gnome-save-calendar.eplug.xml @@ -5,32 +5,9 @@ <_description>Save a calendar or task list to disk. - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/src/plugins/save-calendar/save-calendar.c b/src/plugins/save-calendar/save-calendar.c index 4e381d56e6..cca13bff96 100644 --- a/src/plugins/save-calendar/save-calendar.c +++ b/src/plugins/save-calendar/save-calendar.c @@ -34,12 +34,12 @@ #include "format-handler.h" /* Plugin entry points */ -gboolean calendar_save_as_init (GtkUIManager *ui_manager, - EShellView *shell_view); -gboolean memo_list_save_as_init (GtkUIManager *ui_manager, - EShellView *shell_view); -gboolean task_list_save_as_init (GtkUIManager *ui_manager, - EShellView *shell_view); +gboolean save_calendar_calendar_save_as_init (EUIManager *ui_manager, + EShellView *shell_view); +gboolean save_calendar_memo_list_save_as_init (EUIManager *ui_manager, + EShellView *shell_view); +gboolean save_calendar_task_list_save_as_init (EUIManager *ui_manager, + EShellView *shell_view); gint e_plugin_lib_enable (EPlugin *ep, gint enable); @@ -306,139 +306,139 @@ save_general (EShellView *shell_view) } static void -action_calendar_save_as_cb (GtkAction *action, - EShellView *shell_view) +action_calendar_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; + + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + save_general (shell_view); } static void -action_memo_list_save_as_cb (GtkAction *action, - EShellView *shell_view) +action_memo_list_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; + + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + save_general (shell_view); } static void -action_task_list_save_as_cb (GtkAction *action, - EShellView *shell_view) +action_task_list_save_as_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellView *shell_view = user_data; + + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + save_general (shell_view); } -gboolean -calendar_save_as_init (GtkUIManager *ui_manager, - EShellView *shell_view) +static void +save_calendar_init_ui (EUIManager *ui_manager, + EShellView *shell_view, + const gchar *select_one_action_name, + const EUIActionEntry *entry, + const gchar *eui) { - EShellWindow *shell_window; - GtkActionGroup *action_group; - GtkAction *action, *select_one_action; - const gchar *tooltip; - const gchar *icon_name; - const gchar *name; + EUIAction *action, *select_one_action; - shell_window = e_shell_view_get_shell_window (shell_view); - - name = "calendar-save-as"; - tooltip = _("Save the selected calendar to disk"); - icon_name = "document-save-as"; - action = gtk_action_new (name, _("Save _As"), tooltip, icon_name); - - name = "lockdown-save-to-disk"; - action_group = e_shell_window_get_action_group (shell_window, name); - gtk_action_group_add_action (action_group, action); - - g_signal_connect ( - action, "activate", - G_CALLBACK (action_calendar_save_as_cb), shell_view); + e_ui_manager_add_actions_with_eui_data (ui_manager, "lockdown-save-to-disk", NULL, entry, 1, shell_view, eui); /* select-one is always sensitive, except when the clicked and the primary source differ */ - select_one_action = e_shell_window_get_action (shell_window, "calendar-select-one"); + select_one_action = e_ui_manager_get_action (ui_manager, select_one_action_name); + action = e_ui_manager_get_action (ui_manager, entry->name); e_binding_bind_property ( select_one_action, "sensitive", action, "visible", G_BINDING_SYNC_CREATE); +} - g_object_unref (action); +gboolean +save_calendar_calendar_save_as_init (EUIManager *ui_manager, + EShellView *shell_view) +{ + static const gchar *eui = + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry entry = { + "calendar-save-as", + "document-save-as", + N_("Save _As"), + NULL, + N_("Save the selected calendar to disk"), + action_calendar_save_as_cb, NULL, NULL, NULL + }; + + save_calendar_init_ui (ui_manager, shell_view, "calendar-select-one", &entry, eui); return TRUE; } gboolean -memo_list_save_as_init (GtkUIManager *ui_manager, - EShellView *shell_view) +save_calendar_memo_list_save_as_init (EUIManager *ui_manager, + EShellView *shell_view) { - EShellWindow *shell_window; - GtkActionGroup *action_group; - GtkAction *action, *select_one_action; - const gchar *tooltip; - const gchar *icon_name; - const gchar *name; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + ""; - shell_window = e_shell_view_get_shell_window (shell_view); + static const EUIActionEntry entry = { + "memo-list-save-as", + "document-save-as", + N_("Save _As"), + NULL, + N_("Save the selected memo list to disk"), + action_memo_list_save_as_cb, NULL, NULL, NULL + }; - name = "memo-list-save-as"; - tooltip = _("Save the selected memo list to disk"); - icon_name = "document-save-as"; - action = gtk_action_new (name, _("Save _As"), tooltip, icon_name); - - name = "lockdown-save-to-disk"; - action_group = e_shell_window_get_action_group (shell_window, name); - gtk_action_group_add_action (action_group, action); - - g_signal_connect ( - action, "activate", - G_CALLBACK (action_memo_list_save_as_cb), shell_view); - - /* select-one is always sensitive, except when the clicked and the primary source differ */ - select_one_action = e_shell_window_get_action (shell_window, "memo-list-select-one"); - - e_binding_bind_property ( - select_one_action, "sensitive", - action, "visible", - G_BINDING_SYNC_CREATE); - - g_object_unref (action); + save_calendar_init_ui (ui_manager, shell_view, "memo-list-select-one", &entry, eui); return TRUE; } gboolean -task_list_save_as_init (GtkUIManager *ui_manager, - EShellView *shell_view) +save_calendar_task_list_save_as_init (EUIManager *ui_manager, + EShellView *shell_view) { - EShellWindow *shell_window; - GtkActionGroup *action_group; - GtkAction *action, *select_one_action; - const gchar *tooltip; - const gchar *icon_name; - const gchar *name; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + ""; - shell_window = e_shell_view_get_shell_window (shell_view); + static const EUIActionEntry entry = { + "task-list-save-as", + "document-save-as", + N_("Save _As"), + NULL, + N_("Save the selected task list to disk"), + action_task_list_save_as_cb, NULL, NULL, NULL + }; - name = "task-list-save-as"; - tooltip = _("Save the selected task list to disk"); - icon_name = "document-save-as"; - action = gtk_action_new (name, _("Save _As"), tooltip, icon_name); - - name = "lockdown-save-to-disk"; - action_group = e_shell_window_get_action_group (shell_window, name); - gtk_action_group_add_action (action_group, action); - - g_signal_connect ( - action, "activate", - G_CALLBACK (action_task_list_save_as_cb), shell_view); - - /* select-one is always sensitive, except when the clicked and the primary source differ */ - select_one_action = e_shell_window_get_action (shell_window, "task-list-select-one"); - - e_binding_bind_property ( - select_one_action, "sensitive", - action, "visible", - G_BINDING_SYNC_CREATE); - - g_object_unref (action); + save_calendar_init_ui (ui_manager, shell_view, "task-list-select-one", &entry, eui); return TRUE; } diff --git a/src/plugins/templates/org-gnome-templates.eplug.xml b/src/plugins/templates/org-gnome-templates.eplug.xml index 5543493dd9..1fba405a65 100644 --- a/src/plugins/templates/org-gnome-templates.eplug.xml +++ b/src/plugins/templates/org-gnome-templates.eplug.xml @@ -13,21 +13,9 @@ - - - - - - - - - - - - - + + + diff --git a/src/plugins/templates/templates.c b/src/plugins/templates/templates.c index 73a11623f8..8dce69c737 100644 --- a/src/plugins/templates/templates.c +++ b/src/plugins/templates/templates.c @@ -33,6 +33,7 @@ #include "mail/e-mail-reader.h" #include "mail/e-mail-reader-utils.h" #include "mail/e-mail-ui-session.h" +#include "mail/e-mail-view.h" #include "mail/e-mail-templates.h" #include "mail/e-mail-templates-store.h" #include "mail/em-composer-utils.h" @@ -78,10 +79,12 @@ enum { GtkWidget * e_plugin_lib_get_configure_widget (EPlugin *plugin); -gboolean init_composer_actions (GtkUIManager *ui_manager, +gboolean init_composer_actions (EUIManager *ui_manager, EMsgComposer *composer); -gboolean init_shell_actions (GtkUIManager *ui_manager, - EShellWindow *shell_window); +gboolean init_mail_actions (EUIManager *ui_manager, + EShellView *shell_view); +gboolean init_mail_browser_actions (EUIManager *ui_manager, + EMailBrowser *mail_browser); gint e_plugin_lib_enable (EPlugin *plugin, gboolean enabled); @@ -89,9 +92,12 @@ gint e_plugin_lib_enable (EPlugin *plugin, typedef struct _TemplatesData { EMailTemplatesStore *templates_store; + EMailReader *mail_reader; + GMenu *reply_template_menu; gulong changed_handler_id; + guint update_menu_id; gboolean changed; - guint merge_id; + gboolean update_immediately; } TemplatesData; static void @@ -105,7 +111,14 @@ templates_data_free (gpointer ptr) td->changed_handler_id = 0; } + if (td->update_menu_id) { + g_source_remove (td->update_menu_id); + td->update_menu_id = 0; + } + g_clear_object (&td->templates_store); + g_clear_object (&td->mail_reader); + g_clear_object (&td->reply_template_menu); g_free (td); } } @@ -694,18 +707,15 @@ action_reply_with_template_cb (EMailTemplatesStore *templates_store, const gchar *template_message_uid, gpointer user_data) { + EMailReader *reader = user_data; EActivity *activity; AsyncContext *context; GCancellable *cancellable; CamelFolder *folder; - EShellView *shell_view = user_data; - EShellContent *shell_content; - EMailReader *reader; GPtrArray *uids; const gchar *message_uid; - shell_content = e_shell_view_get_shell_content (shell_view); - reader = E_MAIL_READER (shell_content); + g_return_if_fail (E_IS_MAIL_READER (reader)); uids = e_mail_reader_get_selected_uids (reader); g_return_if_fail (uids != NULL && uids->len == 1); @@ -787,22 +797,16 @@ save_template_async_data_free (gpointer ptr) if (sta) { if (sta->templates_folder_uri && sta->new_message_uid) { EHTMLEditor *editor; - GtkActionGroup *action_group; - GtkAction *action; + EUIAction *action; e_msg_composer_set_header (sta->composer, "X-Evolution-Templates-Folder", sta->templates_folder_uri); e_msg_composer_set_header (sta->composer, "X-Evolution-Templates-Message", sta->new_message_uid); editor = e_msg_composer_get_editor (sta->composer); - action_group = e_html_editor_get_action_group (editor, "composer"); - - if (action_group) { - action = gtk_action_group_get_action (action_group, "template-replace"); - - if (action) { - gtk_action_set_visible (action, TRUE); - gtk_action_set_sensitive (action, TRUE); - } + action = e_html_editor_get_action (editor, "template-replace"); + if (action) { + e_ui_action_set_visible (action, TRUE); + e_ui_action_set_sensitive (action, TRUE); } } @@ -942,9 +946,14 @@ got_message_draft_cb (GObject *source_object, } static void -action_template_replace_cb (GtkAction *action, - EMsgComposer *composer) +action_template_replace_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; + + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + /* XXX Pass a GCancellable */ e_msg_composer_get_message_draft ( composer, G_PRIORITY_DEFAULT, NULL, @@ -952,102 +961,109 @@ action_template_replace_cb (GtkAction *action, } static void -action_template_save_new_cb (GtkAction *action, - EMsgComposer *composer) +action_template_save_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EMsgComposer *composer = user_data; + + g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + /* XXX Pass a GCancellable */ e_msg_composer_get_message_draft ( composer, G_PRIORITY_DEFAULT, NULL, got_message_draft_cb, GINT_TO_POINTER (0)); } -static GtkActionEntry composer_entries[] = { - - { "template-replace", - "document-save", - N_("Save _Template"), - "t", - N_("Replace opened Template message"), - G_CALLBACK (action_template_replace_cb) }, - - { "template-save-new", - "document-save", - N_("Save as _New Template"), - NULL, - N_("Save as Template"), - G_CALLBACK (action_template_save_new_cb) } -}; - static void templates_composer_realize_cb (EMsgComposer *composer, gpointer user_data) { EHTMLEditor *editor; - GtkActionGroup *action_group; - GtkAction *action; + EUIAction *action; const gchar *existing_folder_uri; const gchar *existing_message_uid; editor = e_msg_composer_get_editor (composer); - action_group = e_html_editor_get_action_group (editor, "composer"); - if (!action_group) - return; - - action = gtk_action_group_get_action (action_group, "template-replace"); + action = e_html_editor_get_action (editor, "template-replace"); if (!action) return; existing_folder_uri = e_msg_composer_get_header (composer, "X-Evolution-Templates-Folder", 0); existing_message_uid = e_msg_composer_get_header (composer, "X-Evolution-Templates-Message", 0); - gtk_action_set_visible (action, existing_folder_uri && *existing_folder_uri && existing_message_uid && *existing_message_uid); - gtk_action_set_sensitive (action, gtk_action_get_visible (action)); + e_ui_action_set_visible (action, existing_folder_uri && *existing_folder_uri && existing_message_uid && *existing_message_uid); + e_ui_action_set_sensitive (action, e_ui_action_get_visible (action)); } static void -templates_shell_view_update_actions_cb (EShellView *shell_view, - GtkActionGroup *action_group) +templates_update_menu (TemplatesData *td) +{ + g_return_if_fail (td != NULL); + + td->changed = FALSE; + + e_mail_templates_store_update_menu (td->templates_store, td->reply_template_menu, e_mail_reader_get_ui_manager (td->mail_reader), + action_reply_with_template_cb, td->mail_reader); +} + +static void +templates_mail_reader_update_actions_cb (EMailReader *reader, + guint state, + gpointer user_data) { TemplatesData *td; + gboolean sensitive; if (!plugin_enabled) return; - td = g_object_get_data (G_OBJECT (shell_view), TEMPLATES_DATA_KEY); - if (td) { - if (td->changed) { - EShellWindow *shell_window; - GtkUIManager *ui_manager; + td = g_object_get_data (G_OBJECT (reader), TEMPLATES_DATA_KEY); + if (td && td->changed) + templates_update_menu (td); - td->changed = FALSE; + sensitive = (state & E_MAIL_READER_SELECTION_SINGLE) != 0; - shell_window = e_shell_view_get_shell_window (shell_view); - ui_manager = e_shell_window_get_ui_manager (shell_window); - - e_mail_templates_store_build_menu (td->templates_store, shell_view, ui_manager, action_group, - "/main-menu/custom-menus/mail-message-menu/mail-reply-template", - "/mail-message-popup/mail-message-popup-common-actions/mail-popup-reply-template", - td->merge_id, - action_reply_with_template_cb, shell_view); - } - } - - gtk_action_group_set_sensitive (action_group, TRUE); - gtk_action_group_set_visible (action_group, TRUE); + e_ui_action_set_sensitive (e_mail_reader_get_action (reader, "EPluginTemplates::mail-reply-template"), sensitive); + e_ui_action_set_sensitive (e_mail_reader_get_action (reader, "template-use-this"), sensitive); } gboolean -init_composer_actions (GtkUIManager *ui_manager, +init_composer_actions (EUIManager *ui_manager, EMsgComposer *composer) { - EHTMLEditor *editor; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; - editor = e_msg_composer_get_editor (composer); + static const EUIActionEntry entries[] = { + { "template-replace", + "document-save", + N_("Save _Template"), + "t", + N_("Replace opened Template message"), + action_template_replace_cb, NULL, NULL, NULL }, - /* Add actions to the "composer" action group. */ - gtk_action_group_add_actions ( - e_html_editor_get_action_group (editor, "composer"), - composer_entries, G_N_ELEMENTS (composer_entries), composer); + { "template-save-new", + "document-save", + N_("Save as _New Template"), + NULL, + N_("Save as Template"), + action_template_save_new_cb, NULL, NULL, NULL } + }; + + e_ui_manager_add_actions_with_eui_data (ui_manager, "composer", GETTEXT_PACKAGE, + entries, G_N_ELEMENTS (entries), composer, eui); g_signal_connect (composer, "realize", G_CALLBACK (templates_composer_realize_cb), NULL); @@ -1055,6 +1071,18 @@ init_composer_actions (GtkUIManager *ui_manager, return TRUE; } +static gboolean +templates_update_menu_timeout_cb (gpointer user_data) +{ + TemplatesData *td = user_data; + + td->update_menu_id = 0; + + templates_update_menu (td); + + return G_SOURCE_REMOVE; +} + static void templates_store_changed_cb (EMailTemplatesStore *templates_store, gpointer user_data) @@ -1064,55 +1092,145 @@ templates_store_changed_cb (EMailTemplatesStore *templates_store, g_return_if_fail (td != NULL); td->changed = TRUE; + + if (td->update_immediately && !td->update_menu_id) + td->update_menu_id = g_timeout_add (100, templates_update_menu_timeout_cb, td); +} + +static gboolean +templates_ui_manager_create_item_cb (EUIManager *ui_manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + GMenuModel *reply_template_menu = user_data; + const gchar *name; + + g_return_val_if_fail (G_IS_MENU (reply_template_menu), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "EPluginTemplates::")) + return FALSE; + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (is_action ("EPluginTemplates::mail-reply-template")) { + *out_item = e_ui_manager_create_item_from_menu_model (ui_manager, elem, action, for_kind, reply_template_menu); + } else if (for_kind == E_UI_ELEMENT_KIND_MENU) { + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + #undef is_action + + return TRUE; } static void -mail_shell_view_created_cb (EShellWindow *shell_window, - EShellView *shell_view) +init_actions_for_mail_backend (EMailBackend *mail_backend, + EUIManager *ui_manager, + EMailReader *mail_reader, + gboolean update_immediately) { - EMailBackend *backend; + static const gchar *eui = + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + ""; + + static const EUIActionEntry entries[] = { + { "EPluginTemplates::mail-reply-template", NULL, N_("Repl_y with Template"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + EMailSession *session; - EShellBackend *shell_backend; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; TemplatesData *td; - ui_manager = e_shell_window_get_ui_manager (shell_window); - e_shell_window_add_action_group_full (shell_window, "templates", "mail"); - action_group = e_lookup_action_group (ui_manager, "templates"); - - shell_backend = e_shell_view_get_shell_backend (shell_view); - - backend = E_MAIL_BACKEND (shell_backend); - session = e_mail_backend_get_session (backend); + session = e_mail_backend_get_session (mail_backend); td = g_new0 (TemplatesData, 1); td->templates_store = e_mail_templates_store_ref_default (e_mail_ui_session_get_account_store (E_MAIL_UI_SESSION (session))); + td->mail_reader = g_object_ref (mail_reader); + td->reply_template_menu = g_menu_new (); td->changed_handler_id = g_signal_connect (td->templates_store, "changed", G_CALLBACK (templates_store_changed_cb), td); - td->merge_id = gtk_ui_manager_new_merge_id (ui_manager); td->changed = TRUE; + td->update_immediately = update_immediately; - g_object_set_data_full (G_OBJECT (shell_view), TEMPLATES_DATA_KEY, td, templates_data_free); + g_object_set_data_full (G_OBJECT (mail_reader), TEMPLATES_DATA_KEY, td, templates_data_free); - g_signal_connect ( - shell_view, "update-actions", - G_CALLBACK (templates_shell_view_update_actions_cb), action_group); + g_signal_connect_data (ui_manager, "create-item", + G_CALLBACK (templates_ui_manager_create_item_cb), g_object_ref (td->reply_template_menu), + (GClosureNotify) g_object_unref, 0); + + e_ui_manager_add_actions_with_eui_data (ui_manager, "templates", NULL, + entries, G_N_ELEMENTS (entries), td, eui); + + templates_update_menu (td); } gboolean -init_shell_actions (GtkUIManager *ui_manager, - EShellWindow *shell_window) +init_mail_actions (EUIManager *ui_manager, + EShellView *shell_view) { - EShellView *shell_view; + EShellBackend *shell_backend; + EShellContent *shell_content; + EMailView *mail_view = NULL; + + shell_backend = e_shell_view_get_shell_backend (shell_view); + shell_content = e_shell_view_get_shell_content (shell_view); + + g_object_get (shell_content, "mail-view", &mail_view, NULL); + if (mail_view) { + init_actions_for_mail_backend (E_MAIL_BACKEND (shell_backend), ui_manager, E_MAIL_READER (mail_view), FALSE); - /* Be careful not to instantiate the mail view ourselves. */ - shell_view = e_shell_window_peek_shell_view (shell_window, "mail"); - if (shell_view != NULL) - mail_shell_view_created_cb (shell_window, shell_view); - else g_signal_connect ( - shell_window, "shell-view-created::mail", - G_CALLBACK (mail_shell_view_created_cb), NULL); + mail_view, "update-actions", + G_CALLBACK (templates_mail_reader_update_actions_cb), NULL); + + g_clear_object (&mail_view); + } + + return TRUE; +} + +gboolean +init_mail_browser_actions (EUIManager *ui_manager, + EMailBrowser *mail_browser) +{ + EMailReader *reader = E_MAIL_READER (mail_browser); + + init_actions_for_mail_backend (e_mail_reader_get_backend (reader), ui_manager, reader, TRUE); return TRUE; } diff --git a/src/shell/CMakeLists.txt b/src/shell/CMakeLists.txt index 735c205745..fac4e9987c 100644 --- a/src/shell/CMakeLists.txt +++ b/src/shell/CMakeLists.txt @@ -19,7 +19,6 @@ set(SOURCES e-shell-backend.c e-shell-content.c e-shell-enumtypes.c - e-shell-headerbar.c e-shell-searchbar.c e-shell-sidebar.c e-shell-switcher.c @@ -41,7 +40,6 @@ set(HEADERS e-shell-backend.h e-shell-common.h e-shell-content.h - e-shell-headerbar.h e-shell-searchbar.h e-shell-sidebar.h e-shell-switcher.h diff --git a/src/shell/e-shell-headerbar.c b/src/shell/e-shell-headerbar.c deleted file mode 100644 index a8746f616b..0000000000 --- a/src/shell/e-shell-headerbar.c +++ /dev/null @@ -1,326 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * SPDX-FileCopyrightText: (C) 2022 Cédric Bellegarde - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "evolution-config.h" - -#include "e-util/e-util.h" -#include "e-shell-headerbar.h" -#include "e-shell-window-private.h" - -#include - -struct _EShellHeaderBarPrivate { - GWeakRef shell_window; - GtkWidget *menu_button; - GtkWidget *new_button; - - gulong prefered_item_notify_id; -}; - -enum { - PROP_0, - PROP_MENU_BUTTON, - PROP_SHELL_WINDOW -}; - -G_DEFINE_TYPE_WITH_CODE (EShellHeaderBar, e_shell_header_bar, E_TYPE_HEADER_BAR, - G_ADD_PRIVATE (EShellHeaderBar)) - -static void -shell_header_bar_clear_box (GList *children, - const gchar *name) -{ - GList *iter; - const gchar *widget_name; - - for (iter = children; iter != NULL; iter = g_list_next (iter)) { - GtkWidget *widget = iter->data; - - widget_name = gtk_widget_get_name (widget); - if (widget_name != NULL && g_str_has_prefix (widget_name, name)) - gtk_widget_destroy (widget); - } -} - -static EShellWindow * -shell_header_bar_dup_shell_window (EShellHeaderBar *headerbar) -{ - g_return_val_if_fail (E_IS_SHELL_HEADER_BAR (headerbar), NULL); - - return g_weak_ref_get (&headerbar->priv->shell_window); -} - -static void -shell_header_bar_set_menu_button (EShellHeaderBar *headerbar, - GtkWidget *menu_button) -{ - g_return_if_fail (GTK_IS_WIDGET (menu_button)); - g_return_if_fail (headerbar->priv->menu_button == NULL); - - headerbar->priv->menu_button = g_object_ref_sink (menu_button); -} - -static void -shell_header_bar_set_shell_window (EShellHeaderBar *headerbar, - EShellWindow *shell_window) -{ - EShellWindow *priv_shell_window = shell_header_bar_dup_shell_window (headerbar); - - /* This should be always NULL, but for a sake of completeness - and no memory leak do unref it here. Also do *not* use - g_clear_object(), because the non-NULL is tested below. */ - if (priv_shell_window) - g_object_unref (priv_shell_window); - - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - g_return_if_fail (priv_shell_window == NULL); - - g_weak_ref_set ( - &headerbar->priv->shell_window, - G_OBJECT (shell_window)); -} - -static void -shell_header_bar_update_new_menu (EShellWindow *shell_window, - gpointer user_data) -{ - EShellHeaderBar *headerbar = user_data; - GtkWidget *menu; - - /* Update the "New" menu button submenu. */ - menu = e_shell_window_create_new_menu (shell_window); - e_header_bar_button_take_menu (E_HEADER_BAR_BUTTON (headerbar->priv->new_button), menu); -} - -static void -shell_header_bar_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_MENU_BUTTON: - shell_header_bar_set_menu_button ( - E_SHELL_HEADER_BAR (object), - g_value_get_object (value)); - return; - - case PROP_SHELL_WINDOW: - shell_header_bar_set_shell_window ( - E_SHELL_HEADER_BAR (object), - g_value_get_object (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -shell_header_bar_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_SHELL_WINDOW: - g_value_take_object ( - value, shell_header_bar_dup_shell_window ( - E_SHELL_HEADER_BAR (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -shell_header_bar_constructed (GObject *object) -{ - EShellHeaderBar *self = E_SHELL_HEADER_BAR (object); - EShellWindow *shell_window; - GtkUIManager *ui_manager; - GtkWidget *new_button; - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_shell_header_bar_parent_class)->constructed (object); - - shell_window = shell_header_bar_dup_shell_window (self); - - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - ui_manager = e_shell_window_get_ui_manager (shell_window); - - new_button = e_header_bar_button_new (C_("toolbar-button", "New"), NULL); - /* show label also on the New button, but only if all other buttons have space for their label */ - e_header_bar_pack_start (E_HEADER_BAR (self), new_button, G_MAXUINT); - gtk_widget_show (new_button); - self->priv->new_button = g_object_ref (new_button); - - if (self->priv->menu_button) - e_header_bar_pack_end (E_HEADER_BAR (self), self->priv->menu_button, G_MAXUINT); - - e_header_bar_button_add_accelerator ( - E_HEADER_BAR_BUTTON (self->priv->new_button), - gtk_ui_manager_get_accel_group (ui_manager), - GDK_KEY_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); - - self->priv->prefered_item_notify_id = g_signal_connect ( - shell_window, "update-new-menu", - G_CALLBACK (shell_header_bar_update_new_menu), self); - - g_object_unref (shell_window); -} - -static void -shell_header_bar_dispose (GObject *object) -{ - EShellHeaderBar *headerbar = E_SHELL_HEADER_BAR (object); - - if (headerbar->priv->new_button != NULL) { - EShellWindow *shell_window = shell_header_bar_dup_shell_window (headerbar); - - if (shell_window) { - g_signal_handler_disconnect ( - shell_window, - headerbar->priv->prefered_item_notify_id); - g_object_unref (headerbar->priv->new_button); - - g_object_unref (shell_window); - } - - headerbar->priv->new_button = NULL; - headerbar->priv->prefered_item_notify_id = 0; - } - - g_clear_object (&headerbar->priv->menu_button); - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_shell_header_bar_parent_class)->dispose (object); -} - -static void -shell_header_bar_finalize (GObject *object) -{ - EShellHeaderBar *self = E_SHELL_HEADER_BAR (object); - - g_weak_ref_clear (&self->priv->shell_window); - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_shell_header_bar_parent_class)->finalize (object); -} - -static void -e_shell_header_bar_class_init (EShellHeaderBarClass *klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - object_class->set_property = shell_header_bar_set_property; - object_class->get_property = shell_header_bar_get_property; - object_class->constructed = shell_header_bar_constructed; - object_class->dispose = shell_header_bar_dispose; - object_class->finalize = shell_header_bar_finalize; - - g_object_class_install_property ( - object_class, - PROP_MENU_BUTTON, - g_param_spec_object ( - "menu-button", - "Menu Button", - "Menu button to add to the header bar", - GTK_TYPE_WIDGET, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_EXPLICIT_NOTIFY | - G_PARAM_STATIC_STRINGS)); - - /** - * EShellHeaderbar:shell-window - * - * The #EShellWindow to which the headerbar belongs. - **/ - g_object_class_install_property ( - object_class, - PROP_SHELL_WINDOW, - g_param_spec_object ( - "shell-window", - "Shell Window", - "The window to which the headerbar belongs", - E_TYPE_SHELL_WINDOW, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_EXPLICIT_NOTIFY | - G_PARAM_STATIC_STRINGS)); -} - -static void -e_shell_header_bar_init (EShellHeaderBar *self) -{ - self->priv = e_shell_header_bar_get_instance_private (self); - g_weak_ref_init (&self->priv->shell_window, NULL); -} - -/** - * e_shell_header_bar_new: - * @shel_window: The #EShellWindow to which the headerbar belongs - * @menu_button: a menu button to add to the header bar - * - * Creates a new #EShellHeaderBar - * - * Returns: (transfer full): a new #EShellHeaderBar - * - * Since: 3.46 - **/ -GtkWidget * -e_shell_header_bar_new (EShellWindow *shell_window, - GtkWidget *menu_button) -{ - return g_object_new (E_TYPE_SHELL_HEADER_BAR, - "shell-window", shell_window, - "menu-button", menu_button, - NULL); -} - -/** - * e_shell_header_bar_get_new_button: - * @headerbar: an #EShellHeaderBar - * - * Returns: (transfer none): the 'New' button widget, which is #EHeaderBarButton - * - * Since: 3.46 - **/ -GtkWidget * -e_shell_header_bar_get_new_button (EShellHeaderBar *headerbar) -{ - g_return_val_if_fail (E_IS_SHELL_HEADER_BAR (headerbar), NULL); - - return headerbar->priv->new_button; -} - -/** - * e_shell_header_bar_clear: - * @headerbar: an #EShellHeaderBar - * @name: widget name starts with - * - * Removes all widgets from the header bar where widget name starts with @name - * - * Since: 3.46 - **/ -void -e_shell_header_bar_clear (EShellHeaderBar *headerbar, - const gchar *name) -{ - GList *children; - - g_return_if_fail (E_IS_SHELL_HEADER_BAR (headerbar)); - - children = e_header_bar_get_start_widgets (E_HEADER_BAR (headerbar)); - shell_header_bar_clear_box (children, name); - g_list_free (children); - - children = e_header_bar_get_end_widgets (E_HEADER_BAR (headerbar)); - shell_header_bar_clear_box (children, name); - g_list_free (children); -} diff --git a/src/shell/e-shell-headerbar.h b/src/shell/e-shell-headerbar.h deleted file mode 100644 index 00815f039c..0000000000 --- a/src/shell/e-shell-headerbar.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * SPDX-FileCopyrightText: (C) 2022 Cédric Bellegarde - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#ifndef E_SHELL_HEADER_BAR_H -#define E_SHELL_HEADER_BAR_H - -#include - -#include -#include - -#define E_TYPE_SHELL_HEADER_BAR \ - (e_shell_header_bar_get_type ()) -#define E_SHELL_HEADER_BAR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_SHELL_HEADER_BAR, EShellHeaderBar)) -#define E_SHELL_HEADER_BAR_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_SHELL_HEADER_BAR, EShellHeaderBarClass)) -#define E_IS_SHELL_HEADER_BAR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_SHELL_HEADER_BAR)) -#define E_IS_SHELL_HEADER_BAR_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_SHELL_HEADER_BAR)) -#define E_SHELL_HEADER_BAR_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_SHELL_HEADER_BAR, EShellHeaderBarClass)) - -G_BEGIN_DECLS - -typedef struct _EShellHeaderBar EShellHeaderBar; -typedef struct _EShellHeaderBarClass EShellHeaderBarClass; -typedef struct _EShellHeaderBarPrivate EShellHeaderBarPrivate; - -struct _EShellHeaderBar { - EHeaderBar parent; - EShellHeaderBarPrivate *priv; -}; - -struct _EShellHeaderBarClass { - EHeaderBarClass parent_class; -}; - -GType e_shell_header_bar_get_type (void); -GtkWidget * e_shell_header_bar_new (EShellWindow *shell_window, - GtkWidget *menu_button); -GtkWidget * e_shell_header_bar_get_new_button (EShellHeaderBar *headerbar); -void e_shell_header_bar_clear (EShellHeaderBar *headerbar, - const gchar *name); -G_END_DECLS - -#endif /* E_SHELL_HEADER_BAR_H */ diff --git a/src/shell/e-shell-searchbar.c b/src/shell/e-shell-searchbar.c index f8065c71ec..62bdbe8ce7 100644 --- a/src/shell/e-shell-searchbar.c +++ b/src/shell/e-shell-searchbar.c @@ -47,7 +47,7 @@ struct _EShellSearchbarPrivate { gpointer shell_view; /* weak pointer */ - GtkRadioAction *search_option; + EUIAction *search_option; EFilterRule *search_rule; GtkCssProvider *css_provider; @@ -83,68 +83,76 @@ G_DEFINE_TYPE_WITH_CODE (EShellSearchbar, e_shell_searchbar, GTK_TYPE_BOX, G_ADD_PRIVATE (EShellSearchbar) G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)) +static EUIAction * +shell_searchbar_radio_action_get_current_action (EUIAction *group_action) +{ + GPtrArray *radio_group; + guint ii; + + radio_group = e_ui_action_get_radio_group (group_action); + + if (!radio_group) + return group_action; + + for (ii = 0; ii < radio_group->len; ii++) { + EUIAction *action = g_ptr_array_index (radio_group, ii); + + if (e_ui_action_get_active (action)) + return action; + } + + return group_action; +} + static void -shell_searchbar_save_search_filter (EShellSearchbar *searchbar) +shell_searchbar_save_current_action (EShellSearchbar *searchbar, + const gchar *key, + EUIAction *action) { EShellView *shell_view; - EActionComboBox *action_combo_box; - GtkRadioAction *radio_action; GKeyFile *key_file; const gchar *action_name; const gchar *state_group; - const gchar *key; shell_view = e_shell_searchbar_get_shell_view (searchbar); state_group = e_shell_searchbar_get_state_group (searchbar); g_return_if_fail (state_group != NULL); - key = STATE_KEY_SEARCH_FILTER; key_file = e_shell_view_get_state_key_file (shell_view); - action_combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); - radio_action = e_action_combo_box_get_action (action_combo_box); + if (action != NULL) + action = shell_searchbar_radio_action_get_current_action (action); - if (radio_action != NULL) - radio_action = e_radio_action_get_current_action (radio_action); - - if (radio_action != NULL) { - action_name = gtk_action_get_name (GTK_ACTION (radio_action)); + if (action) { + action_name = g_action_get_name (G_ACTION (action)); g_key_file_set_string (key_file, state_group, key, action_name); - } else + } else { g_key_file_remove_key (key_file, state_group, key, NULL); + } e_shell_view_set_state_dirty (shell_view); } +static void +shell_searchbar_save_search_filter (EShellSearchbar *searchbar) +{ + EActionComboBox *action_combo_box; + EUIAction *action; + + action_combo_box = e_shell_searchbar_get_filter_combo_box (searchbar); + action = e_action_combo_box_get_action (action_combo_box); + + shell_searchbar_save_current_action (searchbar, STATE_KEY_SEARCH_FILTER, action); +} + static void shell_searchbar_save_search_option (EShellSearchbar *searchbar) { - EShellView *shell_view; - GtkRadioAction *radio_action; - GKeyFile *key_file; - const gchar *action_name; - const gchar *state_group; - const gchar *key; + EUIAction *action; - shell_view = e_shell_searchbar_get_shell_view (searchbar); - state_group = e_shell_searchbar_get_state_group (searchbar); - g_return_if_fail (state_group != NULL); + action = e_shell_searchbar_get_search_option (searchbar); - key = STATE_KEY_SEARCH_OPTION; - key_file = e_shell_view_get_state_key_file (shell_view); - - radio_action = e_shell_searchbar_get_search_option (searchbar); - - if (radio_action != NULL) - radio_action = e_radio_action_get_current_action (radio_action); - - if (radio_action != NULL) { - action_name = gtk_action_get_name (GTK_ACTION (radio_action)); - g_key_file_set_string (key_file, state_group, key, action_name); - } else - g_key_file_remove_key (key_file, state_group, key, NULL); - - e_shell_view_set_state_dirty (shell_view); + shell_searchbar_save_current_action (searchbar, STATE_KEY_SEARCH_OPTION, action); } static void @@ -176,41 +184,19 @@ shell_searchbar_save_search_text (EShellSearchbar *searchbar) static void shell_searchbar_save_search_scope (EShellSearchbar *searchbar) { - EShellView *shell_view; EActionComboBox *action_combo_box; - GtkRadioAction *radio_action; - GKeyFile *key_file; - const gchar *action_name; - const gchar *state_group; - const gchar *key; - - shell_view = e_shell_searchbar_get_shell_view (searchbar); - state_group = e_shell_searchbar_get_state_group (searchbar); - g_return_if_fail (state_group != NULL); - - key = STATE_KEY_SEARCH_SCOPE; - key_file = e_shell_view_get_state_key_file (shell_view); + EUIAction *action; action_combo_box = e_shell_searchbar_get_scope_combo_box (searchbar); - radio_action = e_action_combo_box_get_action (action_combo_box); + action = e_action_combo_box_get_action (action_combo_box); - if (radio_action != NULL) - radio_action = e_radio_action_get_current_action (radio_action); - - if (radio_action != NULL) { - action_name = gtk_action_get_name (GTK_ACTION (radio_action)); - g_key_file_set_string (key_file, state_group, key, action_name); - } else - g_key_file_remove_key (key_file, state_group, key, NULL); - - e_shell_view_set_state_dirty (shell_view); + shell_searchbar_save_current_action (searchbar, STATE_KEY_SEARCH_SCOPE, action); } static void shell_searchbar_update_search_widgets (EShellSearchbar *searchbar) { EShellView *shell_view; - EShellWindow *shell_window; GtkWidget *widget; const gchar *search_text; gboolean sensitive; @@ -220,7 +206,6 @@ shell_searchbar_update_search_widgets (EShellSearchbar *searchbar) widget = searchbar->priv->search_entry; shell_view = e_shell_searchbar_get_shell_view (searchbar); - shell_window = e_shell_view_get_shell_window (shell_view); search_text = e_shell_searchbar_get_search_text (searchbar); sensitive = @@ -253,13 +238,13 @@ shell_searchbar_update_search_widgets (EShellSearchbar *searchbar) } if (e_shell_view_is_active (shell_view)) { - GtkAction *action; + EUIAction *action; - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); - gtk_action_set_sensitive (action, sensitive); + action = e_shell_view_get_action (shell_view, "search-clear"); + e_ui_action_set_sensitive (action, sensitive); - action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window); - gtk_action_set_visible (action, sensitive && e_shell_view_get_search_rule (shell_view) != NULL); + action = e_shell_view_get_action (shell_view, "search-save"); + e_ui_action_set_visible (action, sensitive && e_shell_view_get_search_rule (shell_view) != NULL); } } @@ -267,7 +252,8 @@ static void shell_searchbar_clear_search_cb (EShellView *shell_view, EShellSearchbar *searchbar) { - GtkRadioAction *search_option; + EUIAction *search_option; + GVariant *state; gint current_value; e_shell_searchbar_set_search_text (searchbar, NULL); @@ -276,10 +262,13 @@ shell_searchbar_clear_search_cb (EShellView *shell_view, if (search_option == NULL) return; + state = g_action_get_state (G_ACTION (search_option)); + current_value = state ? g_variant_get_int32 (state) : -1; + g_clear_pointer (&state, g_variant_unref); + /* Reset the search option if it's set to advanced search. */ - current_value = gtk_radio_action_get_current_value (search_option); if (current_value == SEARCH_OPTION_ADVANCED) - gtk_radio_action_set_current_value (search_option, 0); + e_ui_action_set_state (search_option, g_variant_new_int32 (0)); } static void @@ -287,14 +276,14 @@ shell_searchbar_custom_search_cb (EShellView *shell_view, EFilterRule *custom_rule, EShellSearchbar *searchbar) { - GtkRadioAction *search_option; + EUIAction *search_option; gint value = SEARCH_OPTION_ADVANCED; e_shell_searchbar_set_search_text (searchbar, NULL); search_option = e_shell_searchbar_get_search_option (searchbar); if (search_option != NULL) - gtk_radio_action_set_current_value (search_option, value); + e_ui_action_set_state (search_option, g_variant_new_int32 (value)); } static void @@ -341,44 +330,40 @@ static void shell_searchbar_entry_activate_cb (EShellSearchbar *searchbar) { EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; + EUIAction *action; const gchar *search_text; shell_view = e_shell_searchbar_get_shell_view (searchbar); - shell_window = e_shell_view_get_shell_window (shell_view); search_text = e_shell_searchbar_get_search_text (searchbar); if (search_text != NULL && *search_text != '\0') - action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); + action = e_shell_view_get_action (shell_view, "search-quick"); else - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); + action = e_shell_view_get_action (shell_view, "search-clear"); - gtk_action_activate (action); + g_action_activate (G_ACTION (action), NULL); } static void shell_searchbar_entry_changed_cb (EShellSearchbar *searchbar) { EShellView *shell_view; - EShellWindow *shell_window; const gchar *search_text; gboolean sensitive; shell_view = e_shell_searchbar_get_shell_view (searchbar); - shell_window = e_shell_view_get_shell_window (shell_view); search_text = e_shell_searchbar_get_search_text (searchbar); sensitive = (search_text != NULL && *search_text != '\0'); if (e_shell_view_is_active (shell_view)) { - GtkAction *action; + EUIAction *action; - action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); - gtk_action_set_sensitive (action, sensitive); + action = e_shell_view_get_action (shell_view, "search-quick"); + e_ui_action_set_sensitive (action, sensitive); - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); - gtk_action_set_sensitive (action, sensitive || + action = e_shell_view_get_action (shell_view, "search-clear"); + e_ui_action_set_sensitive (action, sensitive || (searchbar->priv->active_search_text && *searchbar->priv->active_search_text) || e_shell_view_get_search_rule (shell_view) != NULL); } @@ -402,8 +387,7 @@ shell_searchbar_entry_icon_press_cb (EShellSearchbar *searchbar, GdkEvent *event) { EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; + EUIAction *action; /* Show the search options menu when the icon is pressed. */ @@ -411,10 +395,9 @@ shell_searchbar_entry_icon_press_cb (EShellSearchbar *searchbar, return; shell_view = e_shell_searchbar_get_shell_view (searchbar); - shell_window = e_shell_view_get_shell_window (shell_view); - action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); - gtk_action_activate (action); + action = e_shell_view_get_action (shell_view, "search-options"); + g_action_activate (G_ACTION (action), NULL); } static void @@ -423,8 +406,7 @@ shell_searchbar_entry_icon_release_cb (EShellSearchbar *searchbar, GdkEvent *event) { EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; + EUIAction *action; /* Clear the search when the icon is pressed and released. */ @@ -432,10 +414,9 @@ shell_searchbar_entry_icon_release_cb (EShellSearchbar *searchbar, return; shell_view = e_shell_searchbar_get_shell_view (searchbar); - shell_window = e_shell_view_get_shell_window (shell_view); - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); - gtk_action_activate (action); + action = e_shell_view_get_action (shell_view, "search-clear"); + g_action_activate (G_ACTION (action), NULL); } static gboolean @@ -444,8 +425,7 @@ shell_searchbar_entry_key_press_cb (EShellSearchbar *searchbar, GtkWindow *entry) { EShellView *shell_view; - EShellWindow *shell_window; - GtkAction *action; + EUIAction *action; guint mask; mask = gtk_accelerator_get_default_mod_mask (); @@ -456,30 +436,35 @@ shell_searchbar_entry_key_press_cb (EShellSearchbar *searchbar, return FALSE; shell_view = e_shell_searchbar_get_shell_view (searchbar); - shell_window = e_shell_view_get_shell_window (shell_view); - action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); - gtk_action_activate (action); + action = e_shell_view_get_action (shell_view, "search-options"); + g_action_activate (G_ACTION (action), NULL); return TRUE; } static void -shell_searchbar_option_changed_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellSearchbar *searchbar) +shell_searchbar_option_notify_state_cb (EUIAction *action, + GParamSpec *param, + EShellSearchbar *searchbar) { EShellView *shell_view; + EUIAction *current; const gchar *search_text; const gchar *label; + GVariant *state; gint current_value; - shell_view = e_shell_searchbar_get_shell_view (searchbar); + state = g_action_get_state (G_ACTION (action)); + current_value = state ? g_variant_get_int32 (state) : -1; + g_clear_pointer (&state, g_variant_unref); - label = gtk_action_get_label (GTK_ACTION (current)); + shell_view = e_shell_searchbar_get_shell_view (searchbar); + current = shell_searchbar_radio_action_get_current_action (action); + + label = e_ui_action_get_label (current); e_shell_searchbar_set_search_hint (searchbar, label); - current_value = gtk_radio_action_get_current_value (current); search_text = e_shell_searchbar_get_search_text (searchbar); if (current_value != SEARCH_OPTION_ADVANCED) { @@ -691,15 +676,12 @@ static void shell_searchbar_constructed (GObject *object) { EShellView *shell_view; - EShellWindow *shell_window; EShellSearchbar *searchbar; GtkSizeGroup *size_group; - GtkAction *action; GtkWidget *widget; searchbar = E_SHELL_SEARCHBAR (object); shell_view = e_shell_searchbar_get_shell_view (searchbar); - shell_window = e_shell_view_get_shell_window (shell_view); size_group = e_shell_view_get_size_group (shell_view); g_signal_connect ( @@ -734,36 +716,6 @@ shell_searchbar_constructed (GObject *object) GTK_STYLE_PROVIDER (searchbar->priv->css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window); - - e_binding_bind_property ( - action, "sensitive", - widget, "secondary-icon-sensitive", - G_BINDING_SYNC_CREATE); - e_binding_bind_property ( - action, "icon-name", - widget, "secondary-icon-name", - G_BINDING_SYNC_CREATE); - e_binding_bind_property ( - action, "tooltip", - widget, "secondary-icon-tooltip-text", - G_BINDING_SYNC_CREATE); - - action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window); - - e_binding_bind_property ( - action, "sensitive", - widget, "primary-icon-sensitive", - G_BINDING_SYNC_CREATE); - e_binding_bind_property ( - action, "icon-name", - widget, "primary-icon-name", - G_BINDING_SYNC_CREATE); - e_binding_bind_property ( - action, "tooltip", - widget, "primary-icon-tooltip-text", - G_BINDING_SYNC_CREATE); - widget = GTK_WIDGET (searchbar); gtk_size_group_add_widget (size_group, widget); @@ -842,7 +794,7 @@ e_shell_searchbar_class_init (EShellSearchbarClass *class) "search-option", NULL, NULL, - GTK_TYPE_RADIO_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -1095,6 +1047,47 @@ e_shell_searchbar_get_shell_view (EShellSearchbar *searchbar) return E_SHELL_VIEW (searchbar->priv->shell_view); } +void +e_shell_searchbar_init_ui_data (EShellSearchbar *searchbar) +{ + EShellView *shell_view; + EUIAction *action; + + g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); + + shell_view = e_shell_searchbar_get_shell_view (searchbar); + + action = e_shell_view_get_action (shell_view, "search-clear"); + + e_binding_bind_property ( + action, "sensitive", + searchbar->priv->search_entry, "secondary-icon-sensitive", + G_BINDING_SYNC_CREATE); + e_binding_bind_property ( + action, "icon-name", + searchbar->priv->search_entry, "secondary-icon-name", + G_BINDING_SYNC_CREATE); + e_binding_bind_property ( + action, "tooltip", + searchbar->priv->search_entry, "secondary-icon-tooltip-text", + G_BINDING_SYNC_CREATE); + + action = e_shell_view_get_action (shell_view, "search-options"); + + e_binding_bind_property ( + action, "sensitive", + searchbar->priv->search_entry, "primary-icon-sensitive", + G_BINDING_SYNC_CREATE); + e_binding_bind_property ( + action, "icon-name", + searchbar->priv->search_entry, "primary-icon-name", + G_BINDING_SYNC_CREATE); + e_binding_bind_property ( + action, "tooltip", + searchbar->priv->search_entry, "primary-icon-tooltip-text", + G_BINDING_SYNC_CREATE); +} + EActionComboBox * e_shell_searchbar_get_filter_combo_box (EShellSearchbar *searchbar) { @@ -1164,7 +1157,7 @@ e_shell_searchbar_set_search_hint (EShellSearchbar *searchbar, g_object_notify (G_OBJECT (searchbar), "search-hint"); } -GtkRadioAction * +EUIAction * e_shell_searchbar_get_search_option (EShellSearchbar *searchbar) { g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL); @@ -1174,7 +1167,7 @@ e_shell_searchbar_get_search_option (EShellSearchbar *searchbar) void e_shell_searchbar_set_search_option (EShellSearchbar *searchbar, - GtkRadioAction *search_option) + EUIAction *search_option) { g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); @@ -1182,7 +1175,7 @@ e_shell_searchbar_set_search_option (EShellSearchbar *searchbar, return; if (search_option != NULL) { - g_return_if_fail (GTK_IS_RADIO_ACTION (search_option)); + g_return_if_fail (E_IS_UI_ACTION (search_option)); g_object_ref (search_option); } @@ -1196,12 +1189,15 @@ e_shell_searchbar_set_search_option (EShellSearchbar *searchbar, searchbar->priv->search_option = search_option; - if (search_option != NULL) + if (search_option != NULL) { g_signal_connect ( - search_option, "changed", - G_CALLBACK (shell_searchbar_option_changed_cb), + search_option, "notify::state", + G_CALLBACK (shell_searchbar_option_notify_state_cb), searchbar); + shell_searchbar_option_notify_state_cb (search_option, NULL, searchbar); + } + g_object_notify (G_OBJECT (searchbar), "search-option"); } @@ -1342,15 +1338,14 @@ void e_shell_searchbar_load_state (EShellSearchbar *searchbar) { EShellView *shell_view; - EShellWindow *shell_window; GKeyFile *key_file; - GtkAction *action; + EUIAction *action; GtkWidget *widget; const gchar *search_text; const gchar *state_group; const gchar *key; gchar *string; - gint value = 0; + gint value; g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar)); @@ -1359,13 +1354,9 @@ e_shell_searchbar_load_state (EShellSearchbar *searchbar) g_return_if_fail (state_group != NULL); key_file = e_shell_view_get_state_key_file (shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); /* Changing the combo boxes triggers searches, so block * the search action until the state is fully restored. */ - action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); - gtk_action_block_activate (action); - e_shell_view_block_execute_search (shell_view); e_shell_view_set_search_rule (shell_view, NULL); @@ -1373,12 +1364,12 @@ e_shell_searchbar_load_state (EShellSearchbar *searchbar) key = STATE_KEY_SEARCH_FILTER; string = g_key_file_get_string (key_file, state_group, key, NULL); if (string != NULL && *string != '\0') - action = e_shell_window_get_action (shell_window, string); + action = e_shell_view_get_action (shell_view, string); else action = NULL; - if (GTK_IS_RADIO_ACTION (action)) - gtk_action_activate (action); - else { + if (action) { + e_ui_action_set_active (action, TRUE); + } else { /* Pick the first combo box item. */ widget = searchbar->priv->filter_combo_box; gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); @@ -1390,18 +1381,24 @@ e_shell_searchbar_load_state (EShellSearchbar *searchbar) key = STATE_KEY_SEARCH_OPTION; string = g_key_file_get_string (key_file, state_group, key, NULL); if (string != NULL && *string != '\0') - action = e_shell_window_get_action (shell_window, string); + action = e_shell_view_get_action (shell_view, string); else action = NULL; - if (GTK_IS_RADIO_ACTION (action)) - g_object_get (action, "value", &value, NULL); - else + value = SEARCH_OPTION_ADVANCED; + if (action) { + GVariant *target; + + target = e_ui_action_ref_target (action); + if (target) + value = g_variant_get_int32 (target); + g_clear_pointer (&target, g_variant_unref); + } else { value = SEARCH_OPTION_ADVANCED; + } if (value != SEARCH_OPTION_ADVANCED) - gtk_action_activate (action); + e_ui_action_set_active (action, TRUE); else if (searchbar->priv->search_option != NULL) - gtk_radio_action_set_current_value ( - searchbar->priv->search_option, 0); + e_ui_action_set_state (searchbar->priv->search_option, g_variant_new_int32 (0)); g_free (string); key = STATE_KEY_SEARCH_TEXT; @@ -1416,12 +1413,12 @@ e_shell_searchbar_load_state (EShellSearchbar *searchbar) key = STATE_KEY_SEARCH_SCOPE; string = g_key_file_get_string (key_file, state_group, key, NULL); if (string != NULL && *string != '\0') - action = e_shell_window_get_action (shell_window, string); + action = e_shell_view_get_action (shell_view, string); else action = NULL; - if (GTK_IS_RADIO_ACTION (action)) - gtk_action_activate (action); - else { + if (action) { + e_ui_action_set_active (action, TRUE); + } else { /* Pick the first combo box item. */ widget = searchbar->priv->scope_combo_box; gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0); @@ -1430,9 +1427,6 @@ e_shell_searchbar_load_state (EShellSearchbar *searchbar) e_shell_view_unblock_execute_search (shell_view); - action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window); - gtk_action_unblock_activate (action); - /* Execute the search when we have time. */ g_object_ref (shell_view); diff --git a/src/shell/e-shell-searchbar.h b/src/shell/e-shell-searchbar.h index 28069ed9e7..d3fd68c61e 100644 --- a/src/shell/e-shell-searchbar.h +++ b/src/shell/e-shell-searchbar.h @@ -66,6 +66,7 @@ struct _EShellSearchbarClass { GType e_shell_searchbar_get_type (void); GtkWidget * e_shell_searchbar_new (EShellView *shell_view); +void e_shell_searchbar_init_ui_data (EShellSearchbar *searchbar); EShellView * e_shell_searchbar_get_shell_view (EShellSearchbar *searchbar); EActionComboBox * @@ -81,11 +82,11 @@ const gchar * e_shell_searchbar_get_search_hint void e_shell_searchbar_set_search_hint (EShellSearchbar *searchbar, const gchar *search_hint); -GtkRadioAction *e_shell_searchbar_get_search_option +EUIAction * e_shell_searchbar_get_search_option (EShellSearchbar *searchbar); void e_shell_searchbar_set_search_option (EShellSearchbar *searchbar, - GtkRadioAction *search_option); + EUIAction *search_option); const gchar * e_shell_searchbar_get_search_text (EShellSearchbar *searchbar); void e_shell_searchbar_set_search_text diff --git a/src/shell/e-shell-sidebar.c b/src/shell/e-shell-sidebar.c index 4619732f3f..ff0b826aab 100644 --- a/src/shell/e-shell-sidebar.c +++ b/src/shell/e-shell-sidebar.c @@ -188,26 +188,19 @@ shell_sidebar_constructed (GObject *object) EShellView *shell_view; EShellSidebar *shell_sidebar; GtkSizeGroup *size_group; - GtkAction *action; + EUIAction *action; GtkWidget *widget; - gchar *label; - gchar *icon_name; shell_sidebar = E_SHELL_SIDEBAR (object); shell_view = e_shell_sidebar_get_shell_view (shell_sidebar); size_group = e_shell_view_get_size_group (shell_view); - action = e_shell_view_get_action (shell_view); + action = e_shell_view_get_switcher_action (shell_view); widget = shell_sidebar->priv->event_box; gtk_size_group_add_widget (size_group, widget); - g_object_get (action, "icon-name", &icon_name, NULL); - e_shell_sidebar_set_icon_name (shell_sidebar, icon_name); - g_free (icon_name); - - g_object_get (action, "label", &label, NULL); - e_shell_sidebar_set_primary_text (shell_sidebar, label); - g_free (label); + e_shell_sidebar_set_icon_name (shell_sidebar, e_ui_action_get_icon_name (action)); + e_shell_sidebar_set_primary_text (shell_sidebar, e_ui_action_get_label (action)); e_extensible_load_extensions (E_EXTENSIBLE (object)); diff --git a/src/shell/e-shell-switcher.c b/src/shell/e-shell-switcher.c index bd63c5d831..aafb954ee6 100644 --- a/src/shell/e-shell-switcher.c +++ b/src/shell/e-shell-switcher.c @@ -26,14 +26,12 @@ #include "evolution-config.h" -#include "e-shell-switcher.h" - #include #include #include -#include "e-shell-window-private.h" +#include "e-shell-switcher.h" #define H_PADDING 6 #define V_PADDING 6 @@ -588,20 +586,20 @@ tool_item_get_button (GtkWidget *widget) static gboolean tool_item_button_cb (GtkWidget *internal_widget, GdkEvent *button_event, - GtkAction *action) + EUIAction *action) { guint32 my_mods = GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK; GdkModifierType event_state = 0; guint event_button = 0; - g_return_val_if_fail (GTK_IS_ACTION (action), FALSE); + g_return_val_if_fail (E_IS_UI_ACTION (action), FALSE); gdk_event_get_button (button_event, &event_button); gdk_event_get_state (button_event, &event_state); if (event_button == 2 || (event_button == 1 && (event_state & my_mods) == GDK_SHIFT_MASK)) { - gtk_action_activate (action); + g_action_activate (G_ACTION (action), NULL); return TRUE; } @@ -611,8 +609,8 @@ tool_item_button_cb (GtkWidget *internal_widget, /** * e_shell_switcher_add_action: * @switcher: an #EShellSwitcher - * @switch_action: a #GtkAction - * @new_window_action: a #GtkAction + * @switch_action: an #EUIAction + * @new_window_action: an #EUIAction * * Adds a button to @switcher that proxies for @switcher_action. * Switcher buttons appear in the order they were added. A middle @@ -623,48 +621,59 @@ tool_item_button_cb (GtkWidget *internal_widget, **/ void e_shell_switcher_add_action (EShellSwitcher *switcher, - GtkAction *switch_action, - GtkAction *new_window_action) + EUIAction *switch_action, + EUIAction *new_window_action) { GtkWidget *widget; GtkButton *button; + GtkToolItem *tool_item; GSettings *settings; + GVariant *target; + const gchar *view_name; gchar **strv; gint ii; gboolean skip = FALSE; g_return_if_fail (E_IS_SHELL_SWITCHER (switcher)); - g_return_if_fail (GTK_IS_ACTION (switch_action)); - g_return_if_fail (GTK_IS_ACTION (new_window_action)); + g_return_if_fail (E_IS_UI_ACTION (switch_action)); + g_return_if_fail (E_IS_UI_ACTION (new_window_action)); settings = e_util_ref_settings ("org.gnome.evolution.shell"); strv = g_settings_get_strv (settings, "buttons-hide"); g_clear_object (&settings); - for (ii = 0; strv && strv[ii] && !skip; ii++) { - gchar *name; + target = e_ui_action_ref_target (switch_action); + view_name = g_variant_get_string (target, NULL); - name = g_strdup_printf (E_SHELL_SWITCHER_FORMAT, strv[ii]); - skip = g_strcmp0 (name, gtk_action_get_name (switch_action)) == 0; - g_free (name); + for (ii = 0; strv && strv[ii] && !skip; ii++) { + skip = g_strcmp0 (view_name, strv[ii]) == 0; } + g_clear_pointer (&target, g_variant_unref); g_strfreev (strv); if (skip) return; g_object_ref (switch_action); - widget = gtk_action_create_tool_item (switch_action); - gtk_tool_item_set_is_important (GTK_TOOL_ITEM (widget), TRUE); + tool_item = gtk_toggle_tool_button_new (); + gtk_tool_item_set_is_important (tool_item, TRUE); + gtk_tool_button_set_label (GTK_TOOL_BUTTON (tool_item), e_ui_action_get_label (switch_action)); + gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (tool_item), e_ui_action_get_icon_name (switch_action)); + + widget = GTK_WIDGET (tool_item); + gtk_widget_set_tooltip_text (widget, e_ui_action_get_tooltip (switch_action)); gtk_widget_show (widget); + e_ui_action_util_assign_to_widget (switch_action, widget); + button = tool_item_get_button (widget); - if (button != NULL) - g_signal_connect ( + if (button != NULL) { + g_signal_connect_object ( button, "button-release-event", G_CALLBACK (tool_item_button_cb), - new_window_action); + new_window_action, 0); + } gtk_widget_set_visible (widget, switcher->priv->toolbar_visible); diff --git a/src/shell/e-shell-switcher.h b/src/shell/e-shell-switcher.h index 8b544d75b1..7a7a8267b3 100644 --- a/src/shell/e-shell-switcher.h +++ b/src/shell/e-shell-switcher.h @@ -21,6 +21,7 @@ #ifndef E_SHELL_SWITCHER_H #define E_SHELL_SWITCHER_H +#include #include /* Standard GObject macros */ @@ -71,8 +72,8 @@ struct _EShellSwitcherClass { GType e_shell_switcher_get_type (void); GtkWidget * e_shell_switcher_new (void); void e_shell_switcher_add_action (EShellSwitcher *switcher, - GtkAction *switch_action, - GtkAction *new_window_action); + EUIAction *switch_action, + EUIAction *new_window_action); GtkToolbarStyle e_shell_switcher_get_style (EShellSwitcher *switcher); void e_shell_switcher_set_style (EShellSwitcher *switcher, GtkToolbarStyle style); diff --git a/src/shell/e-shell-view.c b/src/shell/e-shell-view.c index e0e23adde9..3a9a54dc74 100644 --- a/src/shell/e-shell-view.c +++ b/src/shell/e-shell-view.c @@ -52,12 +52,31 @@ struct _EShellViewPrivate { gulong view_instance_changed_handler_id; gulong view_instance_loaded_handler_id; + EUIManager *ui_manager; + GtkWidget *headerbar; + EMenuBar *menu_bar; + GtkWidget *menu_button; /* owned by menu_bar */ + GtkWidget *switcher; + GtkWidget *tooltip_label; + GtkWidget *status; + + GMenu *new_menu; + GMenu *gal_view_list_menu; + GMenu *saved_searches_menu; + + guint sidebar_visible : 1; + guint switcher_visible : 1; + guint taskbar_visible : 1; + guint toolbar_visible : 1; + guint accel_group_added : 1; + gint sidebar_width; + gchar *title; gchar *view_id; gint page_num; guint merge_id; - GtkAction *action; + EUIAction *switcher_action; GtkSizeGroup *size_group; GtkWidget *shell_content; GtkWidget *shell_sidebar; @@ -75,7 +94,7 @@ struct _EShellViewPrivate { enum { PROP_0, - PROP_ACTION, + PROP_SWITCHER_ACTION, PROP_PAGE_NUM, PROP_SEARCHBAR, PROP_SEARCH_RULE, @@ -87,15 +106,21 @@ enum { PROP_STATE_KEY_FILE, PROP_TITLE, PROP_VIEW_ID, - PROP_VIEW_INSTANCE + PROP_VIEW_INSTANCE, + PROP_MENUBAR_VISIBLE, + PROP_SIDEBAR_VISIBLE, + PROP_SWITCHER_VISIBLE, + PROP_TASKBAR_VISIBLE, + PROP_TOOLBAR_VISIBLE, + PROP_SIDEBAR_WIDTH }; enum { - TOGGLED, CLEAR_SEARCH, CUSTOM_SEARCH, EXECUTE_SEARCH, UPDATE_ACTIONS, + INIT_UI_DATA, LAST_SIGNAL }; @@ -347,28 +372,1206 @@ e_shell_view_save_state_immediately (EShellView *shell_view) } static void -shell_view_emit_toggled (EShellView *shell_view) +shell_view_online_button_clicked_cb (EOnlineButton *button, + gpointer user_data) { - g_signal_emit (shell_view, signals[TOGGLED], 0); + EShellView *self = user_data; + EUIAction *action; + + if (e_online_button_get_online (button)) + action = e_ui_manager_get_action (self->priv->ui_manager, "work-offline"); + else + action = e_ui_manager_get_action (self->priv->ui_manager, "work-online"); + + g_action_activate (G_ACTION (action), NULL); +} + +static gint +shell_view_sort_by_action_label_cmp (gconstpointer aa, + gconstpointer bb) +{ + const EUIAction *action1 = *((EUIAction **) aa); + const EUIAction *action2 = *((EUIAction **) bb); + + if (action1 == action2) + return 0; + + return g_utf8_collate (e_ui_action_get_label ((EUIAction *) action1), e_ui_action_get_label ((EUIAction *) action2)); } static void -shell_view_set_action (EShellView *shell_view, - GtkAction *action) +shell_view_extract_actions (const gchar *for_view, + GPtrArray *source_array, + GPtrArray *destination_array) { - gchar *label; + guint ii, from_index = destination_array->len; - g_return_if_fail (shell_view->priv->action == NULL); + /* Pick out the actions from the source list that are tagged + * as belonging to the for_view EShellView and move them to the + * destination list. */ - shell_view->priv->action = g_object_ref (action); + /* Example: Suppose [A] and [C] are tagged for this EShellView. + * + * source_list = [A] -> [B] -> [C] + * ^ ^ + * | | + * match_list = [ ] --------> [ ] + * + * + * destination_list = [1] -> [2] (other actions) + */ + for (ii = 0; ii < source_array->len; ii++) { + EUIAction *action = g_ptr_array_index (source_array, ii); + const gchar *backend_name; - g_object_get (action, "label", &label, NULL); - e_shell_view_set_title (shell_view, label); - g_free (label); + backend_name = g_object_get_data (G_OBJECT (action), "backend-name"); - g_signal_connect_swapped ( - action, "toggled", - G_CALLBACK (shell_view_emit_toggled), shell_view); + if (g_strcmp0 (backend_name, for_view) != 0) + continue; + + if (g_object_get_data (G_OBJECT (action), "primary")) + g_ptr_array_insert (destination_array, from_index++, g_object_ref (action)); + else + g_ptr_array_add (destination_array, g_object_ref (action)); + + /* destination_list = [1] -> [2] -> [A] -> [C] */ + g_ptr_array_remove_index (source_array, ii); + ii--; + } +} + +static gboolean +shell_view_button_style_to_state_cb (GValue *value, + GVariant *variant, + gpointer user_data) +{ + GtkToolbarStyle style = -1; + const gchar *string = g_variant_get_string (variant, NULL); + + if (string != NULL) { + if (strcmp (string, "icons") == 0) + style = GTK_TOOLBAR_ICONS; + else if (strcmp (string, "text") == 0) + style = GTK_TOOLBAR_TEXT; + else if (strcmp (string, "both") == 0) + style = GTK_TOOLBAR_BOTH_HORIZ; + else + style = -1; + } + + g_value_set_variant (value, g_variant_new_int32 (style)); + + return TRUE; +} + +static GVariant * +shell_view_state_to_button_style_cb (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + GVariant *var_value = g_value_get_variant (value); + const gchar *string; + + switch (var_value ? g_variant_get_int32 (var_value) : -1) { + case GTK_TOOLBAR_ICONS: + string = "icons"; + break; + + case GTK_TOOLBAR_TEXT: + string = "text"; + break; + + case GTK_TOOLBAR_BOTH: + case GTK_TOOLBAR_BOTH_HORIZ: + string = "both"; + break; + + default: + string = "toolbar"; + break; + } + + return g_variant_new_string (string); +} + +static void +shell_view_add_actions_as_section (EShellView *self, + GMenu *new_menu, + GPtrArray *actions) +{ + GMenu *items_menu; + GMenuItem *item; + guint ii; + + if (!actions || !actions->len) + return; + + items_menu = g_menu_new (); + + for (ii = 0; ii < actions->len; ii++) { + EUIAction *action = g_ptr_array_index (actions, ii); + + item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (self->priv->ui_manager, item, action); + g_menu_append_item (items_menu, item); + g_clear_object (&item); + } + + g_menu_append_section (new_menu, NULL, G_MENU_MODEL (items_menu)); + + g_clear_object (&items_menu); +} + +static void +shell_view_populate_new_menu (EShellView *self) +{ + EShellBackend *shell_backend; + EShellBackendClass *shell_backend_class; + GPtrArray *new_item_actions; + GPtrArray *new_source_actions; + GPtrArray *view_actions; + const gchar *backend_name; + + shell_backend = e_shell_view_get_shell_backend (self); + shell_backend_class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + g_return_if_fail (shell_backend_class != NULL); + + e_ui_manager_freeze (self->priv->ui_manager); + + backend_name = shell_backend_class->name; + + /* Get sorted lists of "new item" and "new source" actions. */ + + new_item_actions = e_ui_action_group_list_actions (e_ui_manager_get_action_group (self->priv->ui_manager, "new-item")); + g_ptr_array_sort (new_item_actions, shell_view_sort_by_action_label_cmp); + + new_source_actions = e_ui_action_group_list_actions (e_ui_manager_get_action_group (self->priv->ui_manager, "new-source")); + g_ptr_array_sort (new_source_actions, shell_view_sort_by_action_label_cmp); + + /* Give priority to actions that belong to this shell view. */ + + view_actions = g_ptr_array_new_with_free_func (g_object_unref); + + shell_view_extract_actions (backend_name, new_item_actions, view_actions); + shell_view_extract_actions (backend_name, new_source_actions, view_actions); + + g_menu_remove_all (self->priv->new_menu); + + /* Construct the menu with the layout. */ + + shell_view_add_actions_as_section (self, self->priv->new_menu, view_actions); + shell_view_add_actions_as_section (self, self->priv->new_menu, new_item_actions); + shell_view_add_actions_as_section (self, self->priv->new_menu, new_source_actions); + + g_clear_pointer (&new_item_actions, g_ptr_array_unref); + g_clear_pointer (&new_source_actions, g_ptr_array_unref); + g_clear_pointer (&view_actions, g_ptr_array_unref); + + e_ui_manager_thaw (self->priv->ui_manager); +} + +static GtkWidget * +shell_view_construct_taskbar (EShellView *self) +{ + EShell *shell; + GtkWidget *box; + GtkWidget *status_area; + GtkWidget *online_button; + GtkWidget *tooltip_label; + GtkStyleContext *style_context; + gint height; + + shell = e_shell_window_get_shell (self->priv->shell_window); + + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); + gtk_container_set_border_width (GTK_CONTAINER (box), 3); + gtk_widget_show (box); + + status_area = gtk_frame_new (NULL); + style_context = gtk_widget_get_style_context (status_area); + gtk_style_context_add_class (style_context, "taskbar"); + gtk_container_add (GTK_CONTAINER (status_area), box); + + e_binding_bind_property ( + self, "taskbar-visible", + status_area, "visible", + G_BINDING_SYNC_CREATE); + + /* Make the status area as large as the task bar. */ + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &height); + gtk_widget_set_size_request (status_area, -1, (height * 2) + 6); + + online_button = e_online_button_new (); + gtk_box_pack_start (GTK_BOX (box), online_button, FALSE, TRUE, 0); + gtk_widget_show (online_button); + + e_binding_bind_property ( + shell, "online", + online_button, "online", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + shell, "network-available", + online_button, "sensitive", + G_BINDING_SYNC_CREATE); + + g_signal_connect ( + online_button, "clicked", + G_CALLBACK (shell_view_online_button_clicked_cb), + self); + + tooltip_label = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (tooltip_label), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (box), tooltip_label, TRUE, TRUE, 0); + self->priv->tooltip_label = g_object_ref (tooltip_label); + gtk_widget_hide (tooltip_label); + + gtk_box_pack_start (GTK_BOX (box), self->priv->shell_taskbar, TRUE, TRUE, 0); + gtk_widget_show (self->priv->shell_taskbar); + + e_binding_bind_property ( + self->priv->shell_taskbar, "height-request", + self->priv->tooltip_label, "height-request", + G_BINDING_SYNC_CREATE); + + return status_area; +} + +static gboolean +e_shell_view_ui_manager_ignore_accel_cb (EUIManager *manager, + EUIAction *action, + gpointer user_data) +{ + EShellView *self = user_data; + gboolean ignore = FALSE; + + if (!e_shell_view_is_active (self)) + ignore = TRUE; + + return ignore; +} + +static void +action_custom_rule_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + EFilterRule *rule; + + rule = g_object_get_data (G_OBJECT (action), "rule"); + g_return_if_fail (E_IS_FILTER_RULE (rule)); + + e_shell_view_custom_search (self, rule); +} + +static void +shell_view_update_search_menu (EShellView *self) +{ + EShellViewClass *shell_view_class; + ERuleContext *context; + EFilterRule *rule; + EUIActionGroup *action_group; + const gchar *source; + gint ii = 0; + + g_return_if_fail (E_IS_SHELL_VIEW (self)); + + shell_view_class = E_SHELL_VIEW_GET_CLASS (self); + context = shell_view_class->search_context; + + source = E_FILTER_SOURCE_INCOMING; + + e_ui_manager_freeze (self->priv->ui_manager); + + action_group = e_ui_manager_get_action_group (self->priv->ui_manager, "custom-rules"); + e_ui_action_group_remove_all (action_group); + + g_menu_remove_all (self->priv->saved_searches_menu); + e_ui_action_group_remove_all (action_group); + + rule = e_rule_context_next_rule (context, NULL, source); + while (rule != NULL) { + EUIAction *action; + GMenuItem *menu_item; + gchar action_name[128]; + gchar *label, *label_numbered = NULL; + + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "custom-rule-%d", ii) < sizeof (action_name)); + label = e_str_without_underscores (rule->name); + if (ii < 10) + label_numbered = g_strdup_printf ("_%d. %s", ++ii, label); + else + ii++; + + action = e_ui_action_new (e_ui_action_group_get_name (action_group), action_name, NULL); + e_ui_action_set_label (action, label_numbered ? label_numbered : label); + e_ui_action_set_tooltip (action, _("Execute these search parameters")); + + e_ui_action_group_add (action_group, action); + + g_object_set_data_full (G_OBJECT (action), "rule", g_object_ref (rule), g_object_unref); + + g_signal_connect_object (action, "activate", + G_CALLBACK (action_custom_rule_cb), self, 0); + + menu_item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (self->priv->ui_manager, menu_item, action); + g_menu_append_item (self->priv->saved_searches_menu, menu_item); + g_clear_object (&menu_item); + + g_object_unref (action); + g_free (label_numbered); + g_free (label); + + rule = e_rule_context_next_rule (context, rule, source); + } + + e_ui_manager_thaw (self->priv->ui_manager); +} + +static void +action_search_advanced_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + EShellContent *shell_content; + + shell_content = e_shell_view_get_shell_content (self); + + e_shell_content_run_advanced_search_dialog (shell_content); + shell_view_update_search_menu (self); +} + +static void +action_search_clear_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + + e_shell_view_clear_search (self); +} + +static void +action_search_edit_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + EShellContent *shell_content; + + shell_content = e_shell_view_get_shell_content (self); + + e_shell_content_run_edit_searches_dialog (shell_content); + shell_view_update_search_menu (self); +} + +static void +search_options_selection_cancel_cb (GtkMenuShell *menu, + EShellView *self); + +static void +search_options_selection_done_cb (GtkMenuShell *menu, + EShellView *self) +{ + EShellSearchbar *search_bar; + + /* disconnect first */ + g_signal_handlers_disconnect_by_func (menu, search_options_selection_done_cb, self); + g_signal_handlers_disconnect_by_func (menu, search_options_selection_cancel_cb, self); + + g_return_if_fail (E_IS_SHELL_VIEW (self)); + + search_bar = E_SHELL_SEARCHBAR (e_shell_view_get_searchbar (self)); + e_shell_searchbar_search_entry_grab_focus (search_bar); +} + +static void +search_options_selection_cancel_cb (GtkMenuShell *menu, + EShellView *self) +{ + /* only disconnect both functions, thus the selection-done is not called */ + g_signal_handlers_disconnect_by_func (menu, search_options_selection_done_cb, self); + g_signal_handlers_disconnect_by_func (menu, search_options_selection_cancel_cb, self); +} + +static void +action_search_options_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + EShellSearchbar *search_bar; + GtkWidget *popup_menu; + + search_bar = E_SHELL_SEARCHBAR (e_shell_view_get_searchbar (self)); + if (!e_shell_searchbar_search_entry_has_focus (search_bar)) { + e_shell_searchbar_search_entry_grab_focus (search_bar); + return; + } + + popup_menu = e_shell_view_show_popup_menu (self, "search-options", NULL); + + if (popup_menu) { + g_return_if_fail (GTK_IS_MENU_SHELL (popup_menu)); + + g_signal_connect_object (popup_menu, "selection-done", + G_CALLBACK (search_options_selection_done_cb), self, 0); + g_signal_connect_object (popup_menu, "cancel", + G_CALLBACK (search_options_selection_cancel_cb), self, 0); + } +} + +static void +action_search_quick_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + + e_shell_view_execute_search (self); +} + +static void +action_search_save_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + EShellContent *shell_content; + + shell_content = e_shell_view_get_shell_content (self); + + e_shell_content_run_save_search_dialog (shell_content); + shell_view_update_search_menu (self); +} + +static void +action_gal_delete_view_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + GalViewInstance *view_instance; + gchar *gal_view_id; + gint index = -1; + + view_instance = e_shell_view_get_view_instance (self); + g_return_if_fail (view_instance != NULL); + + /* XXX This is kinda cumbersome. The view collection API + * should be using only view ID's, not index numbers. */ + gal_view_id = gal_view_instance_get_current_view_id (view_instance); + if (gal_view_id != NULL) { + index = gal_view_collection_get_view_index_by_id ( + view_instance->collection, gal_view_id); + g_free (gal_view_id); + } + + gal_view_collection_delete_view (view_instance->collection, index); + + gal_view_collection_save (view_instance->collection); +} + +static void shell_view_update_view_menu (EShellView *self); + +static void +action_gal_view_cb (EUIAction *action, + GParamSpec *parm, + gpointer user_data) +{ + EShellView *self = user_data; + GVariant *state; + const gchar *view_id; + + state = g_action_get_state (G_ACTION (action)); + + view_id = g_variant_get_string (state, NULL); + + e_shell_view_set_view_id (self, view_id); + + g_clear_pointer (&state, g_variant_unref); + + shell_view_update_view_menu (self); +} + +static void +action_gal_save_custom_view_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + GalViewInstance *view_instance; + + view_instance = e_shell_view_get_view_instance (self); + + gal_view_instance_save_as (view_instance); +} + +static void +action_gal_customize_view_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + GalViewInstance *view_instance; + GalView *gal_view; + + view_instance = e_shell_view_get_view_instance (self); + + gal_view = gal_view_instance_get_current_view (view_instance); + + if (GAL_IS_VIEW_ETABLE (gal_view)) { + GalViewEtable *etable_view = GAL_VIEW_ETABLE (gal_view); + ETable *etable; + + etable = gal_view_etable_get_table (etable_view); + + if (etable) { + e_table_customize_view (etable); + } else { + ETree *etree; + + etree = gal_view_etable_get_tree (etable_view); + + if (etree) + e_tree_customize_view (etree); + } + } +} + +static EUIAction * /* (transfer none) */ +shell_view_get_prefer_new_item_action (EShellView *self) +{ + EShellBackend *shell_backend; + EUIAction *action = NULL; + const gchar *prefer_new_item; + + shell_backend = e_shell_view_get_shell_backend (self); + prefer_new_item = e_shell_backend_get_prefer_new_item (shell_backend); + + if (prefer_new_item) + action = e_shell_view_get_action (self, prefer_new_item); + + if (!action) { + EShellBackendClass *shell_backend_class; + GPtrArray *new_item_actions; + const gchar *backend_name; + guint ii; + + shell_backend_class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + g_return_val_if_fail (shell_backend_class != NULL, NULL); + + backend_name = shell_backend_class->name; + + new_item_actions = e_ui_action_group_list_actions (e_ui_manager_get_action_group (self->priv->ui_manager, "new-item")); + g_ptr_array_sort (new_item_actions, shell_view_sort_by_action_label_cmp); + + for (ii = 0; ii < new_item_actions->len; ii++) { + EUIAction *new_item_action = g_ptr_array_index (new_item_actions, ii); + const gchar *action_backend_name; + + action_backend_name = g_object_get_data (G_OBJECT (new_item_action), "backend-name"); + + /* pick the primary action or the first action in the list */ + if (g_strcmp0 (action_backend_name, backend_name) == 0) { + if (g_object_get_data (G_OBJECT (new_item_action), "primary")) { + action = new_item_action; + break; + } else if (!action) { + action = new_item_action; + } + } + } + + g_clear_pointer (&new_item_actions, g_ptr_array_unref); + } + + g_return_val_if_fail (action != NULL, NULL); + + return action; +} + +static void +action_shell_view_new_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellView *self = user_data; + EUIAction *new_item_action; + + new_item_action = shell_view_get_prefer_new_item_action (self); + g_return_if_fail (new_item_action != NULL); + + g_action_activate (G_ACTION (new_item_action), NULL); +} + +static void +shell_view_init_ui_data (EShellView *self) +{ + static const EUIActionEntry search_entries[] = { + + { "search-advanced", + NULL, + N_("_Advanced Search…"), + NULL, + N_("Construct a more advanced search"), + action_search_advanced_cb, NULL, NULL, NULL }, + + { "search-clear", + "edit-clear", + N_("_Clear"), + "q", + N_("Clear the current search parameters"), + action_search_clear_cb, NULL, NULL, NULL }, + + { "search-edit", + NULL, + N_("_Edit Saved Searches…"), + NULL, + N_("Manage your saved searches"), + action_search_edit_cb, NULL, NULL, NULL }, + + { "search-options", + "edit-find", + N_("_Find"), + "f", + N_("Click here to change the search type"), + action_search_options_cb, NULL, NULL, NULL }, + + { "search-quick", + "edit-find", + N_("_Find Now"), + NULL, + N_("Execute the current search parameters"), + action_search_quick_cb, NULL, NULL, NULL }, + + { "search-save", + NULL, + N_("_Save Search…"), + NULL, + N_("Save the current search parameters"), + action_search_save_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry show_entries[] = { + + { "show-menubar", + NULL, + N_("Show _Menu Bar"), + NULL, + N_("Show the menu bar"), + NULL, NULL, "true", NULL }, + + { "show-sidebar", + NULL, + N_("Show Side _Bar"), + "F9", + N_("Show the side bar"), + NULL, NULL, "true", NULL }, + + { "show-switcher", + NULL, + N_("Show _Buttons"), + NULL, + N_("Show the switcher buttons"), + NULL, NULL, "true", NULL }, + + { "show-taskbar", + NULL, + N_("Show _Status Bar"), + NULL, + N_("Show the status bar"), + NULL, NULL, "true", NULL }, + + { "show-toolbar", + NULL, + N_("Show _Tool Bar"), + NULL, + N_("Show the tool bar"), + NULL, NULL, "true", NULL } + }; + + static const EUIActionEntry custom_entries[] = { + + { "gal-delete-view", + NULL, + N_("Delete Current View"), + NULL, + NULL, /* Set in update_view_menu */ + action_gal_delete_view_cb, NULL, NULL, NULL }, + + { "gal-save-custom-view", + NULL, + N_("Save Custom View…"), + NULL, + N_("Save current custom view"), + action_gal_save_custom_view_cb, NULL, NULL, NULL }, + + { "gal-customize-view", + NULL, + N_("Custo_mize Current View…"), + NULL, + NULL, + action_gal_customize_view_cb, NULL, NULL, NULL }, + + { "gal-custom-view", + NULL, + N_("Custom View"), + NULL, + N_("Current view is a customized view"), + NULL, "s", "''", NULL }, + + { "EShellView::new-menu", + "document-new", + N_("_New"), + NULL, + NULL, + action_shell_view_new_cb, NULL, NULL, NULL }, + + /*** Menus ***/ + + { "gal-view-menu", NULL, N_("C_urrent View"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "saved-searches", NULL, N_("Saved searches"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EShellView::gal-view-list", NULL, N_("List of available views"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EShellView::menu-button", NULL, N_("Menu"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EShellView::saved-searches-list", NULL, N_("List of saved searches"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EShellView::switch-to-list", NULL, N_("List of views"), NULL, NULL, NULL, NULL, NULL, NULL } + }; + + static const EUIActionEnumEntry shell_switcher_style_entries[] = { + + { "switcher-style-icons", + NULL, + N_("_Icons Only"), + NULL, + N_("Display window buttons with icons only"), + NULL, GTK_TOOLBAR_ICONS }, + + { "switcher-style-text", + NULL, + N_("_Text Only"), + NULL, + N_("Display window buttons with text only"), + NULL, GTK_TOOLBAR_TEXT }, + + { "switcher-style-both", + NULL, + N_("Icons _and Text"), + NULL, + N_("Display window buttons with icons and text"), + NULL, GTK_TOOLBAR_BOTH_HORIZ }, + + { "switcher-style-user", + NULL, + N_("Tool_bar Style"), + NULL, + N_("Display window buttons using the desktop toolbar setting"), + NULL, -1 } + }; + + EShellViewClass *shell_view_class; + EUIActionGroup *action_group; + EUIAction *action; + GError *local_error = NULL; + + shell_view_class = E_SHELL_VIEW_GET_CLASS (self); + g_return_if_fail (shell_view_class != NULL); + + e_ui_manager_add_actions (self->priv->ui_manager, "search-entries", NULL, + search_entries, G_N_ELEMENTS (search_entries), self); + e_ui_manager_add_actions (self->priv->ui_manager, "show-entries", NULL, + show_entries, G_N_ELEMENTS (show_entries), self); + e_ui_manager_add_actions (self->priv->ui_manager, "custom-entries", NULL, + custom_entries, G_N_ELEMENTS (custom_entries), self); + e_ui_manager_add_actions_enum (self->priv->ui_manager, "custom-entries", NULL, + shell_switcher_style_entries, G_N_ELEMENTS (shell_switcher_style_entries), self); + + action_group = e_ui_action_group_new ("gal-view"); + e_ui_manager_add_action_group (self->priv->ui_manager, action_group); + g_clear_object (&action_group); + + action = e_ui_manager_get_action (self->priv->ui_manager, "gal-custom-view"); + g_signal_connect_object (action, "notify::state", + G_CALLBACK (action_gal_view_cb), self, 0); + + e_shell_window_init_ui_data (self->priv->shell_window, self); + shell_view_populate_new_menu (self); + + if (self->priv->searchbar && E_IS_SHELL_SEARCHBAR (self->priv->searchbar)) + e_shell_searchbar_init_ui_data (E_SHELL_SEARCHBAR (self->priv->searchbar)); + + g_signal_emit (self, signals[INIT_UI_DATA], 0); + + /* Fine tuning. */ + e_ui_action_set_sensitive (e_ui_manager_get_action (self->priv->ui_manager, "search-quick"), FALSE); + + e_binding_bind_property ( + self, "menubar-visible", + e_ui_manager_get_action (self->priv->ui_manager, "show-menubar"), "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + self, "sidebar-visible", + e_ui_manager_get_action (self->priv->ui_manager, "show-sidebar"), "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + self, "switcher-visible", + e_ui_manager_get_action (self->priv->ui_manager, "show-switcher"), "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + self, "taskbar-visible", + e_ui_manager_get_action (self->priv->ui_manager, "show-taskbar"), "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + self, "toolbar-visible", + e_ui_manager_get_action (self->priv->ui_manager, "show-toolbar"), "active", + G_BINDING_BIDIRECTIONAL | + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + e_ui_manager_get_action (self->priv->ui_manager, "show-sidebar"), "active", + e_ui_manager_get_action (self->priv->ui_manager, "show-switcher"), "sensitive", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + e_ui_manager_get_action (self->priv->ui_manager, "show-sidebar"), "active", + e_ui_manager_get_action (self->priv->ui_manager, "switcher-style-both"), "sensitive", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + e_ui_manager_get_action (self->priv->ui_manager, "show-sidebar"), "active", + e_ui_manager_get_action (self->priv->ui_manager, "switcher-style-icons"), "sensitive", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + e_ui_manager_get_action (self->priv->ui_manager, "show-sidebar"), "active", + e_ui_manager_get_action (self->priv->ui_manager, "switcher-style-text"), "sensitive", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + e_ui_manager_get_action (self->priv->ui_manager, "show-sidebar"), "active", + e_ui_manager_get_action (self->priv->ui_manager, "switcher-style-user"), "sensitive", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + e_ui_manager_get_action (self->priv->ui_manager, "show-sidebar"), "active", + e_ui_manager_get_action (self->priv->ui_manager, "switcher-menu"), "sensitive", + G_BINDING_SYNC_CREATE); + + if (!e_ui_parser_merge_file (e_ui_manager_get_parser (self->priv->ui_manager), shell_view_class->ui_definition, &local_error)) + g_warning ("%s: Failed to read %s file: %s", G_STRFUNC, shell_view_class->ui_definition, local_error ? local_error->message : "Unknown error"); + + g_clear_error (&local_error); + + g_signal_connect_object (self->priv->shell_window, "update-new-menu", + G_CALLBACK (shell_view_populate_new_menu), self, G_CONNECT_SWAPPED); +} + +static void +shell_view_menubar_deactivate_cb (GtkWidget *menu_bar, + gpointer user_data) +{ + EShellView *self = user_data; + + g_return_if_fail (E_IS_SHELL_VIEW (self)); + + if (!e_shell_view_get_menubar_visible (self)) + gtk_widget_hide (menu_bar); +} + +static void +shell_view_set_switcher_action (EShellView *shell_view, + EUIAction *action) +{ + g_return_if_fail (shell_view->priv->switcher_action == NULL); + g_return_if_fail (E_IS_UI_ACTION (action)); + + shell_view->priv->switcher_action = g_object_ref (action); + + e_shell_view_set_title (shell_view, e_ui_action_get_label (action)); +} + +static void +shell_view_switcher_style_cb (EUIAction *action, + GParamSpec *param, + gpointer user_data) +{ + EShellSwitcher *switcher = user_data; + GtkToolbarStyle style; + GVariant *state; + + state = g_action_get_state (G_ACTION (action)); + style = g_variant_get_int32 (state); + g_clear_pointer (&state, g_variant_unref); + + switch (style) { + case GTK_TOOLBAR_ICONS: + case GTK_TOOLBAR_TEXT: + case GTK_TOOLBAR_BOTH: + case GTK_TOOLBAR_BOTH_HORIZ: + e_shell_switcher_set_style (switcher, style); + break; + + default: + e_shell_switcher_unset_style (switcher); + break; + } +} + +static gboolean +shell_view_ui_manager_create_item_cb (EUIManager *manager, + EUIElement *elem, + EUIAction *action, + EUIElementKind for_kind, + GObject **out_item, + gpointer user_data) +{ + EShellView *self = user_data; + const gchar *name; + + g_return_val_if_fail (E_IS_SHELL_VIEW (self), FALSE); + + name = g_action_get_name (G_ACTION (action)); + + if (!g_str_has_prefix (name, "EShellView::")) + return FALSE; + + #define is_action(_nm) (g_strcmp0 (name, (_nm)) == 0) + + if (for_kind == E_UI_ELEMENT_KIND_MENU) { + if (is_action ("EShellView::new-menu")) { + *out_item = G_OBJECT (g_menu_item_new_submenu (e_ui_action_get_label (action), G_MENU_MODEL (self->priv->new_menu))); + g_menu_item_set_attribute (G_MENU_ITEM (*out_item), "icon", "s", e_ui_action_get_icon_name (action)); + } else if (is_action ("EShellView::gal-view-list")) { + *out_item = G_OBJECT (g_menu_item_new_section (NULL, G_MENU_MODEL (self->priv->gal_view_list_menu))); + } else if (is_action ("EShellView::saved-searches-list")) { + *out_item = G_OBJECT (g_menu_item_new_section (NULL, G_MENU_MODEL (self->priv->saved_searches_menu))); + } else if (is_action ("EShellView::switch-to-list")) { + GMenuModel *menu_model = self->priv->shell_window ? e_shell_window_ref_switch_to_menu_model (self->priv->shell_window) : NULL; + if (menu_model) + *out_item = G_OBJECT (g_menu_item_new_section (NULL, menu_model)); + } else { + g_warning ("%s: Unhandled menu action '%s'", G_STRFUNC, name); + } + } else if (for_kind == E_UI_ELEMENT_KIND_TOOLBAR) { + GtkWidget *widget = NULL; + gboolean claimed = FALSE; + + if (is_action ("EShellView::new-menu")) { + EShellBackend *shell_backend; + GtkToolItem *tool_item; + GtkWidget *menu; + + menu = gtk_menu_new_from_model (G_MENU_MODEL (self->priv->new_menu)); + tool_item = e_menu_tool_button_new (C_("toolbar-button", "New"), manager); + gtk_tool_item_set_is_important (tool_item, TRUE); + gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (tool_item), menu); + gtk_widget_set_visible (GTK_WIDGET (tool_item), TRUE); + + shell_backend = e_shell_view_get_shell_backend (self); + + e_binding_bind_property (shell_backend, "prefer-new-item", + tool_item, "prefer-item", + G_BINDING_SYNC_CREATE); + + *out_item = G_OBJECT (tool_item); + } else { + g_warning ("%s: Unhandled toolbar action '%s'", G_STRFUNC, name); + claimed = TRUE; + } + + if (widget) { + GtkToolItem *tool_item; + + tool_item = gtk_tool_item_new (); + gtk_container_add (GTK_CONTAINER (tool_item), widget); + gtk_widget_show_all (GTK_WIDGET (tool_item)); + + *out_item = G_OBJECT (tool_item); + } else if (!claimed && !*out_item) { + g_warning ("%s: Did not get toolbar widget for '%s'", G_STRFUNC, name); + } + } else if (for_kind == E_UI_ELEMENT_KIND_HEADERBAR) { + if (is_action ("EShellView::new-menu")) { + GtkWidget *button; + GtkWidget *menu; + EShellBackend *shell_backend; + + menu = gtk_menu_new_from_model (G_MENU_MODEL (self->priv->new_menu)); + button = e_header_bar_button_new (C_("toolbar-button", "New"), NULL, manager); + e_header_bar_button_take_menu (E_HEADER_BAR_BUTTON (button), menu); + gtk_widget_set_visible (GTK_WIDGET (button), TRUE); + + shell_backend = e_shell_view_get_shell_backend (self); + + e_binding_bind_property (shell_backend, "prefer-new-item", + button, "prefer-item", + G_BINDING_SYNC_CREATE); + + *out_item = G_OBJECT (button); + } else if (is_action ("EShellView::menu-button")) { + *out_item = G_OBJECT (g_object_ref (self->priv->menu_button)); + } else { + g_warning ("%s: Unhandled headerbar action '%s'", G_STRFUNC, name); + } + } else { + g_warning ("%s: Unhandled element kind '%d' for action '%s'", G_STRFUNC, (gint) for_kind, name); + } + + #undef is_action + + return TRUE; +} + +static void +shell_view_update_view_menu (EShellView *self) +{ + EShellViewClass *shell_view_class; + EUIActionGroup *action_group; + EUIAction *action; + GPtrArray *radio_group; + GalViewCollection *view_collection; + GalViewInstance *view_instance; + gboolean visible; + const gchar *view_id; + gchar *delete_tooltip = NULL; + gboolean view_exists = FALSE; + gboolean delete_visible = FALSE; + gint count, ii; + + shell_view_class = E_SHELL_VIEW_GET_CLASS (self); + g_return_if_fail (shell_view_class != NULL); + + view_collection = shell_view_class->view_collection; + view_id = e_shell_view_get_view_id (self); + g_return_if_fail (view_collection != NULL); + + action_group = e_ui_manager_get_action_group (self->priv->ui_manager, "gal-view"); + + e_ui_manager_freeze (self->priv->ui_manager); + + g_menu_remove_all (self->priv->gal_view_list_menu); + e_ui_action_group_remove_all (action_group); + + /* We have a view ID, so forge ahead. */ + count = gal_view_collection_get_count (view_collection); + + radio_group = g_ptr_array_sized_new (1 + count); + + /* Prevent spurious activations. */ + action = e_ui_manager_get_action (self->priv->ui_manager, "gal-custom-view"); + g_signal_handlers_block_matched ( + action, G_SIGNAL_MATCH_FUNC, 0, 0, + NULL, action_gal_view_cb, NULL); + + /* first unset, because overriding the group is considered a code error */ + e_ui_action_set_radio_group (action, NULL); + e_ui_action_set_radio_group (action, radio_group); + + /* Add a menu item for each view collection item. */ + for (ii = 0; ii < count; ii++) { + GalViewCollectionItem *item; + GMenuItem *menu_item; + gchar action_name[128]; + gchar *tooltip, *title; + + item = gal_view_collection_get_view_item (view_collection, ii); + + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), "gal-view-%d", ii) < sizeof (action_name)); + title = e_str_without_underscores (item->title); + tooltip = g_strdup_printf (_("Select view: %s"), title); + + action = e_ui_action_new_stateful (e_ui_action_group_get_name (action_group), action_name, + G_VARIANT_TYPE_STRING, g_variant_new_string (item->id)); + e_ui_action_set_label (action, title); + e_ui_action_set_tooltip (action, tooltip); + if (item->built_in && item->accelerator) + e_ui_action_set_accel (action, item->accelerator); + e_ui_action_set_radio_group (action, radio_group); + + if (g_strcmp0 (item->id, view_id) == 0) { + view_exists = TRUE; + g_free (delete_tooltip); + delete_tooltip = g_strdup_printf (_("Delete view: %s"), title); + delete_visible = (!item->built_in); + } + + e_ui_action_group_add (action_group, action); + + menu_item = g_menu_item_new (NULL, NULL); + e_ui_manager_update_item_from_action (self->priv->ui_manager, menu_item, action); + g_menu_append_item (self->priv->gal_view_list_menu, menu_item); + g_clear_object (&menu_item); + + g_free (tooltip); + g_free (title); + } + + action = e_ui_manager_get_action (self->priv->ui_manager, "gal-custom-view"); + e_ui_action_set_state (action, g_variant_new_string (view_exists ? view_id : "")); + visible = e_ui_action_get_active (action); + e_ui_action_set_visible (action, visible); + + g_signal_handlers_unblock_matched ( + action, G_SIGNAL_MATCH_FUNC, 0, 0, + NULL, action_gal_view_cb, NULL); + + action = e_ui_manager_get_action (self->priv->ui_manager, "gal-save-custom-view"); + e_ui_action_set_visible (action, visible); + + view_instance = e_shell_view_get_view_instance (self); + visible = view_instance && gal_view_instance_get_current_view (view_instance) && + GAL_IS_VIEW_ETABLE (gal_view_instance_get_current_view (view_instance)); + action = e_ui_manager_get_action (self->priv->ui_manager, "gal-customize-view"); + e_ui_action_set_visible (action, visible); + + action = e_ui_manager_get_action (self->priv->ui_manager, "gal-delete-view"); + e_ui_action_set_tooltip (action, delete_tooltip); + e_ui_action_set_visible (action, delete_visible); + + e_ui_manager_thaw (self->priv->ui_manager); + + g_ptr_array_unref (radio_group); + g_free (delete_tooltip); +} + +static void +shell_view_notify_active_view_cb (GObject *object, + GParamSpec *param, + gpointer user_data) +{ + EShellView *self = user_data; + GtkAccelGroup *accel_group; + + if (!self->priv->ui_manager) + return; + + accel_group = e_ui_manager_get_accel_group (self->priv->ui_manager); + + /* Different views can use the same accelerator for their actions. + The gtk+ finds the first accel group with the accelerator and + activates it, but it does not go to other groups, if the chosen + one cannot be activated due to the view being inactive (in + the EUIManager::ignore-accel callback). */ + if (e_shell_view_is_active (self)) { + if (!self->priv->accel_group_added) { + self->priv->accel_group_added = TRUE; + gtk_window_add_accel_group (GTK_WINDOW (object), accel_group); + } + } else if (self->priv->accel_group_added) { + self->priv->accel_group_added = FALSE; + gtk_window_remove_accel_group (GTK_WINDOW (object), accel_group); + } } static void @@ -392,8 +1595,8 @@ shell_view_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_ACTION: - shell_view_set_action ( + case PROP_SWITCHER_ACTION: + shell_view_set_switcher_action ( E_SHELL_VIEW (object), g_value_get_object (value)); return; @@ -433,6 +1636,42 @@ shell_view_set_property (GObject *object, E_SHELL_VIEW (object), g_value_get_object (value)); return; + + case PROP_MENUBAR_VISIBLE: + e_shell_view_set_menubar_visible ( + E_SHELL_VIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_SIDEBAR_VISIBLE: + e_shell_view_set_sidebar_visible ( + E_SHELL_VIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_SWITCHER_VISIBLE: + e_shell_view_set_switcher_visible ( + E_SHELL_VIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_TASKBAR_VISIBLE: + e_shell_view_set_taskbar_visible ( + E_SHELL_VIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_TOOLBAR_VISIBLE: + e_shell_view_set_toolbar_visible ( + E_SHELL_VIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_SIDEBAR_WIDTH: + e_shell_view_set_sidebar_width ( + E_SHELL_VIEW (object), + g_value_get_int (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -445,9 +1684,9 @@ shell_view_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_ACTION: + case PROP_SWITCHER_ACTION: g_value_set_object ( - value, e_shell_view_get_action ( + value, e_shell_view_get_switcher_action ( E_SHELL_VIEW (object))); return; @@ -522,6 +1761,42 @@ shell_view_get_property (GObject *object, value, e_shell_view_get_view_instance ( E_SHELL_VIEW (object))); return; + + case PROP_MENUBAR_VISIBLE: + g_value_set_boolean ( + value, e_shell_view_get_menubar_visible ( + E_SHELL_VIEW (object))); + return; + + case PROP_SIDEBAR_VISIBLE: + g_value_set_boolean ( + value, e_shell_view_get_sidebar_visible ( + E_SHELL_VIEW (object))); + return; + + case PROP_SWITCHER_VISIBLE: + g_value_set_boolean ( + value, e_shell_view_get_switcher_visible ( + E_SHELL_VIEW (object))); + return; + + case PROP_TASKBAR_VISIBLE: + g_value_set_boolean ( + value, e_shell_view_get_taskbar_visible ( + E_SHELL_VIEW (object))); + return; + + case PROP_TOOLBAR_VISIBLE: + g_value_set_boolean ( + value, e_shell_view_get_toolbar_visible ( + E_SHELL_VIEW (object))); + return; + + case PROP_SIDEBAR_WIDTH: + g_value_set_int ( + value, e_shell_view_get_sidebar_width ( + E_SHELL_VIEW (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -581,6 +1856,11 @@ shell_view_dispose (GObject *object) g_clear_object (&self->priv->searchbar); g_clear_object (&self->priv->search_rule); g_clear_object (&self->priv->preferences_window); + g_clear_object (&self->priv->ui_manager); + g_clear_object (&self->priv->new_menu); + g_clear_object (&self->priv->gal_view_list_menu); + g_clear_object (&self->priv->saved_searches_menu); + g_clear_object (&self->priv->headerbar); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_shell_view_parent_class)->dispose (object); @@ -607,20 +1887,38 @@ shell_view_constructed (GObject *object) EShellView *shell_view; EShellBackend *shell_backend; EShellViewClass *shell_view_class; + EUIAction *action; GtkWidget *widget; + GtkPaned *paned; + GSettings *settings; + GObject *ui_item; gulong handler_id; + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_shell_view_parent_class)->constructed (object); + shell_view = E_SHELL_VIEW (object); shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view); g_return_if_fail (shell_view_class != NULL); + e_ui_manager_freeze (shell_view->priv->ui_manager); + + gtk_orientable_set_orientation (GTK_ORIENTABLE (shell_view), GTK_ORIENTATION_VERTICAL); + gtk_box_set_spacing (GTK_BOX (shell_view), 0); + + g_signal_connect (shell_view->priv->ui_manager, "ignore-accel", + G_CALLBACK (e_shell_view_ui_manager_ignore_accel_cb), shell_view); + + e_ui_manager_set_action_groups_widget (shell_view->priv->ui_manager, GTK_WIDGET (shell_view)); + + e_signal_connect_notify_object (shell_view->priv->shell_window, "notify::active-view", + G_CALLBACK (shell_view_notify_active_view_cb), shell_view, 0); + shell_backend = e_shell_view_get_shell_backend (shell_view); shell = e_shell_backend_get_shell (shell_backend); shell_view_load_state (shell_view); - /* Invoke factory methods. */ - /* Create the taskbar widget first so the content and * sidebar widgets can access it during construction. */ widget = shell_view_class->new_shell_taskbar (shell_view); @@ -644,6 +1942,80 @@ shell_view_constructed (GObject *object) g_object_unref (shell_view->priv->size_group); shell_view->priv->size_group = NULL; + shell_view_init_ui_data (shell_view); + + ui_item = e_ui_manager_create_item (shell_view->priv->ui_manager, "main-menu"); + widget = gtk_menu_bar_new_from_model (G_MENU_MODEL (ui_item)); + g_clear_object (&ui_item); + + shell_view->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (widget), GTK_WINDOW (shell_view->priv->shell_window), &shell_view->priv->menu_button); + gtk_box_pack_start (GTK_BOX (shell_view), widget, FALSE, FALSE, 0); + + g_signal_connect_object (widget, "deactivate", + G_CALLBACK (shell_view_menubar_deactivate_cb), shell_view, 0); + + if (e_util_get_use_header_bar ()) { + ui_item = e_ui_manager_create_item (shell_view->priv->ui_manager, "main-headerbar"); + shell_view->priv->headerbar = g_object_ref_sink (GTK_WIDGET (ui_item)); + + ui_item = e_ui_manager_create_item (shell_view->priv->ui_manager, "main-toolbar-with-headerbar"); + } else { + ui_item = e_ui_manager_create_item (shell_view->priv->ui_manager, "main-toolbar-without-headerbar"); + } + + widget = GTK_WIDGET (ui_item); + gtk_box_pack_start (GTK_BOX (shell_view), widget, FALSE, FALSE, 0); + + e_binding_bind_property ( + shell_view, "toolbar-visible", + widget, "visible", + G_BINDING_SYNC_CREATE); + + widget = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); + gtk_box_pack_start (GTK_BOX (shell_view), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + paned = GTK_PANED (widget); + + e_binding_bind_property (shell_view, "sidebar-width", + paned, "position", + G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL); + + widget = shell_view_construct_taskbar (shell_view); + gtk_box_pack_start (GTK_BOX (shell_view), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = e_shell_switcher_new (); + shell_view->priv->switcher = g_object_ref_sink (widget); + + e_binding_bind_property ( + shell_view, "sidebar-visible", + shell_view->priv->switcher, "visible", + G_BINDING_SYNC_CREATE); + + e_binding_bind_property ( + shell_view, "switcher-visible", + shell_view->priv->switcher, "toolbar-visible", + G_BINDING_SYNC_CREATE); + + gtk_container_add (GTK_CONTAINER (shell_view->priv->switcher), shell_view->priv->shell_sidebar); + + g_object_set (shell_view->priv->shell_content, + "hexpand", TRUE, + "halign", GTK_ALIGN_FILL, + "vexpand", TRUE, + "valign", GTK_ALIGN_FILL, + NULL); + + gtk_paned_pack1 (paned, widget, FALSE, FALSE); + gtk_paned_pack2 (paned, shell_view->priv->shell_content, TRUE, FALSE); + + e_shell_window_fill_switcher_actions (shell_view->priv->shell_window, shell_view->priv->ui_manager, + E_SHELL_SWITCHER (shell_view->priv->switcher)); + + shell_view_update_view_menu (shell_view); + shell_view_update_search_menu (shell_view); + /* Update actions whenever the Preferences window is closed. */ widget = e_shell_get_preferences_window (shell); shell_view->priv->preferences_window = g_object_ref (widget); @@ -652,10 +2024,35 @@ shell_view_constructed (GObject *object) G_CALLBACK (e_shell_view_update_actions_in_idle), shell_view); shell_view->priv->preferences_hide_handler_id = handler_id; + /* it's okay to connect the signal on one of them only, + because they are in a group */ + action = e_ui_manager_get_action (shell_view->priv->ui_manager, "switcher-style-icons"); + settings = e_util_ref_settings ("org.gnome.evolution.shell"); + g_settings_bind_with_mapping (settings, "buttons-style", + action, "state", + G_SETTINGS_BIND_DEFAULT, + shell_view_button_style_to_state_cb, + shell_view_state_to_button_style_cb, + NULL, NULL); + g_clear_object (&settings); + + g_signal_connect_object (action, "notify::state", + G_CALLBACK (shell_view_switcher_style_cb), shell_view->priv->switcher, 0); + shell_view_switcher_style_cb (action, NULL, shell_view->priv->switcher); + + e_signal_connect_notify ( + shell_view, "notify::view-id", + G_CALLBACK (shell_view_update_view_menu), NULL); + + /* Register the EUIManager ID for the shell view. */ + e_plugin_ui_register_manager (shell_view->priv->ui_manager, shell_view_class->ui_manager_id, shell_view); + e_extensible_load_extensions (E_EXTENSIBLE (object)); - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_shell_view_parent_class)->constructed (object); + if (shell_view->priv->headerbar) + e_ui_manager_add_action_groups_to_widget (shell_view->priv->ui_manager, shell_view->priv->headerbar); + + e_ui_manager_thaw (shell_view->priv->ui_manager); } static GtkWidget * @@ -696,42 +2093,6 @@ shell_view_get_search_name (EShellView *shell_view) return g_strdup_printf ("%s %s", rule->name, search_text); } -static void -shell_view_toggled (EShellView *shell_view) -{ - EShellViewPrivate *priv = shell_view->priv; - EShellViewClass *shell_view_class; - EShellWindow *shell_window; - GtkUIManager *ui_manager; - const gchar *basename, *id; - gboolean view_is_active; - - shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view); - g_return_if_fail (shell_view_class != NULL); - - shell_window = e_shell_view_get_shell_window (shell_view); - ui_manager = e_shell_window_get_ui_manager (shell_window); - view_is_active = e_shell_view_is_active (shell_view); - basename = shell_view_class->ui_definition; - id = shell_view_class->ui_manager_id; - - if (view_is_active && priv->merge_id == 0) { - priv->merge_id = e_load_ui_manager_definition ( - ui_manager, basename); - e_plugin_ui_enable_manager (ui_manager, id); - } else if (!view_is_active && priv->merge_id != 0) { - e_plugin_ui_disable_manager (ui_manager, id); - gtk_ui_manager_remove_ui (ui_manager, priv->merge_id); - gtk_ui_manager_ensure_update (ui_manager); - priv->merge_id = 0; - } - - gtk_ui_manager_ensure_update (ui_manager); - - if (view_is_active) - e_shell_window_update_search_menu (shell_window); -} - static void shell_view_clear_search (EShellView *shell_view) { @@ -752,8 +2113,8 @@ shell_view_update_actions (EShellView *shell_view) { EShellWindow *shell_window; EFocusTracker *focus_tracker; - GtkAction *action; - GtkActionGroup *action_group; + EUIAction *action; + EUIActionGroup *action_group; g_return_if_fail (e_shell_view_is_active (shell_view)); @@ -762,11 +2123,11 @@ shell_view_update_actions (EShellView *shell_view) e_focus_tracker_update_actions (focus_tracker); - action_group = E_SHELL_WINDOW_ACTION_GROUP_CUSTOM_RULES (shell_window); - gtk_action_group_set_sensitive (action_group, TRUE); + action_group = e_ui_manager_get_action_group (shell_view->priv->ui_manager, "custom-rules"); + e_ui_action_group_set_sensitive (action_group, TRUE); - action = E_SHELL_WINDOW_ACTION_SEARCH_ADVANCED (shell_window); - gtk_action_set_sensitive (action, TRUE); + action = e_ui_manager_get_action (shell_view->priv->ui_manager, "search-advanced"); + e_ui_action_set_sensitive (action, TRUE); } static void @@ -778,6 +2139,8 @@ e_shell_view_class_init (EShellViewClass *class) if (EShellView_private_offset != 0) g_type_class_adjust_private_offset (class, &EShellView_private_offset); + gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), "EShellView"); + object_class = G_OBJECT_CLASS (class); object_class->set_property = shell_view_set_property; object_class->get_property = shell_view_get_property; @@ -796,24 +2159,25 @@ e_shell_view_class_init (EShellViewClass *class) class->construct_searchbar = shell_view_construct_searchbar; class->get_search_name = shell_view_get_search_name; - class->toggled = shell_view_toggled; class->clear_search = shell_view_clear_search; class->custom_search = shell_view_custom_search; class->update_actions = shell_view_update_actions; /** - * EShellView:action: + * EShellView:switcher-action: * - * The #GtkRadioAction registered with #EShellSwitcher. + * The #EUIAction registered with #EShellSwitcher. + * + * Since: 3.56 **/ g_object_class_install_property ( object_class, - PROP_ACTION, + PROP_SWITCHER_ACTION, g_param_spec_object ( - "action", + "switcher-action", "Switcher Action", "The switcher action for this shell view", - GTK_TYPE_RADIO_ACTION, + E_TYPE_UI_ACTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); @@ -1002,27 +2366,113 @@ e_shell_view_class_init (EShellViewClass *class) G_PARAM_READWRITE)); /** - * EShellView::toggled - * @shell_view: the #EShellView which emitted the signal + * EShellView:menubar-visible * - * Emitted when @shell_view is activated or deactivated. - * Use e_shell_view_is_active() to find out which event has - * occurred. The shell view being deactivated is always - * notified before the shell view being activated. + * Whether the menu bar is visible. * - * By default, #EShellView adds the UI definition file - * given in the ui_definition - * field of #EShellViewClass on activation, and removes the - * UI definition on deactivation. + * Since: 3.56 **/ - signals[TOGGLED] = g_signal_new ( - "toggled", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EShellViewClass, toggled), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_object_class_install_property ( + object_class, + PROP_MENUBAR_VISIBLE, + g_param_spec_boolean ( + "menubar-visible", + "Menubar Visible", + "Whether the shell view's menu bar is visible", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * EShellView:sidebar-visible + * + * Whether the side bar is visible. + * + * Since: 3.56 + **/ + g_object_class_install_property ( + object_class, + PROP_SIDEBAR_VISIBLE, + g_param_spec_boolean ( + "sidebar-visible", + "Sidebar Visible", + "Whether the shell view's side bar is visible", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * EShellView:switcher-visible + * + * Whether the switcher buttons are visible. + * + * Since: 3.56 + **/ + g_object_class_install_property ( + object_class, + PROP_SWITCHER_VISIBLE, + g_param_spec_boolean ( + "switcher-visible", + "Switcher Visible", + "Whether the shell view's switcher buttons are visible", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * EShellView:taskbar-visible + * + * Whether the task bar is visible. + * + * Since: 3.56 + **/ + g_object_class_install_property ( + object_class, + PROP_TASKBAR_VISIBLE, + g_param_spec_boolean ( + "taskbar-visible", + "Taskbar Visible", + "Whether the shell view's task bar is visible", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * EShellView:toolbar-visible + * + * Whether the tool bar is visible. + * + * Since: 3.56 + **/ + g_object_class_install_property ( + object_class, + PROP_TOOLBAR_VISIBLE, + g_param_spec_boolean ( + "toolbar-visible", + "Toolbar Visible", + "Whether the shell view's tool bar is visible", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * EShellView:sidebar-width + * + * Width of the side bar, in pixels. + * + * Since: 3.56 + **/ + g_object_class_install_property ( + object_class, + PROP_SIDEBAR_WIDTH, + g_param_spec_int ( + "sidebar-width", + "Sidebar Width", + "Width of the side bar, in pixels", + 0, G_MAXINT, 128, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); /** * EShellView::clear-search @@ -1082,10 +2532,10 @@ e_shell_view_class_init (EShellViewClass *class) * #EShellView subclasses should override the * update_actions method in * #EShellViewClass to update sensitivities, labels, or any - * other aspect of the #GtkActions they have registered. + * other aspect of the actions they have registered. * * Plugins can also connect to this signal to be notified - * when to update their own #GtkActions. + * when to update their own actions. **/ signals[UPDATE_ACTIONS] = g_signal_new ( "update-actions", @@ -1095,13 +2545,37 @@ e_shell_view_class_init (EShellViewClass *class) NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + + /** + * EShellView::init-ui-data + * @shell_view: the #EShellView which emitted the signal + * + * #EShellView subclasses should override the + * init_ui_data method in + * #EShellViewClass to add any actions and UI definitions. + * The @shell_view automatically adds UI definition from + * ui_definition class property + * after this signal is emitted. + * + * Since: 3.56 + **/ + signals[INIT_UI_DATA] = g_signal_new ( + "init-ui-data", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (EShellViewClass, init_ui_data), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void e_shell_view_init (EShellView *shell_view, EShellViewClass *class) { - GtkSizeGroup *size_group; + GtkStyleContext *style_context; + GtkCssProvider *provider; + GError *local_error = NULL; /* XXX Our use of GInstanceInitFunc's 'class' parameter * prevents us from using G_DEFINE_ABSTRACT_TYPE. */ @@ -1112,12 +2586,30 @@ e_shell_view_init (EShellView *shell_view, if (class->view_collection == NULL) shell_view_init_view_collection (class); - size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); - shell_view->priv = e_shell_view_get_instance_private (shell_view); shell_view->priv->main_thread = g_thread_self (); shell_view->priv->state_key_file = g_key_file_new (); - shell_view->priv->size_group = size_group; + shell_view->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); + shell_view->priv->ui_manager = e_ui_manager_new (); + shell_view->priv->new_menu = g_menu_new (); + shell_view->priv->gal_view_list_menu = g_menu_new (); + shell_view->priv->saved_searches_menu = g_menu_new (); + + provider = gtk_css_provider_new (); + + if (!gtk_css_provider_load_from_data (provider, "EShellView { padding:0px; margin:0px; border:0px; }", -1, &local_error)) + g_critical ("%s: Failed to load CSS data: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error"); + + g_clear_error (&local_error); + + style_context = gtk_widget_get_style_context (GTK_WIDGET (shell_view)); + gtk_style_context_add_provider (style_context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + g_clear_object (&provider); + + gtk_widget_set_visible (GTK_WIDGET (shell_view), TRUE); + + g_signal_connect (shell_view->priv->ui_manager, "create-item", + G_CALLBACK (shell_view_ui_manager_create_item_cb), shell_view); } GType @@ -1146,7 +2638,7 @@ e_shell_view_get_type (void) }; type = g_type_register_static ( - G_TYPE_OBJECT, "EShellView", + GTK_TYPE_BOX, "EShellView", &type_info, G_TYPE_FLAG_ABSTRACT); EShellView_private_offset = g_type_add_instance_private (type, sizeof (EShellViewPrivate)); @@ -1171,37 +2663,85 @@ e_shell_view_get_type (void) const gchar * e_shell_view_get_name (EShellView *shell_view) { - GtkAction *action; + EUIAction *action; + GVariant *target; + const gchar *view_name; g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); - action = e_shell_view_get_action (shell_view); + action = e_shell_view_get_switcher_action (shell_view); + target = e_ui_action_ref_target (action); + view_name = g_variant_get_string (target, NULL); + /* technically speaking, the `view_name` can vanish after the following line, but + the `target` is left unchanged and alive together with the `action`, which + the `shell_view` owns */ + g_clear_pointer (&target, g_variant_unref); - /* Switcher actions have a secret "view-name" data value. - * This gets set in e_shell_window_create_switcher_actions(). */ - return g_object_get_data (G_OBJECT (action), "view-name"); + return view_name; +} + +/** + * e_shell_view_get_ui_manager: + * @shell_view: an #EShellView + * + * Returns the view's #EUIManager. It can be used to add UI elemenrs + * related to the @shell_view itself. + * + * Returns: (transfer none): the view's UI manager + * + * Since: 3.56 + **/ +EUIManager * +e_shell_view_get_ui_manager (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return shell_view->priv->ui_manager; } /** * e_shell_view_get_action: * @shell_view: an #EShellView + * @name: action name to get + * + * Returns an @EUIAction named @name. + * + * Returns: (transfer none) (nullable): an @EUIAction named @name, or %NULL, + * when no such exists + * + * Since: 3.56 + **/ +EUIAction * +e_shell_view_get_action (EShellView *shell_view, + const gchar *name) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return e_ui_manager_get_action (shell_view->priv->ui_manager, name); +} + +/** + * e_shell_view_get_switcher_action: + * @shell_view: an #EShellView * * Returns the switcher action for @shell_view. * - * An #EShellWindow creates a #GtkRadioAction for each registered subclass + * An #EShellWindow creates an #EUIAction for each registered subclass * of #EShellView. This action gets passed to the #EShellSwitcher, which * displays a button that proxies the action. The icon at the top of the * sidebar also proxies the action. When @shell_view is active, the * action's icon becomes the #EShellWindow icon. * - * Returns: the switcher action for @shell_view + * Returns: (transfer none): the switcher action for @shell_view + * + * Since: 3.56 **/ -GtkAction * -e_shell_view_get_action (EShellView *shell_view) +EUIAction * +e_shell_view_get_switcher_action (EShellView *shell_view) { g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); - return shell_view->priv->action; + return shell_view->priv->switcher_action; } /** @@ -1251,6 +2791,295 @@ e_shell_view_set_title (EShellView *shell_view, g_object_notify (G_OBJECT (shell_view), "title"); } +static void +shell_view_menubar_info_response_cb (EAlert *alert, + gint response_id, + gpointer user_data) +{ + GWeakRef *weakref = user_data; + + g_return_if_fail (weakref != NULL); + + if (response_id == GTK_RESPONSE_APPLY) { + EShellView *shell_view; + + shell_view = g_weak_ref_get (weakref); + if (shell_view) { + e_shell_view_set_menubar_visible (shell_view, TRUE); + g_object_unref (shell_view); + } + } +} + +/** + * e_shell_view_get_menubar_visible: + * @shell_view: an #EShellView + * + * Returns %TRUE if @shell_view's menu bar is visible. + * + * Returns: %TRUE is the menu bar is visible + * + * Since: 3.56 + **/ +gboolean +e_shell_view_get_menubar_visible (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), FALSE); + + return shell_view->priv->menu_bar && + e_menu_bar_get_visible (shell_view->priv->menu_bar); +} + +/** + * e_shell_view_set_menubar_visible: + * @shell_view: an #EShellView + * @menubar_visible: whether the menu bar should be visible + * + * Makes @shell_view's menu bar visible or invisible. + * + * Since: 3.56 + **/ +void +e_shell_view_set_menubar_visible (EShellView *shell_view, + gboolean menubar_visible) +{ + GSettings *settings; + + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + if ((e_shell_view_get_menubar_visible (shell_view) ? 1 : 0) == (menubar_visible ? 1 : 0)) + return; + + e_menu_bar_set_visible (shell_view->priv->menu_bar, menubar_visible); + + settings = e_util_ref_settings ("org.gnome.evolution.shell"); + if (!menubar_visible && + g_settings_get_boolean (settings, e_shell_window_is_main_instance (shell_view->priv->shell_window) ? "menubar-visible" : "menubar-visible-sub")) { + /* The menu bar had been just hidden. Show a hint how to enable it. */ + EShellContent *shell_content; + EAlert *alert; + + shell_content = e_shell_view_get_shell_content (shell_view); + + alert = e_alert_new ("shell:menubar-hidden", NULL); + + g_signal_connect_data (alert, "response", G_CALLBACK (shell_view_menubar_info_response_cb), + e_weak_ref_new (shell_view), (GClosureNotify) e_weak_ref_free, 0); + + e_alert_sink_submit_alert (E_ALERT_SINK (shell_content), alert); + e_alert_start_timer (alert, 30); + g_object_unref (alert); + } + g_object_unref (settings); + + g_object_notify (G_OBJECT (shell_view), "menubar-visible"); +} + +/** + * e_shell_view_get_sidebar_visible: + * @shell_view: an #EShellView + * + * Returns %TRUE if @shell_view's side bar is visible. + * + * Returns: %TRUE is the side bar is visible + * + * Since: 3.56 + **/ +gboolean +e_shell_view_get_sidebar_visible (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), FALSE); + + return shell_view->priv->sidebar_visible; +} + +/** + * e_shell_view_set_sidebar_visible: + * @shell_view: an #EShellView + * @sidebar_visible: whether the side bar should be visible + * + * Makes @shell_view's side bar visible or invisible. + * + * Since: 3.56 + **/ +void +e_shell_view_set_sidebar_visible (EShellView *shell_view, + gboolean sidebar_visible) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + if (shell_view->priv->sidebar_visible == sidebar_visible) + return; + + shell_view->priv->sidebar_visible = sidebar_visible; + + g_object_notify (G_OBJECT (shell_view), "sidebar-visible"); +} + +/** + * e_shell_view_get_switcher_visible: + * @shell_view: an #EShellView + * + * Returns %TRUE if @shell_view's switcher buttons are visible. + * + * Returns: %TRUE is the switcher buttons are visible + * + * Since: 3.56 + **/ +gboolean +e_shell_view_get_switcher_visible (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), FALSE); + + return shell_view->priv->switcher_visible; +} + +/** + * e_shell_view_set_switcher_visible: + * @shell_view: an #EShellView + * @switcher_visible: whether the switcher buttons should be visible + * + * Makes @shell_view's switcher buttons visible or invisible. + * + * Since: 3.56 + **/ +void +e_shell_view_set_switcher_visible (EShellView *shell_view, + gboolean switcher_visible) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + if (shell_view->priv->switcher_visible == switcher_visible) + return; + + shell_view->priv->switcher_visible = switcher_visible; + + g_object_notify (G_OBJECT (shell_view), "switcher-visible"); +} + +/** + * e_shell_view_get_taskbar_visible: + * @shell_view: an #EShellView + * + * Returns %TRUE if @shell_view's task bar is visible. + * + * Returns: %TRUE is the task bar is visible + * + * Since: 3.56 + **/ +gboolean +e_shell_view_get_taskbar_visible (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), FALSE); + + return shell_view->priv->taskbar_visible; +} + +/** + * e_shell_view_set_taskbar_visible: + * @shell_view: an #EShellView + * @taskbar_visible: whether the task bar should be visible + * + * Makes @shell_view's task bar visible or invisible. + * + * Since: 3.56 + **/ +void +e_shell_view_set_taskbar_visible (EShellView *shell_view, + gboolean taskbar_visible) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + if (shell_view->priv->taskbar_visible == taskbar_visible) + return; + + shell_view->priv->taskbar_visible = taskbar_visible; + + g_object_notify (G_OBJECT (shell_view), "taskbar-visible"); +} + +/** + * e_shell_view_get_toolbar_visible: + * @shell_view: an #EShellView + * + * Returns %TRUE if @shell_view's tool bar is visible. + * + * Returns: %TRUE if the tool bar is visible + * + * Since: 3.56 + **/ +gboolean +e_shell_view_get_toolbar_visible (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), FALSE); + + return shell_view->priv->toolbar_visible; +} + +/** + * e_shell_view_set_toolbar_visible: + * @shell_view: an #EShellView + * @toolbar_visible: whether the tool bar should be visible + * + * Makes @shell_view's tool bar visible or invisible. + * + * Since: 3.56 + **/ +void +e_shell_view_set_toolbar_visible (EShellView *shell_view, + gboolean toolbar_visible) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + if (shell_view->priv->toolbar_visible == toolbar_visible) + return; + + shell_view->priv->toolbar_visible = toolbar_visible; + + g_object_notify (G_OBJECT (shell_view), "toolbar-visible"); +} + +/** + * e_shell_view_get_sidebar_width: + * @shell_view: an #EShellView + * + * Gets width of the sidebar, in pixels. + * + * Returns: width of the side bar, in pixels + * + * Since: 3.56 + **/ +gint +e_shell_view_get_sidebar_width (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), 0); + + return shell_view->priv->sidebar_width; +} + +/** + * e_shell_view_set_sidebar_width: + * @shell_view: an #EShellView + * @width: width in pixels + * + * Sets width of the sidebar, in pixels. + * + * Since: 3.56 + **/ +void +e_shell_view_set_sidebar_width (EShellView *shell_view, + gint width) +{ + g_return_if_fail (E_IS_SHELL_VIEW (shell_view)); + + if (shell_view->priv->sidebar_width == width) + return; + + shell_view->priv->sidebar_width = width; + + g_object_notify (G_OBJECT (shell_view), "sidebar-width"); +} + /** * e_shell_view_get_view_id: * @shell_view: an #EShellView @@ -1419,6 +3248,25 @@ e_shell_view_get_shell_window (EShellView *shell_view) return E_SHELL_WINDOW (shell_view->priv->shell_window); } +/** + * e_shell_view_get_headerbar: + * @shell_view: an #EShellView + * + * Returns a header bar widget for the @shell_view. + * + * Returns: (transfer none) (nullable): a header bar widget for the @shell_view, + * or #NULL, when none is needed for it. + * + * Since: 3.56 + **/ +GtkWidget * +e_shell_view_get_headerbar (EShellView *shell_view) +{ + g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); + + return shell_view->priv->headerbar; +} + /** * e_shell_view_is_active: * @shell_view: an #EShellView @@ -1427,21 +3275,21 @@ e_shell_view_get_shell_window (EShellView *shell_view) * visible in its #EShellWindow. An #EShellWindow can only display one * shell view at a time. * - * Technically this just checks the #GtkToggleAction:active property of - * the shell view's switcher action. See e_shell_view_get_action(). + * Technically this just checks the shell view's switcher action "active" property. + * See e_shell_view_get_switcher_action(). * * Returns: %TRUE if @shell_view is active **/ gboolean e_shell_view_is_active (EShellView *shell_view) { - GtkAction *action; + EUIAction *action; g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), FALSE); - action = e_shell_view_get_action (shell_view); + action = e_shell_view_get_switcher_action (shell_view); - return gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); + return e_ui_action_get_active (action); } /** @@ -1861,7 +3709,7 @@ e_shell_view_is_execute_search_blocked (EShellView *shell_view) * * #EShellView subclasses should implement the * update_actions method in #EShellViewClass - * to update the various #GtkActions based on the current + * to update the various actions based on the current * #EShellSidebar and #EShellContent selections. The * #EShellView::update-actions signal is typically emitted just before * showing a popup menu or just after the user selects an item in the @@ -1878,7 +3726,11 @@ e_shell_view_update_actions (EShellView *shell_view) shell_view->priv->update_actions_idle_id = 0; } + e_ui_manager_freeze (shell_view->priv->ui_manager); + g_signal_emit (shell_view, signals[UPDATE_ACTIONS], 0); + + e_ui_manager_thaw (shell_view->priv->ui_manager); } } @@ -1916,20 +3768,10 @@ e_shell_view_update_actions_in_idle (EShellView *shell_view) shell_view_call_update_actions_idle, shell_view); } -static void -e_shell_view_popup_menu_deactivate (GtkMenu *popup_menu, - gpointer user_data) -{ - g_return_if_fail (GTK_IS_MENU (popup_menu)); - - g_signal_handlers_disconnect_by_func (popup_menu, e_shell_view_popup_menu_deactivate, user_data); - gtk_menu_detach (popup_menu); -} - /** * e_shell_view_show_popup_menu: * @shell_view: an #EShellView - * @widget_path: path in the UI definition + * @menu_name: name of the menu in the UI definition * @button_event: a #GdkEvent, or %NULL * * Displays a context-sensitive (or "popup") menu that is described in @@ -1940,35 +3782,50 @@ e_shell_view_popup_menu_deactivate (GtkMenu *popup_menu, * showing the menu to give @shell_view and any plugins that extend * @shell_view a chance to update the menu's actions. * - * Returns: the popup menu being displayed + * The returned #GtkMenu is automatically destroyed once the user + * either selects an item from it or when it's dismissed. + * + * Returns: (transfer none): the popup menu being displayed + * + * Since: 3.56 **/ GtkWidget * e_shell_view_show_popup_menu (EShellView *shell_view, - const gchar *widget_path, + const gchar *menu_name, GdkEvent *button_event) { - EShellWindow *shell_window; - GtkWidget *menu; + GObject *ui_item; + GtkWidget *widget; + GtkMenu *menu; g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL); e_shell_view_update_actions (shell_view); - shell_window = e_shell_view_get_shell_window (shell_view); - menu = e_shell_window_get_managed_widget (shell_window, widget_path); - g_return_val_if_fail (GTK_IS_MENU (menu), NULL); + ui_item = e_ui_manager_create_item (shell_view->priv->ui_manager, menu_name); - if (!gtk_menu_get_attach_widget (GTK_MENU (menu))) { - gtk_menu_attach_to_widget (GTK_MENU (menu), - GTK_WIDGET (shell_window), - NULL); - - g_signal_connect (menu, "deactivate", G_CALLBACK (e_shell_view_popup_menu_deactivate), NULL); + if (!ui_item) { + g_warning ("%s: Cannot find menu '%s' in %s", G_STRFUNC, menu_name, G_OBJECT_TYPE_NAME (shell_view)); + return NULL; } - gtk_menu_popup_at_pointer (GTK_MENU (menu), button_event); + if (!G_IS_MENU_MODEL (ui_item)) { + g_warning ("%s: Object '%s' is not a GMenuItem, but %s instead", G_STRFUNC, menu_name, G_OBJECT_TYPE_NAME (ui_item)); + g_clear_object (&ui_item); + return NULL; + } - return menu; + widget = gtk_menu_new_from_model (G_MENU_MODEL (ui_item)); + g_clear_object (&ui_item); + + menu = GTK_MENU (widget); + + gtk_menu_attach_to_widget (menu, GTK_WIDGET (shell_view), NULL); + e_util_connect_menu_detach_after_deactivate (menu); + + gtk_menu_popup_at_pointer (menu, button_event); + + return widget; } /** @@ -2130,3 +3987,23 @@ e_shell_view_submit_thread_job (EShellView *shell_view, return activity; } + +gboolean +e_shell_view_util_layout_to_state_cb (GValue *value, + GVariant *variant, + gpointer user_data) +{ + g_value_set_variant (value, variant); + return TRUE; +} + +GVariant * +e_shell_view_util_state_to_layout_cb (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + GVariant *var = g_value_get_variant (value); + if (var) + g_variant_ref_sink (var); + return var; +} diff --git a/src/shell/e-shell-view.h b/src/shell/e-shell-view.h index b987e5739b..f92fc44a5b 100644 --- a/src/shell/e-shell-view.h +++ b/src/shell/e-shell-view.h @@ -51,6 +51,9 @@ (G_TYPE_INSTANCE_GET_CLASS \ ((obj), E_TYPE_SHELL_VIEW, EShellViewClass)) +#define E_SHELL_VIEW_ACTION(view, name) \ + (e_shell_view_get_action (E_SHELL_VIEW (view), (name))) + G_BEGIN_DECLS typedef struct _EShellView EShellView; @@ -64,7 +67,7 @@ typedef struct _EShellViewPrivate EShellViewPrivate; * functions below. **/ struct _EShellView { - GObject parent; + GtkBox parent; EShellViewPrivate *priv; }; @@ -72,14 +75,14 @@ struct _EShellView { * EShellViewClass: * @parent_class: The parent class structure. * @label: The initial value for the switcher action's - * #GtkAction:label property. See - * e_shell_view_get_action(). + * #EUIAction:label property. See + * e_shell_view_get_view_action(). * @icon_name: The initial value for the switcher action's - * #GtkAction:icon-name property. See - * e_shell_view_get_action(). + * #EUIAction:icon-name property. See + * e_shell_view_get_view_action(). * @ui_definition: Base name of the UI definition file to add * when the shell view is activated. - * @ui_manager_id: The #GtkUIManager ID for #EPluginUI. Plugins + * @ui_manager_id: The #EUIManager ID for #EPluginUI. Plugins * should use to this ID in their "eplug" files to * add menu and toolbar items to the shell view. * @search_context_type:GType of the search context, which should be an @@ -117,9 +120,6 @@ struct _EShellView { * @get_search_name: Class method to obtain a suitable name for the * current search criteria. Subclasses should rarely * need to override the default behavior. - * @toggled: Class method for the #EShellView::toggled signal. - * Subclasses should rarely need to override the - * default behavior. * @clear_search: Class method for the #EShellView::clear-search * signal. The default method sets the * #EShellView:search-rule to %NULL and then emits @@ -135,11 +135,14 @@ struct _EShellView { * @update_actions: Class method for the #EShellView::update-actions * signal. There is no default behavior; subclasses * should override this. + * @init_ui_data: Class method for the #EShellView::init-ui-data signal. + * The subclasses can override it to add actions into + * the view's UI manager. * * #EShellViewClass contains a number of important settings for subclasses. **/ struct _EShellViewClass { - GObjectClass parent_class; + GtkBoxClass parent_class; /* Initial switcher action values. */ const gchar *label; @@ -148,7 +151,7 @@ struct _EShellViewClass { /* Base name of the UI definition file. */ const gchar *ui_definition; - /* GtkUIManager identifier for use with EPluginUI. + /* EUIManager identifier for use with EPluginUI. * Usually "org.gnome.evolution.$(VIEW_NAME)". */ const gchar *ui_manager_id; @@ -157,9 +160,6 @@ struct _EShellViewClass { GType search_context_type; ERuleContext *search_context; - /* Widget path to the search options popup menu. */ - const gchar *search_options; - /* Base name of the search rule definition file. */ const gchar *search_rules; @@ -180,20 +180,43 @@ struct _EShellViewClass { gchar * (*get_search_name) (EShellView *shell_view); /* Signals */ - void (*toggled) (EShellView *shell_view); void (*clear_search) (EShellView *shell_view); void (*custom_search) (EShellView *shell_view, EFilterRule *custom_rule); void (*execute_search) (EShellView *shell_view); void (*update_actions) (EShellView *shell_view); + void (*init_ui_data) (EShellView *shell_view); }; GType e_shell_view_get_type (void); const gchar * e_shell_view_get_name (EShellView *shell_view); -GtkAction * e_shell_view_get_action (EShellView *shell_view); +EUIManager * e_shell_view_get_ui_manager (EShellView *shell_view); +EUIAction * e_shell_view_get_action (EShellView *shell_view, + const gchar *name); +EUIAction * e_shell_view_get_switcher_action(EShellView *shell_view); const gchar * e_shell_view_get_title (EShellView *shell_view); void e_shell_view_set_title (EShellView *shell_view, const gchar *title); +gboolean e_shell_view_get_menubar_visible(EShellView *shell_view); +void e_shell_view_set_menubar_visible(EShellView *shell_view, + gboolean menubar_visible); +gboolean e_shell_view_get_sidebar_visible(EShellView *shell_view); +void e_shell_view_set_sidebar_visible(EShellView *shell_view, + gboolean sidebar_visible); +gboolean e_shell_view_get_switcher_visible + (EShellView *shell_view); +void e_shell_view_set_switcher_visible + (EShellView *shell_view, + gboolean switcher_visible); +gboolean e_shell_view_get_taskbar_visible(EShellView *shell_view); +void e_shell_view_set_taskbar_visible(EShellView *shell_view, + gboolean taskbar_visible); +gboolean e_shell_view_get_toolbar_visible(EShellView *shell_view); +void e_shell_view_set_toolbar_visible(EShellView *shell_view, + gboolean toolbar_visible); +gint e_shell_view_get_sidebar_width (EShellView *shell_view); +void e_shell_view_set_sidebar_width (EShellView *shell_view, + gint width); const gchar * e_shell_view_get_view_id (EShellView *shell_view); void e_shell_view_set_view_id (EShellView *shell_view, const gchar *view_id); @@ -220,6 +243,7 @@ EShellContent * e_shell_view_get_shell_content (EShellView *shell_view); EShellSidebar * e_shell_view_get_shell_sidebar (EShellView *shell_view); EShellTaskbar * e_shell_view_get_shell_taskbar (EShellView *shell_view); EShellWindow * e_shell_view_get_shell_window (EShellView *shell_view); +GtkWidget * e_shell_view_get_headerbar (EShellView *shell_view); GKeyFile * e_shell_view_get_state_key_file (EShellView *shell_view); void e_shell_view_set_state_dirty (EShellView *shell_view); void e_shell_view_save_state_immediately @@ -238,7 +262,7 @@ void e_shell_view_update_actions (EShellView *shell_view); void e_shell_view_update_actions_in_idle (EShellView *shell_view); GtkWidget * e_shell_view_show_popup_menu (EShellView *shell_view, - const gchar *widget_path, + const gchar *menu_name, GdkEvent *button_event); void e_shell_view_write_source (EShellView *shell_view, ESource *source); @@ -256,6 +280,15 @@ EActivity * e_shell_view_submit_thread_job (EShellView *shell_view, gpointer user_data, GDestroyNotify free_user_data); +gboolean e_shell_view_util_layout_to_state_cb + (GValue *value, + GVariant *variant, + gpointer user_data); +GVariant * e_shell_view_util_state_to_layout_cb + (const GValue *value, + const GVariantType *expected_type, + gpointer user_data); + G_END_DECLS #endif /* E_SHELL_VIEW_H */ diff --git a/src/shell/e-shell-window-actions.c b/src/shell/e-shell-window-actions.c index e646a42abd..b88cfa58b8 100644 --- a/src/shell/e-shell-window-actions.c +++ b/src/shell/e-shell-window-actions.c @@ -22,6 +22,8 @@ #include "e-shell-window-private.h" +static void e_shell_window_create_views_actions (EShellWindow *shell_window); + /** * E_SHELL_WINDOW_ACTION_ABOUT: * @window: an #EShellWindow @@ -31,16 +33,20 @@ * Main menu item: Help -> About **/ static void -action_about_cb (GtkAction *action, - EShellWindow *shell_window) +action_about_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; e_shell_utils_run_help_about (e_shell_window_get_shell (shell_window)); } static void -action_accounts_cb (GtkAction *action, - EShellWindow *shell_window) +action_accounts_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; static GtkWidget *accounts_window = NULL; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); @@ -70,9 +76,11 @@ action_accounts_cb (GtkAction *action, * Main menu item: File -> Close **/ static void -action_close_cb (GtkAction *action, - EShellWindow *shell_window) +action_close_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; GtkWidget *widget; GdkWindow *window; GdkEvent *event; @@ -97,16 +105,20 @@ action_close_cb (GtkAction *action, * Main menu item: Help -> Contents **/ static void -action_contents_cb (GtkAction *action, - EShellWindow *shell_window) +action_contents_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; e_shell_utils_run_help_contents (e_shell_window_get_shell (shell_window)); } static void -action_shortcuts_cb (GtkAction *action, - EShellWindow *shell_window) +action_shortcuts_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; GtkBuilder *builder; GtkWidget *widget; @@ -121,144 +133,6 @@ action_shortcuts_cb (GtkAction *action, g_object_unref (builder); } -static void -action_custom_rule_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EFilterRule *rule; - EShellView *shell_view; - const gchar *view_name; - - rule = g_object_get_data (G_OBJECT (action), "rule"); - g_return_if_fail (rule != NULL); - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - - rule = g_object_get_data (G_OBJECT (action), "rule"); - g_return_if_fail (E_IS_FILTER_RULE (rule)); - - e_shell_view_custom_search (shell_view, rule); -} - -/** - * E_SHELL_WINDOW_ACTION_GAL_DELETE_VIEW: - * @window: an #EShellWindow - * - * Activation of this action deletes the current user-created GAL view. - * - * Main menu item: View -> Current View -> Delete Current View - **/ -static void -action_gal_delete_view_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - GalViewInstance *view_instance; - const gchar *view_name; - gchar *gal_view_id; - gint index = -1; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - view_instance = e_shell_view_get_view_instance (shell_view); - g_return_if_fail (view_instance != NULL); - - /* XXX This is kinda cumbersome. The view collection API - * should be using only view ID's, not index numbers. */ - gal_view_id = gal_view_instance_get_current_view_id (view_instance); - if (gal_view_id != NULL) { - index = gal_view_collection_get_view_index_by_id ( - view_instance->collection, gal_view_id); - g_free (gal_view_id); - } - - gal_view_collection_delete_view (view_instance->collection, index); - - gal_view_collection_save (view_instance->collection); -} - -/** - * E_SHELL_WINDOW_ACTION_GAL_CUSTOM_VIEW: - * @window: an #EShellWindow - * - * This radio action is selected when using a custom GAL view that has - * not been saved. - * - * Main menu item: View -> Current View -> Custom View - **/ -static void -action_gal_view_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellWindow *shell_window) -{ - EShellView *shell_view; - const gchar *view_name; - const gchar *view_id; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - view_id = g_object_get_data (G_OBJECT (current), "view-id"); - e_shell_view_set_view_id (shell_view, view_id); -} - -/** - * E_SHELL_WINDOW_ACTION_GAL_SAVE_CUSTOM_VIEW: - * @window: an #EShellWindow - * - * Activation of this action saves a custom GAL view. - * - * Main menu item: View -> Current View -> Save Custom View... - **/ -static void -action_gal_save_custom_view_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - GalViewInstance *view_instance; - const gchar *view_name; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - view_instance = e_shell_view_get_view_instance (shell_view); - - gal_view_instance_save_as (view_instance); -} - -static void -action_gal_customize_view_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - GalViewInstance *view_instance; - GalView *gal_view; - const gchar *view_name; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - view_instance = e_shell_view_get_view_instance (shell_view); - - gal_view = gal_view_instance_get_current_view (view_instance); - - if (GAL_IS_VIEW_ETABLE (gal_view)) { - GalViewEtable *etable_view = GAL_VIEW_ETABLE (gal_view); - ETable *etable; - - etable = gal_view_etable_get_table (etable_view); - - if (etable) { - e_table_customize_view (etable); - } else { - ETree *etree; - - etree = gal_view_etable_get_tree (etable_view); - - if (etree) - e_tree_customize_view (etree); - } - } -} - /** * E_SHELL_WINDOW_ACTION_IMPORT: * @window: an #EShellWindow @@ -268,9 +142,11 @@ action_gal_customize_view_cb (GtkAction *action, * Main menu item: File -> Import... **/ static void -action_import_cb (GtkAction *action, - EShellWindow *shell_window) +action_import_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; GtkWidget *assistant; assistant = e_import_assistant_new (GTK_WINDOW (shell_window)); @@ -299,9 +175,11 @@ action_import_cb (GtkAction *action, * Main menu item: File -> New Window **/ static void -action_new_window_cb (GtkAction *action, - EShellWindow *shell_window) +action_new_window_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; EShellView *shell_view; const gchar *view_name; @@ -326,9 +204,11 @@ action_new_window_cb (GtkAction *action, * Main menu item: File -> Page Setup... **/ static void -action_page_setup_cb (GtkAction *action, - EShellWindow *shell_window) +action_page_setup_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; e_print_run_page_setup_dialog (GTK_WINDOW (shell_window)); } @@ -341,9 +221,11 @@ action_page_setup_cb (GtkAction *action, * Main menu item: Edit -> Available categories **/ static void -action_categories_cb (GtkAction *action, - EShellWindow *shell_window) +action_categories_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; GtkWidget *content_area; GtkWidget *dialog; GtkWidget *editor; @@ -381,9 +263,11 @@ action_categories_cb (GtkAction *action, * Main menu item: Edit -> Preferences **/ static void -action_preferences_cb (GtkAction *action, - EShellWindow *shell_window) +action_preferences_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; e_shell_utils_run_preferences (e_shell_window_get_shell (shell_window)); } @@ -396,214 +280,17 @@ action_preferences_cb (GtkAction *action, * Main menu item: File -> Quit **/ static void -action_quit_cb (GtkAction *action, - EShellWindow *shell_window) +action_quit_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; shell = e_shell_window_get_shell (shell_window); e_shell_quit (shell, E_SHELL_QUIT_ACTION); } -/** - * E_SHELL_WINDOW_ACTION_SEARCH_ADVANCED: - * @window: an #EShellWindow - * - * Activation of this action opens an Advanced Search dialog. - * - * Main menu item: Search -> Advanced Search... - **/ -static void -action_search_advanced_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - EShellContent *shell_content; - const gchar *view_name; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - shell_content = e_shell_view_get_shell_content (shell_view); - - e_shell_content_run_advanced_search_dialog (shell_content); - e_shell_window_update_search_menu (shell_window); -} - -/** - * E_SHELL_WINDOW_ACTION_SEARCH_CLEAR: - * @window: an #EShellWindow - * - * Activation of this action clears the most recent search results. - * - * Main menu item: Search -> Clear - **/ -static void -action_search_clear_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - const gchar *view_name; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - - e_shell_view_clear_search (shell_view); -} - -/** - * E_SHELL_WINDOW_ACTION_SEARCH_EDIT: - * @window: an #EShellWindow - * - * Activation of this action opens a dialog for editing saved searches. - * - * Main menu item: Search -> Edit Saved Searches... - **/ -static void -action_search_edit_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - EShellContent *shell_content; - const gchar *view_name; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - shell_content = e_shell_view_get_shell_content (shell_view); - - e_shell_content_run_edit_searches_dialog (shell_content); - e_shell_window_update_search_menu (shell_window); -} - -static EShellSearchbar * -shell_window_get_search_bar (EShellWindow *shell_window) -{ - EShellView *shell_view; - const gchar *view_name; - - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL); - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - g_return_val_if_fail (shell_view != NULL, NULL); - - return E_SHELL_SEARCHBAR (e_shell_view_get_searchbar (shell_view)); -} - -static void -search_options_selection_cancel_cb (GtkMenuShell *menu, - EShellWindow *shell_window); - -static void -search_options_selection_done_cb (GtkMenuShell *menu, - EShellWindow *shell_window) -{ - EShellSearchbar *search_bar; - - /* disconnect first */ - g_signal_handlers_disconnect_by_func (menu, search_options_selection_done_cb, shell_window); - g_signal_handlers_disconnect_by_func (menu, search_options_selection_cancel_cb, shell_window); - - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - search_bar = shell_window_get_search_bar (shell_window); - e_shell_searchbar_search_entry_grab_focus (search_bar); -} - -static void -search_options_selection_cancel_cb (GtkMenuShell *menu, - EShellWindow *shell_window) -{ - /* only disconnect both functions, thus the selection-done is not called */ - g_signal_handlers_disconnect_by_func (menu, search_options_selection_done_cb, shell_window); - g_signal_handlers_disconnect_by_func (menu, search_options_selection_cancel_cb, shell_window); -} - -/** - * E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS: - * @window: an #EShellWindow - * - * Activation of this action displays a menu of search options. - * This appears as a "find" icon in the window's search entry. - **/ -static void -action_search_options_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - EShellViewClass *shell_view_class; - EShellSearchbar *search_bar; - const gchar *view_name; - const gchar *widget_path; - GtkWidget *popup_menu; - - search_bar = shell_window_get_search_bar (shell_window); - if (!e_shell_searchbar_search_entry_has_focus (search_bar)) { - e_shell_searchbar_search_entry_grab_focus (search_bar); - return; - } - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view); - - widget_path = shell_view_class->search_options; - popup_menu = e_shell_view_show_popup_menu (shell_view, widget_path, NULL); - - if (popup_menu) { - g_return_if_fail (GTK_IS_MENU_SHELL (popup_menu)); - - g_signal_connect_object (popup_menu, "selection-done", - G_CALLBACK (search_options_selection_done_cb), shell_window, 0); - g_signal_connect_object (popup_menu, "cancel", - G_CALLBACK (search_options_selection_cancel_cb), shell_window, 0); - } -} - -/** - * E_SHELL_WINDOW_ACTION_SEARCH_QUICK: - * @window: an #EShellWindow - * - * Activation of this action executes the current search conditions. - * - * Main menu item: Search -> Find Now - **/ -static void -action_search_quick_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - const gchar *view_name; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - - e_shell_view_execute_search (shell_view); -} - -/** - * E_SHELL_WINDOW_ACTION_SEARCH_SAVE: - * @window: an #EShellWindow - * - * Activation of this action saves the current search conditions. - * - * Main menu item: Search -> Save Search... - **/ -static void -action_search_save_cb (GtkAction *action, - EShellWindow *shell_window) -{ - EShellView *shell_view; - EShellContent *shell_content; - const gchar *view_name; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - shell_content = e_shell_view_get_shell_content (shell_view); - - e_shell_content_run_save_search_dialog (shell_content); - e_shell_window_update_search_menu (shell_window); -} - /** * E_SHELL_WINDOW_ACTION_SHOW_MENUBAR: * @window: an #EShellWindow @@ -661,9 +348,11 @@ action_search_save_cb (GtkAction *action, * Main menu item: Help -> Submit Bug Report **/ static void -action_submit_bug_cb (GtkAction *action, - EShellWindow *shell_window) +action_submit_bug_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; const gchar *command_line; GError *error = NULL; @@ -708,9 +397,11 @@ shell_window_actions_find_webview (GtkContainer *container) } static void -action_show_webkit_gpu_cb (GtkAction *action, - EShellWindow *shell_window) +action_show_webkit_gpu_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; WebKitWebView *webview; EShellView *shell_view; EShellContent *shell_content; @@ -727,26 +418,38 @@ action_show_webkit_gpu_cb (GtkAction *action, } static void -action_switcher_cb (GtkRadioAction *action, - GtkRadioAction *current, +action_switcher_cb (EUIAction *action, + GParamSpec *param, EShellWindow *shell_window) { + GVariant *target; const gchar *view_name; - view_name = g_object_get_data (G_OBJECT (current), "view-name"); + if (!e_ui_action_get_active (action)) + return; + + target = e_ui_action_ref_target (action); + view_name = g_variant_get_string (target, NULL); + e_shell_window_switch_to_view (shell_window, view_name); + + g_clear_pointer (&target, g_variant_unref); } static void -action_new_view_window_cb (GtkAction *action, - EShellWindow *shell_window) +action_new_view_window_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; + GVariant *target; const gchar *view_name; gchar *modified_view_name; shell = e_shell_window_get_shell (shell_window); - view_name = g_object_get_data (G_OBJECT (action), "view-name"); + target = e_ui_action_ref_target (action); + view_name = g_variant_get_string (target, NULL); /* Just a feature to not change default component, when the view name begins with a star */ @@ -754,70 +457,10 @@ action_new_view_window_cb (GtkAction *action, e_shell_create_shell_window (shell, modified_view_name); + g_clear_pointer (&target, g_variant_unref); g_free (modified_view_name); } -/** - * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_BOTH: - * @window: an #EShellWindow - * - * This radio action displays switcher buttons with icons and text. - * - * Main menu item: View -> Switcher Appearance -> Icons and Text - **/ - -/** - * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_ICONS: - * @window: an #EShellWindow - * - * This radio action displays switcher buttons with icons only. - * - * Main menu item: View -> Switcher Appearance -> Icons Only - **/ - -/** - * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_TEXT: - * @window: an #EShellWindow - * - * This radio action displays switcher buttons with text only. - * - * Main menu item: View -> Switcher Appearance -> Text Only - **/ - -/** - * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_USER: - * @window: an #EShellWindow - * - * This radio action displays switcher buttons according to the desktop - * toolbar setting. - * - * Main menu item: View -> Switcher Appearance -> Toolbar Style - **/ -static void -action_switcher_style_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellWindow *shell_window) -{ - EShellSwitcher *switcher; - GtkToolbarStyle style; - - switcher = E_SHELL_SWITCHER (shell_window->priv->switcher); - style = gtk_radio_action_get_current_value (action); - - switch (style) { - case GTK_TOOLBAR_ICONS: - case GTK_TOOLBAR_TEXT: - case GTK_TOOLBAR_BOTH: - case GTK_TOOLBAR_BOTH_HORIZ: - e_shell_switcher_set_style (switcher, style); - break; - - default: - e_shell_switcher_unset_style (switcher); - break; - } -} - /** * E_SHELL_WINDOW_ACTION_WORK_OFFLINE: * @window: an #EShellWindow @@ -827,9 +470,11 @@ action_switcher_style_cb (GtkRadioAction *action, * Main menu item: File -> Work Offline **/ static void -action_work_offline_cb (GtkAction *action, - EShellWindow *shell_window) +action_work_offline_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; GSettings *settings; @@ -853,9 +498,11 @@ action_work_offline_cb (GtkAction *action, * Main menu item: File -> Work Online **/ static void -action_work_online_cb (GtkAction *action, - EShellWindow *shell_window) +action_work_online_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; EShell *shell; GSettings *settings; @@ -871,9 +518,31 @@ action_work_online_cb (GtkAction *action, } static void -action_new_collection_account_cb (GtkAction *action, - EShellWindow *shell_window) +action_shell_window_new_shortcut_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) { + EShellWindow *shell_window = user_data; + EShellView *shell_view; + + shell_view = e_shell_window_get_shell_view (shell_window, e_shell_window_get_active_view (shell_window)); + if (shell_view) { + EUIAction *new_action; + + new_action = e_shell_view_get_action (shell_view, "EShellView::new-menu"); + if (new_action) + g_action_activate (G_ACTION (new_action), NULL); + else + g_warning ("%s: Cannot find action '%s' in %s", G_STRFUNC, "EShellView::new-menu", G_OBJECT_TYPE_NAME (shell_view)); + } +} + +static void +action_new_collection_account_cb (EUIAction *action, + GVariant *parameter, + gpointer user_data) +{ + EShellWindow *shell_window = user_data; EShell *shell; GtkWindow *window; @@ -883,11 +552,6 @@ action_new_collection_account_cb (GtkAction *action, gtk_window_present (window); } -/** - * E_SHELL_WINDOW_ACTION_GROUP_CUSTOM_RULES: - * @window: an #EShellWindow - **/ - /** * E_SHELL_WINDOW_ACTION_GROUP_GAL_VIEW: * @window: an #EShellWindow @@ -913,765 +577,329 @@ action_new_collection_account_cb (GtkAction *action, * @window: an #EShellWindow **/ -static GtkActionEntry new_source_entries[] = { - - { "new-collection-account", - "evolution", - N_("Collect_ion Account"), - NULL, - N_("Create a new collection account"), - G_CALLBACK (action_new_collection_account_cb) } -}; - -static GtkActionEntry shell_entries[] = { - - { "about", - "help-about", - N_("_About"), - NULL, - N_("Show information about Evolution"), - G_CALLBACK (action_about_cb) }, - - { "accounts", - NULL, - N_("_Accounts"), - NULL, - N_("Configure Evolution Accounts"), - G_CALLBACK (action_accounts_cb) }, - - { "close", - "window-close", - N_("_Close Window"), - "w", - N_("Close this window"), - G_CALLBACK (action_close_cb) }, - - { "close-window-menu", - "window-close", - N_("_Close"), - "w", - N_("Close this window"), - G_CALLBACK (action_close_cb) }, - - { "close-window", - "window-close", - N_("_Close Window"), - "w", - N_("Close this window"), - G_CALLBACK (action_close_cb) }, - - { "contents", - "help-browser", - N_("_Contents"), - "F1", - N_("Open the Evolution User Guide"), - G_CALLBACK (action_contents_cb) }, - - { "copy-clipboard", - "edit-copy", - N_("_Copy"), - "c", - N_("Copy the selection"), - NULL }, /* Handled by EFocusTracker */ - - { "cut-clipboard", - "edit-cut", - N_("Cu_t"), - "x", - N_("Cut the selection"), - NULL }, /* Handled by EFocusTracker */ - - { "delete-selection", - "edit-delete", - N_("_Delete"), - NULL, - N_("Delete the selection"), - NULL }, /* Handled by EFocusTracker */ - - { "import", - "stock_mail-import", - N_("I_mport…"), - NULL, - N_("Import data from other programs"), - G_CALLBACK (action_import_cb) }, - - { "new-window", - "window-new", - N_("New _Window"), - "w", - N_("Create a new window displaying this view"), - G_CALLBACK (action_new_window_cb) }, - - { "paste-clipboard", - "edit-paste", - N_("_Paste"), - "v", - N_("Paste the clipboard"), - NULL }, /* Handled by EFocusTracker */ - - { "categories", - NULL, - N_("Available Cate_gories"), - NULL, - N_("Manage available categories"), - G_CALLBACK (action_categories_cb) }, - - { "preferences", - "preferences-system", - N_("_Preferences"), - "s", - N_("Configure Evolution"), - G_CALLBACK (action_preferences_cb) }, - - { "quit", - "application-exit", - N_("_Quit"), - "q", - N_("Exit the program"), - G_CALLBACK (action_quit_cb) }, - - { "saved-searches", - NULL, - N_("_Saved Searches"), - NULL, - NULL, - NULL }, - - { "search-advanced", - NULL, - N_("_Advanced Search…"), - NULL, - N_("Construct a more advanced search"), - G_CALLBACK (action_search_advanced_cb) }, - - { "search-clear", - "edit-clear", - N_("_Clear"), - "q", - N_("Clear the current search parameters"), - G_CALLBACK (action_search_clear_cb) }, - - { "search-edit", - NULL, - N_("_Edit Saved Searches…"), - NULL, - N_("Manage your saved searches"), - G_CALLBACK (action_search_edit_cb) }, - - { "search-options", - "edit-find", - N_("_Find"), - "f", - N_("Click here to change the search type"), - G_CALLBACK (action_search_options_cb) }, - - { "search-quick", - "edit-find", - N_("_Find Now"), - NULL, - N_("Execute the current search parameters"), - G_CALLBACK (action_search_quick_cb) }, - - { "search-save", - NULL, - N_("_Save Search…"), - NULL, - N_("Save the current search parameters"), - G_CALLBACK (action_search_save_cb) }, - - { "select-all", - "edit-select-all", - N_("Select _All"), - "a", - N_("Select all text"), - NULL }, /* Handled by EFocusTracker */ - - { "shortcuts", - NULL, - N_("_Keyboard Shortcuts"), - "question", - N_("Show keyboard shortcuts"), - G_CALLBACK (action_shortcuts_cb) }, - - { "show-webkit-gpu", - NULL, - N_("Show _WebKit GPU information"), - NULL, - N_("Show WebKit GPU information page in the preview panel"), - G_CALLBACK (action_show_webkit_gpu_cb) }, - - { "submit-bug", - NULL, - N_("Submit _Bug Report…"), - NULL, - N_("Submit a bug report using Bug Buddy"), - G_CALLBACK (action_submit_bug_cb) }, - - { "work-offline", - "stock_disconnect", - N_("_Work Offline"), - NULL, - N_("Put Evolution into offline mode"), - G_CALLBACK (action_work_offline_cb) }, - - { "work-online", - "stock_connect", - N_("_Work Online"), - NULL, - N_("Put Evolution into online mode"), - G_CALLBACK (action_work_online_cb) }, - - /*** Menus ***/ - - { "edit-menu", - NULL, - N_("_Edit"), - NULL, - NULL, - NULL }, - - { "file-menu", - NULL, - N_("_File"), - NULL, - NULL, - NULL }, - - { "help-menu", - NULL, - N_("_Help"), - NULL, - NULL, - NULL }, - - { "layout-menu", - NULL, - N_("Lay_out"), - NULL, - NULL, - NULL }, - - { "new-menu", - "document-new", - /* Translators: This is a New menu item caption, under File->New */ - N_("_New"), - NULL, - NULL, - NULL }, - - { "search-menu", - NULL, - N_("_Search"), - NULL, - NULL, - NULL }, - - { "switcher-menu", - NULL, - N_("_Switcher Appearance"), - NULL, - NULL, - NULL }, - - { "view-menu", - NULL, - N_("_View"), - NULL, - NULL, - NULL }, - - { "window-menu", - NULL, - N_("_Window"), - NULL, - NULL, - NULL } -}; - -static EPopupActionEntry shell_popup_entries[] = { - - { "popup-copy-clipboard", - NULL, - "copy-clipboard" }, - - { "popup-cut-clipboard", - NULL, - "cut-clipboard" }, - - { "popup-delete-selection", - NULL, - "delete-selection" }, - - { "popup-paste-clipboard", - NULL, - "paste-clipboard" } -}; - -static GtkToggleActionEntry shell_toggle_entries[] = { - - { "show-menubar", - NULL, - N_("Show _Menu Bar"), - NULL, - N_("Show the menu bar"), - NULL, - TRUE }, - - { "show-sidebar", - NULL, - N_("Show Side _Bar"), - "F9", - N_("Show the side bar"), - NULL, - TRUE }, - - { "show-switcher", - NULL, - N_("Show _Buttons"), - NULL, - N_("Show the switcher buttons"), - NULL, - TRUE }, - - { "show-taskbar", - NULL, - N_("Show _Status Bar"), - NULL, - N_("Show the status bar"), - NULL, - TRUE }, - - { "show-toolbar", - NULL, - N_("Show _Tool Bar"), - NULL, - N_("Show the tool bar"), - NULL, - TRUE } -}; - -static GtkRadioActionEntry shell_switcher_entries[] = { - - /* This action represents the initial active shell view. - * It should not be visible in the UI, nor should it be - * possible to switch to it from another shell view. */ - { "switcher-initial", - NULL, - NULL, - NULL, - NULL, - -1 } -}; - -static GtkRadioActionEntry shell_switcher_style_entries[] = { - - { "switcher-style-icons", - NULL, - N_("_Icons Only"), - NULL, - N_("Display window buttons with icons only"), - GTK_TOOLBAR_ICONS }, - - { "switcher-style-text", - NULL, - N_("_Text Only"), - NULL, - N_("Display window buttons with text only"), - GTK_TOOLBAR_TEXT }, - - { "switcher-style-both", - NULL, - N_("Icons _and Text"), - NULL, - N_("Display window buttons with icons and text"), - GTK_TOOLBAR_BOTH_HORIZ }, - - { "switcher-style-user", - NULL, - N_("Tool_bar Style"), - NULL, - N_("Display window buttons using the desktop toolbar setting"), - -1 } -}; - -static GtkActionEntry shell_gal_view_entries[] = { - - { "gal-delete-view", - NULL, - N_("Delete Current View"), - NULL, - NULL, /* Set in update_view_menu */ - G_CALLBACK (action_gal_delete_view_cb) }, - - { "gal-save-custom-view", - NULL, - N_("Save Custom View…"), - NULL, - N_("Save current custom view"), - G_CALLBACK (action_gal_save_custom_view_cb) }, - - { "gal-customize-view", - NULL, - N_("Custo_mize Current View…"), - NULL, - NULL, - G_CALLBACK (action_gal_customize_view_cb) }, - - /*** Menus ***/ - - { "gal-view-menu", - NULL, - N_("C_urrent View"), - NULL, - NULL, - NULL } -}; - -static GtkRadioActionEntry shell_gal_view_radio_entries[] = { - - { "gal-custom-view", - NULL, - N_("Custom View"), - NULL, - N_("Current view is a customized view"), - -1 } -}; - -static GtkActionEntry shell_lockdown_print_setup_entries[] = { - - { "page-setup", - "document-page-setup", - N_("Page Set_up…"), - NULL, - N_("Change the page settings for your current printer"), - G_CALLBACK (action_page_setup_cb) } -}; - -static void -shell_window_extract_actions (EShellWindow *shell_window, - GList **source_list, - GList **destination_list) -{ - const gchar *current_view; - GList *match_list = NULL; - GList *iter; - - /* Pick out the actions from the source list that are tagged - * as belonging to the current EShellView and move them to the - * destination list. */ - - current_view = e_shell_window_get_active_view (shell_window); - - /* Example: Suppose [A] and [C] are tagged for this EShellView. - * - * source_list = [A] -> [B] -> [C] - * ^ ^ - * | | - * match_list = [ ] --------> [ ] - * - * - * destination_list = [1] -> [2] (other actions) - */ - for (iter = *source_list; iter != NULL; iter = iter->next) { - GtkAction *action = iter->data; - const gchar *backend_name; - - backend_name = g_object_get_data ( - G_OBJECT (action), "backend-name"); - - if (g_strcmp0 (backend_name, current_view) != 0) - continue; - - if (g_object_get_data (G_OBJECT (action), "primary")) - match_list = g_list_prepend (match_list, iter); - else - match_list = g_list_append (match_list, iter); - } - - /* source_list = [B] match_list = [A] -> [C] */ - for (iter = match_list; iter != NULL; iter = iter->next) { - GList *link = iter->data; - - iter->data = link->data; - *source_list = g_list_delete_link (*source_list, link); - } - - /* destination_list = [1] -> [2] -> [A] -> [C] */ - *destination_list = g_list_concat (*destination_list, match_list); -} - void -e_shell_window_actions_init (EShellWindow *shell_window) +e_shell_window_actions_constructed (EShellWindow *shell_window) { - GtkActionGroup *action_group; + static const EUIActionEntry new_source_entries[] = { + + { "new-collection-account", + "evolution", + N_("Collect_ion Account"), + NULL, + N_("Create a new collection account"), + action_new_collection_account_cb, NULL, NULL, NULL } + }; + + static const EUIActionEntry shell_entries[] = { + + { "about", + "help-about", + N_("_About"), + NULL, + N_("Show information about Evolution"), + action_about_cb, NULL, NULL, NULL }, + + { "accounts", + NULL, + N_("_Accounts"), + NULL, + N_("Configure Evolution Accounts"), + action_accounts_cb, NULL, NULL, NULL }, + + { "close", + "window-close", + N_("_Close Window"), + "w", + N_("Close this window"), + action_close_cb, NULL, NULL, NULL }, + + { "close-window-menu", + "window-close", + N_("_Close"), + "w", + N_("Close this window"), + action_close_cb, NULL, NULL, NULL }, + + { "close-window", + "window-close", + N_("_Close Window"), + "w", + N_("Close this window"), + action_close_cb, NULL, NULL, NULL }, + + { "contents", + "help-browser", + N_("_Contents"), + "F1", + N_("Open the Evolution User Guide"), + action_contents_cb, NULL, NULL, NULL }, + + { "copy-clipboard", + "edit-copy", + N_("_Copy"), + "c", + N_("Copy the selection"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "cut-clipboard", + "edit-cut", + N_("Cu_t"), + "x", + N_("Cut the selection"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "delete-selection", + "edit-delete", + N_("_Delete"), + NULL, + N_("Delete the selection"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "import", + NULL, + N_("I_mport…"), + NULL, + N_("Import data from other programs"), + action_import_cb, NULL, NULL, NULL }, + + { "new-window", + "window-new", + N_("New _Window"), + "w", + N_("Create a new window displaying this view"), + action_new_window_cb, NULL, NULL, NULL }, + + { "paste-clipboard", + "edit-paste", + N_("_Paste"), + "v", + N_("Paste the clipboard"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "categories", + NULL, + N_("Available Cate_gories"), + NULL, + N_("Manage available categories"), + action_categories_cb, NULL, NULL, NULL }, + + { "preferences", + "preferences-system", + N_("_Preferences"), + "s", + N_("Configure Evolution"), + action_preferences_cb, NULL, NULL, NULL }, + + { "quit", + "application-exit", + N_("_Quit"), + "q", + N_("Exit the program"), + action_quit_cb, NULL, NULL, NULL }, + + { "select-all", + "edit-select-all", + N_("Select _All"), + "a", + N_("Select all text"), + NULL, NULL, NULL, NULL }, /* Handled by EFocusTracker */ + + { "shortcuts", + NULL, + N_("_Keyboard Shortcuts"), + "question", + N_("Show keyboard shortcuts"), + action_shortcuts_cb, NULL, NULL, NULL }, + + { "show-webkit-gpu", + NULL, + N_("Show _WebKit GPU information"), + NULL, + N_("Show WebKit GPU information page in the preview panel"), + action_show_webkit_gpu_cb, NULL, NULL, NULL }, + + { "submit-bug", + NULL, + N_("Submit _Bug Report…"), + NULL, + N_("Submit a bug report using Bug Buddy"), + action_submit_bug_cb, NULL, NULL, NULL }, + + { "work-offline", + NULL, + N_("_Work Offline"), + NULL, + N_("Put Evolution into offline mode"), + action_work_offline_cb, NULL, NULL, NULL }, + + { "work-online", + NULL, + N_("_Work Online"), + NULL, + N_("Put Evolution into online mode"), + action_work_online_cb, NULL, NULL, NULL }, + + { "EShellWindow::new-shortcut", + NULL, + N_("_New"), + "n", + NULL, + action_shell_window_new_shortcut_cb, NULL, NULL, NULL }, + + /*** Menus ***/ + + { "edit-menu", NULL, N_("_Edit"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "file-menu", NULL, N_("_File"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "help-menu", NULL, N_("_Help"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "layout-menu", NULL, N_("Lay_out"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "search-menu", NULL, N_("_Search"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "switcher-menu", NULL, N_("_Switcher Appearance"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "view-menu", NULL, N_("_View"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "window-menu", NULL, N_("_Window"), NULL, NULL, NULL, NULL, NULL, NULL }, + { "EShellWindow::new-button", NULL, "New", NULL, NULL, NULL, NULL, NULL, NULL } + }; + + static const EUIActionEntry shell_lockdown_print_setup_entries[] = { + + { "page-setup", + "document-page-setup", + N_("Page Set_up…"), + NULL, + N_("Change the page settings for your current printer"), + action_page_setup_cb, NULL, NULL, NULL } + }; + EFocusTracker *focus_tracker; + EUIActionGroup *action_group; + EUIManager *ui_manager; /* only temporary, for easier creation of the actions */ GSettings *settings; - GtkUIManager *ui_manager; + const gchar *action_group_name; gchar *path; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - ui_manager = e_shell_window_get_ui_manager (shell_window); + ui_manager = e_ui_manager_new (); - e_load_ui_manager_definition (ui_manager, "evolution-shell.ui"); + action_group_name = "shell"; + e_ui_manager_add_actions (ui_manager, action_group_name, NULL, + shell_entries, G_N_ELEMENTS (shell_entries), shell_window); + action_group = e_ui_manager_get_action_group (ui_manager, action_group_name); + g_hash_table_insert (shell_window->priv->action_groups, g_strdup (action_group_name), g_object_ref (action_group)); + action_group_name = "lockdown-print-setup"; + e_ui_manager_add_actions (ui_manager, action_group_name, NULL, + shell_lockdown_print_setup_entries, G_N_ELEMENTS (shell_lockdown_print_setup_entries), shell_window); + action_group = e_ui_manager_get_action_group (ui_manager, action_group_name); + g_hash_table_insert (shell_window->priv->action_groups, g_strdup (action_group_name), g_object_ref (action_group)); + + g_clear_object (&ui_manager); + + action_group_name = "new-item"; + g_hash_table_insert (shell_window->priv->action_groups, g_strdup (action_group_name), e_ui_action_group_new (action_group_name)); + gtk_widget_insert_action_group (GTK_WIDGET (shell_window), action_group_name, + G_ACTION_GROUP (g_hash_table_lookup (shell_window->priv->action_groups, action_group_name))); + + action_group_name = "new-source"; + g_hash_table_insert (shell_window->priv->action_groups, g_strdup (action_group_name), e_ui_action_group_new (action_group_name)); + gtk_widget_insert_action_group (GTK_WIDGET (shell_window), action_group_name, + G_ACTION_GROUP (g_hash_table_lookup (shell_window->priv->action_groups, action_group_name))); + + action_group_name = "lockdown-application-handlers"; + g_hash_table_insert (shell_window->priv->action_groups, g_strdup (action_group_name), e_ui_action_group_new (action_group_name)); + + action_group_name = "lockdown-printing"; + g_hash_table_insert (shell_window->priv->action_groups, g_strdup (action_group_name), e_ui_action_group_new (action_group_name)); + + action_group_name = "lockdown-save-to-disk"; + g_hash_table_insert (shell_window->priv->action_groups, g_strdup (action_group_name), e_ui_action_group_new (action_group_name)); + + /* only after the groups are created */ e_shell_window_register_new_source_actions (shell_window, "shell", new_source_entries, G_N_ELEMENTS (new_source_entries)); - /* Shell Actions */ - action_group = ACTION_GROUP (SHELL); - gtk_action_group_add_actions ( - action_group, shell_entries, - G_N_ELEMENTS (shell_entries), shell_window); - e_action_group_add_popup_actions ( - action_group, shell_popup_entries, - G_N_ELEMENTS (shell_popup_entries)); - gtk_action_group_add_toggle_actions ( - action_group, shell_toggle_entries, - G_N_ELEMENTS (shell_toggle_entries), shell_window); - gtk_action_group_add_radio_actions ( - action_group, shell_switcher_style_entries, - G_N_ELEMENTS (shell_switcher_style_entries), - E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE, - G_CALLBACK (action_switcher_style_cb), shell_window); - gtk_action_group_add_actions ( - action_group, shell_gal_view_entries, - G_N_ELEMENTS (shell_gal_view_entries), shell_window); - gtk_action_group_add_radio_actions ( - action_group, shell_gal_view_radio_entries, - G_N_ELEMENTS (shell_gal_view_radio_entries), - 0, G_CALLBACK (action_gal_view_cb), shell_window); - - /* Switcher Actions */ - action_group = ACTION_GROUP (SWITCHER); - gtk_action_group_add_radio_actions ( - action_group, shell_switcher_entries, - G_N_ELEMENTS (shell_switcher_entries), - -1, G_CALLBACK (action_switcher_cb), shell_window); - - /* Lockdown Print Setup Actions */ - action_group = ACTION_GROUP (LOCKDOWN_PRINT_SETUP); - gtk_action_group_add_actions ( - action_group, shell_lockdown_print_setup_entries, - G_N_ELEMENTS (shell_lockdown_print_setup_entries), - shell_window); - /* Configure an EFocusTracker to manage selection actions. */ + action_group = g_hash_table_lookup (shell_window->priv->action_groups, "shell"); + focus_tracker = e_focus_tracker_new (GTK_WINDOW (shell_window)); - e_focus_tracker_set_cut_clipboard_action ( - focus_tracker, ACTION (CUT_CLIPBOARD)); - e_focus_tracker_set_copy_clipboard_action ( - focus_tracker, ACTION (COPY_CLIPBOARD)); - e_focus_tracker_set_paste_clipboard_action ( - focus_tracker, ACTION (PASTE_CLIPBOARD)); - e_focus_tracker_set_delete_selection_action ( - focus_tracker, ACTION (DELETE_SELECTION)); - e_focus_tracker_set_select_all_action ( - focus_tracker, ACTION (SELECT_ALL)); + + e_focus_tracker_set_cut_clipboard_action (focus_tracker, e_ui_action_group_get_action (action_group, "cut-clipboard")); + e_focus_tracker_set_copy_clipboard_action (focus_tracker, e_ui_action_group_get_action (action_group, "copy-clipboard")); + e_focus_tracker_set_paste_clipboard_action (focus_tracker, e_ui_action_group_get_action (action_group, "paste-clipboard")); + e_focus_tracker_set_delete_selection_action (focus_tracker, e_ui_action_group_get_action (action_group, "delete-selection")); + e_focus_tracker_set_select_all_action (focus_tracker, e_ui_action_group_get_action (action_group, "select-all")); + shell_window->priv->focus_tracker = focus_tracker; - /* Fine tuning. */ - - gtk_action_set_sensitive (ACTION (SEARCH_QUICK), FALSE); - - e_binding_bind_property ( - shell_window, "menubar-visible", - ACTION (SHOW_MENUBAR), "active", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - shell_window, "sidebar-visible", - ACTION (SHOW_SIDEBAR), "active", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - shell_window, "switcher-visible", - ACTION (SHOW_SWITCHER), "active", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - shell_window, "taskbar-visible", - ACTION (SHOW_TASKBAR), "active", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - shell_window, "toolbar-visible", - ACTION (SHOW_TOOLBAR), "active", - G_BINDING_BIDIRECTIONAL | - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - ACTION (SHOW_SIDEBAR), "active", - ACTION (SHOW_SWITCHER), "sensitive", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - ACTION (SHOW_SIDEBAR), "active", - ACTION (SWITCHER_STYLE_BOTH), "sensitive", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - ACTION (SHOW_SIDEBAR), "active", - ACTION (SWITCHER_STYLE_ICONS), "sensitive", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - ACTION (SHOW_SIDEBAR), "active", - ACTION (SWITCHER_STYLE_TEXT), "sensitive", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - ACTION (SHOW_SIDEBAR), "active", - ACTION (SWITCHER_STYLE_USER), "sensitive", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - ACTION (SHOW_SIDEBAR), "active", - ACTION (SWITCHER_MENU), "sensitive", - G_BINDING_SYNC_CREATE); - /* Submitting bug reports requires bug-buddy. */ path = g_find_program_in_path ("bug-buddy"); if (path == NULL) - gtk_action_set_visible (ACTION (SUBMIT_BUG), FALSE); + e_ui_action_set_visible (e_ui_action_group_get_action (action_group, "submit-bug"), FALSE); g_free (path); settings = e_util_ref_settings ("org.gnome.evolution.shell"); - gtk_action_set_visible (ACTION (SHOW_WEBKIT_GPU), g_settings_get_boolean (settings, "webkit-developer-mode")); + e_ui_action_set_visible (e_ui_action_group_get_action (action_group, "show-webkit-gpu"), g_settings_get_boolean (settings, "webkit-developer-mode")); g_object_unref (settings); + + e_shell_window_create_views_actions (shell_window); } -GtkWidget * -e_shell_window_create_new_menu (EShellWindow *shell_window) +void +e_shell_window_init_ui_data (EShellWindow *shell_window, + EShellView *shell_view) { - GtkActionGroup *action_group; - GList *new_item_actions; - GList *new_source_actions; - GList *iter, *list = NULL; - GtkWidget *menu; - GtkWidget *separator; + EUIManager *ui_manager; + EUIActionGroup *action_group; + GHashTableIter iter; + gpointer value; + GError *local_error = NULL; - /* Get sorted lists of "new item" and "new source" actions. */ + ui_manager = e_shell_view_get_ui_manager (shell_view); - action_group = ACTION_GROUP (NEW_ITEM); - - new_item_actions = g_list_sort ( - gtk_action_group_list_actions (action_group), - (GCompareFunc) e_action_compare_by_label); - - action_group = ACTION_GROUP (NEW_SOURCE); - - new_source_actions = g_list_sort ( - gtk_action_group_list_actions (action_group), - (GCompareFunc) e_action_compare_by_label); - - /* Give priority to actions that belong to this shell view. */ - - shell_window_extract_actions ( - shell_window, &new_item_actions, &list); - - shell_window_extract_actions ( - shell_window, &new_source_actions, &list); - - /* Convert the actions to menu item proxy widgets. */ - - for (iter = list; iter != NULL; iter = iter->next) - iter->data = gtk_action_create_menu_item (iter->data); - - for (iter = new_item_actions; iter != NULL; iter = iter->next) - iter->data = gtk_action_create_menu_item (iter->data); - - for (iter = new_source_actions; iter != NULL; iter = iter->next) - iter->data = gtk_action_create_menu_item (iter->data); - - /* Add menu separators. */ - - if (new_item_actions != NULL) { - separator = gtk_separator_menu_item_new (); - new_item_actions = g_list_prepend (new_item_actions, separator); - gtk_widget_show (GTK_WIDGET (separator)); + /* add all action groups to the view's UI manager */ + g_hash_table_iter_init (&iter, shell_window->priv->action_groups); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + action_group = value; + e_ui_manager_add_action_group (ui_manager, action_group); } - if (new_source_actions != NULL) { - separator = gtk_separator_menu_item_new (); - new_source_actions = g_list_prepend (new_source_actions, separator); - gtk_widget_show (GTK_WIDGET (separator)); - } + if (!e_ui_parser_merge_file (e_ui_manager_get_parser (ui_manager), "evolution-shell.eui", &local_error)) + g_warning ("%s: Failed to read evolution-shell.eui file: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error"); - /* Merge everything into one list, reflecting the menu layout. */ - - list = g_list_concat (list, new_item_actions); - new_item_actions = NULL; /* just for clarity */ - - list = g_list_concat (list, new_source_actions); - new_source_actions = NULL; /* just for clarity */ - - /* And finally, build the menu. */ - - menu = gtk_menu_new (); - - for (iter = list; iter != NULL; iter = iter->next) - gtk_menu_shell_append (GTK_MENU_SHELL (menu), iter->data); - - g_list_free (list); - - return menu; + g_clear_error (&local_error); } -static GtkAction * -e_shell_window_create_switcher_action (GType type, - EShellViewClass *class, +static EUIAction * +e_shell_window_create_switcher_action (EShellViewClass *klass, const gchar *name, const gchar *tooltip, const gchar *view_name) { - GtkAction *action; + EUIAction *action; - action = g_object_new ( - type, - "name", name, - "label", class->label, - "tooltip", tooltip, - "icon-name", class->icon_name, - NULL); - - g_object_set_data ( - G_OBJECT (action), - "view-name", (gpointer) view_name); + action = e_ui_action_new_stateful ("shell", name, G_VARIANT_TYPE_STRING, + g_variant_new_string (view_name)); + e_ui_action_set_label (action, klass->label); + e_ui_action_set_tooltip (action, tooltip); + e_ui_action_set_icon_name (action, klass->icon_name); return action; } -/* - * Create both the actions to switch the current window, and also - * to create each view in a new window. - */ void -e_shell_window_create_switcher_actions (EShellWindow *shell_window) +e_shell_window_fill_switcher_actions (EShellWindow *shell_window, + EUIManager *ui_manager, + EShellSwitcher *switcher) { - GSList *group = NULL; - GtkRadioAction *s_action; - GtkActionGroup *s_action_group; - GtkActionGroup *n_action_group; - GtkUIManager *ui_manager; - EShellSwitcher *switcher; + EUIActionGroup *action_group; EShell *shell; + GPtrArray *group; GList *list, *iter; - guint merge_id; - guint ii = 0; + guint ii = 1; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - s_action_group = ACTION_GROUP (SWITCHER); - n_action_group = ACTION_GROUP (NEW_WINDOW); - switcher = E_SHELL_SWITCHER (shell_window->priv->switcher); - ui_manager = e_shell_window_get_ui_manager (shell_window); - merge_id = gtk_ui_manager_new_merge_id (ui_manager); + group = g_ptr_array_new (); shell = e_shell_window_get_shell (shell_window); list = e_shell_get_shell_backends (shell); @@ -1680,20 +908,16 @@ e_shell_window_create_switcher_actions (EShellWindow *shell_window) * actions are manifested as switcher buttons and View->Window * menu items. */ - s_action = GTK_RADIO_ACTION (ACTION (SWITCHER_INITIAL)); - gtk_radio_action_set_group (s_action, group); - group = gtk_radio_action_get_group (s_action); + action_group = e_shell_window_get_ui_action_group (shell_window, "shell"); - for (iter = list; iter != NULL; iter = iter->next) { + for (iter = list; iter != NULL; iter = iter->next, ii++) { EShellBackend *shell_backend = iter->data; EShellBackendClass *backend_class; EShellViewClass *class; - GtkAction *n_action; + EUIAction *s_action, *n_action; GType view_type; const gchar *view_name; - gchar *accelerator; - gchar *s_action_name; - gchar *n_action_name; + gchar tmp_str[128]; gchar *tooltip; /* The backend name is also the view name. */ @@ -1720,292 +944,147 @@ e_shell_window_create_switcher_actions (EShellWindow *shell_window) tooltip = g_strdup_printf (_("Switch to %s"), class->label); - s_action_name = g_strdup_printf ( - E_SHELL_SWITCHER_FORMAT, view_name); + g_warn_if_fail (g_snprintf (tmp_str, sizeof (tmp_str), E_SHELL_SWITCHER_FORMAT, view_name) < sizeof (tmp_str)); - /* Note, we have to set "icon-name" separately because - * gtk_radio_action_new() expects a "stock-id". Sadly, - * GTK+ still distinguishes between the two. */ + s_action = e_ui_action_group_get_action (action_group, tmp_str); + if (s_action) { + g_object_ref (s_action); + } else { + /* these are prepared beforehand, within e_shell_window_create_views_actions() */ + g_warn_if_reached (); + } - s_action = GTK_RADIO_ACTION ( - e_shell_window_create_switcher_action ( - GTK_TYPE_RADIO_ACTION, - class, s_action_name, - tooltip, view_name)); - g_object_set (s_action, "value", ii++, NULL); - gtk_radio_action_set_group (s_action, group); - group = gtk_radio_action_get_group (s_action); + /* Create new window actions */ + g_warn_if_fail (g_snprintf (tmp_str, sizeof (tmp_str), "new-%s-window", view_name) < sizeof (tmp_str)); - /* The first nine views have accelerators Ctrl+(1-9). */ - if (ii < 10) - accelerator = g_strdup_printf ("%d", ii); - else - accelerator = g_strdup (""); + n_action = e_ui_action_group_get_action (action_group, tmp_str); + if (n_action) { + g_object_ref (n_action); + } else { + n_action = e_shell_window_create_switcher_action (class, tmp_str, tooltip, view_name); + g_signal_connect ( + n_action, "activate", + G_CALLBACK (action_new_view_window_cb), shell_window); + e_ui_action_group_add (action_group, n_action); + } - gtk_action_group_add_action_with_accel ( - s_action_group, GTK_ACTION (s_action), accelerator); + e_shell_switcher_add_action (switcher, s_action, n_action); - g_free (accelerator); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, - "/main-menu/view-menu/window-menu", - s_action_name, s_action_name, - GTK_UI_MANAGER_AUTO, FALSE); - g_free (s_action_name); - - /* Create in new window actions */ - n_action_name = g_strdup_printf ( - E_SHELL_NEW_WINDOW_FORMAT, view_name); - n_action = e_shell_window_create_switcher_action ( - GTK_TYPE_ACTION, - class, n_action_name, - tooltip, view_name); - g_signal_connect ( - n_action, "activate", - G_CALLBACK (action_new_view_window_cb), shell_window); - gtk_action_group_add_action (n_action_group, n_action); - - e_shell_switcher_add_action ( - switcher, GTK_ACTION (s_action), n_action); - - g_free (n_action_name); + g_clear_object (&s_action); + g_clear_object (&n_action); g_free (tooltip); g_type_class_unref (class); } + + g_ptr_array_unref (group); } -void -e_shell_window_update_view_menu (EShellWindow *shell_window) +static void +e_shell_window_create_views_actions (EShellWindow *shell_window) { - EShellView *shell_view; - EShellViewClass *shell_view_class; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GalViewCollection *view_collection; - GalViewInstance *view_instance; - GtkRadioAction *radio_action; - GtkAction *action; - GSList *radio_group; - gboolean visible; - const gchar *path; - const gchar *view_id; - const gchar *view_name; - gchar *delete_tooltip = NULL; - gboolean delete_visible = FALSE; - guint merge_id; - gint count, ii; - - ui_manager = e_shell_window_get_ui_manager (shell_window); - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - g_return_if_fail (shell_view != NULL); - - shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view); - view_collection = shell_view_class->view_collection; - view_id = e_shell_view_get_view_id (shell_view); - g_return_if_fail (view_collection != NULL); - - action_group = ACTION_GROUP (GAL_VIEW); - merge_id = shell_window->priv->gal_view_merge_id; - - /* Unmerge the previous menu. */ - gtk_ui_manager_remove_ui (ui_manager, merge_id); - e_action_group_remove_all_actions (action_group); - gtk_ui_manager_ensure_update (ui_manager); - - /* We have a view ID, so forge ahead. */ - count = gal_view_collection_get_count (view_collection); - path = "/main-menu/view-menu/gal-view-menu/gal-view-list"; - - /* Prevent spurious activations. */ - action = ACTION (GAL_CUSTOM_VIEW); - g_signal_handlers_block_matched ( - action, G_SIGNAL_MATCH_FUNC, 0, 0, - NULL, action_gal_view_cb, NULL); - - /* Default to "Custom View", unless we find our view ID. */ - radio_action = GTK_RADIO_ACTION (ACTION (GAL_CUSTOM_VIEW)); - gtk_radio_action_set_group (radio_action, NULL); - radio_group = gtk_radio_action_get_group (radio_action); - gtk_radio_action_set_current_value (radio_action, -1); - - /* Add a menu item for each view collection item. */ - for (ii = 0; ii < count; ii++) { - GalViewCollectionItem *item; - gchar *action_name; - gchar *tooltip, *title; - - item = gal_view_collection_get_view_item (view_collection, ii); - - action_name = g_strdup_printf ( - "gal-view-%s-%d", view_name, ii); - title = e_str_without_underscores (item->title); - tooltip = g_strdup_printf (_("Select view: %s"), title); - - radio_action = gtk_radio_action_new ( - action_name, item->title, tooltip, NULL, ii); - - action = GTK_ACTION (radio_action); - gtk_radio_action_set_group (radio_action, radio_group); - radio_group = gtk_radio_action_get_group (radio_action); - - g_object_set_data_full ( - G_OBJECT (radio_action), "view-id", - g_strdup (item->id), (GDestroyNotify) g_free); - - if (view_id != NULL && strcmp (item->id, view_id) == 0) { - gtk_radio_action_set_current_value (radio_action, ii); - delete_visible = (!item->built_in); - delete_tooltip = g_strdup_printf ( - _("Delete view: %s"), title); - } - - if (item->built_in && item->accelerator) - gtk_action_group_add_action_with_accel (action_group, action, item->accelerator); - else - gtk_action_group_add_action (action_group, action); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, - path, action_name, action_name, - GTK_UI_MANAGER_AUTO, FALSE); - - g_free (action_name); - g_free (tooltip); - g_free (title); - } - - view_instance = e_shell_view_get_view_instance (shell_view); - visible = view_instance && gal_view_instance_get_current_view (view_instance) && - GAL_IS_VIEW_ETABLE (gal_view_instance_get_current_view (view_instance)); - action = ACTION (GAL_CUSTOMIZE_VIEW); - gtk_action_set_visible (action, visible); - - /* Doesn't matter which radio action we check. */ - visible = (gtk_radio_action_get_current_value (radio_action) < 0); - - action = ACTION (GAL_CUSTOM_VIEW); - gtk_action_set_visible (action, visible); - g_signal_handlers_unblock_matched ( - action, G_SIGNAL_MATCH_FUNC, 0, 0, - NULL, action_gal_view_cb, NULL); - - action = ACTION (GAL_SAVE_CUSTOM_VIEW); - gtk_action_set_visible (action, visible); - - action = ACTION (GAL_DELETE_VIEW); - gtk_action_set_tooltip (action, delete_tooltip); - gtk_action_set_visible (action, delete_visible); - - g_free (delete_tooltip); -} - -void -e_shell_window_update_search_menu (EShellWindow *shell_window) -{ - EShellView *shell_view; - EShellViewClass *shell_view_class; - ERuleContext *context; - EFilterRule *rule; - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - const gchar *source; - const gchar *view_name; - gchar *search_options_path; - gboolean sensitive; - guint merge_id; - gint ii = 0; + EUIActionGroup *action_group; + EShell *shell; + EUIManager *tmp_ui_manager; + GPtrArray *group; + GList *list, *iter; + guint ii = 1; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - ui_manager = e_shell_window_get_ui_manager (shell_window); - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); + group = NULL; + shell = e_shell_window_get_shell (shell_window); + list = e_shell_get_shell_backends (shell); + tmp_ui_manager = e_ui_manager_new (); - /* Check for a NULL shell view before proceeding. This can - * happen if the initial view name from GSettings is unrecognized. - * Without this we would crash at E_SHELL_VIEW_GET_CLASS(). */ - g_return_if_fail (shell_view != NULL); + /* Construct a group of radio actions from the various EShellView + * subclasses. */ - shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view); - context = shell_view_class->search_context; - search_options_path = g_strconcat (shell_view_class->search_options, "/saved-searches/custom-rules", NULL); + action_group = e_shell_window_get_ui_action_group (shell_window, "shell"); - source = E_FILTER_SOURCE_INCOMING; + for (iter = list; iter != NULL; iter = iter->next, ii++) { + EShellBackend *shell_backend = iter->data; + EShellBackendClass *backend_class; + EShellViewClass *klass; + EUIAction *s_action; + GType view_type; + const gchar *view_name; + gchar tmp_str[128]; + gchar *tooltip; - /* Update sensitivity of search_options action. */ - sensitive = (shell_view_class->search_options != NULL); - gtk_action_set_sensitive (ACTION (SEARCH_OPTIONS), sensitive); + /* The backend name is also the view name. */ + backend_class = E_SHELL_BACKEND_GET_CLASS (shell_backend); + view_type = backend_class->shell_view_type; + view_name = backend_class->name; - /* Add custom rules to the Search menu. */ - - action_group = ACTION_GROUP (CUSTOM_RULES); - merge_id = shell_window->priv->custom_rule_merge_id; - - /* Unmerge the previous menu. */ - gtk_ui_manager_remove_ui (ui_manager, merge_id); - e_action_group_remove_all_actions (action_group); - gtk_ui_manager_ensure_update (ui_manager); - - if (!gtk_ui_manager_get_widget (ui_manager, search_options_path)) - g_clear_pointer (&search_options_path, g_free); - - rule = e_rule_context_next_rule (context, NULL, source); - while (rule != NULL) { - GtkAction *action; - GString *escaped_name = NULL; - gchar *action_name; - gchar *action_label; - - if (rule->name && strchr (rule->name, '_') != NULL) - escaped_name = e_str_replace_string (rule->name, "_", "__"); - - action_name = g_strdup_printf ("custom-rule-%d", ii++); - if (ii < 10) - action_label = g_strdup_printf ( - "_%d. %s", ii, escaped_name ? escaped_name->str : rule->name); - else - action_label = g_strdup (escaped_name ? escaped_name->str : rule->name); - - if (escaped_name) - g_string_free (escaped_name, TRUE); - - action = gtk_action_new ( - action_name, action_label, - _("Execute these search parameters"), NULL); - - g_object_set_data_full ( - G_OBJECT (action), - "rule", g_object_ref (rule), - (GDestroyNotify) g_object_unref); - - g_signal_connect ( - action, "activate", - G_CALLBACK (action_custom_rule_cb), shell_window); - - gtk_action_group_add_action (action_group, action); - - gtk_ui_manager_add_ui ( - ui_manager, merge_id, - "/main-menu/search-menu/custom-rules", - action_name, action_name, - GTK_UI_MANAGER_AUTO, FALSE); - - if (search_options_path) { - gtk_ui_manager_add_ui ( - ui_manager, merge_id, - search_options_path, - action_name, action_name, - GTK_UI_MANAGER_AUTO, FALSE); + if (!g_type_is_a (view_type, E_TYPE_SHELL_VIEW)) { + g_critical ( + "%s is not a subclass of %s", + g_type_name (view_type), + g_type_name (E_TYPE_SHELL_VIEW)); + continue; } - g_free (action_name); - g_free (action_label); + klass = g_type_class_ref (view_type); - rule = e_rule_context_next_rule (context, rule, source); + if (klass->label == NULL) { + g_critical ( + "Label member not set on %s", + G_OBJECT_CLASS_NAME (klass)); + continue; + } + + tooltip = g_strdup_printf (_("Switch to %s"), klass->label); + + g_warn_if_fail (g_snprintf (tmp_str, sizeof (tmp_str), E_SHELL_SWITCHER_FORMAT, view_name) < sizeof (tmp_str)); + + s_action = e_ui_action_group_get_action (action_group, tmp_str); + if (s_action) { + g_object_ref (s_action); + if (!group) { + group = e_ui_action_get_radio_group (s_action); + if (group) { + g_ptr_array_ref (group); + } else { + group = g_ptr_array_new (); + e_ui_action_set_radio_group (s_action, group); + } + } + } else { + GMenuItem *menu_item; + + if (!group) + group = g_ptr_array_new (); + + s_action = e_shell_window_create_switcher_action (klass, tmp_str, tooltip, view_name); + e_ui_action_set_radio_group (s_action, group); + e_ui_action_group_add (action_group, s_action); + + g_signal_connect_object (s_action, "notify::active", + G_CALLBACK (action_switcher_cb), shell_window, 0); + + /* The first nine views have accelerators Ctrl+(1-9). */ + if (ii < 10) { + g_warn_if_fail (g_snprintf (tmp_str, sizeof (tmp_str), "%d", ii) < sizeof (tmp_str)); + e_ui_action_set_accel (s_action, tmp_str); + } + + menu_item = g_menu_item_new (NULL, NULL); + /* cannot use custom icons here, because the tmp_ui_manager is + only temporary and without set callbacks for the "create-gicon" + signal, but it's not a problem here; the actions are needed + before the EShellView is created, because it references it */ + e_ui_manager_update_item_from_action (tmp_ui_manager, menu_item, s_action); + g_menu_append_item (shell_window->priv->switch_to_menu, menu_item); + g_clear_object (&menu_item); + } + + g_clear_object (&s_action); + g_free (tooltip); + + g_type_class_unref (klass); } - g_clear_pointer (&search_options_path, g_free); + g_clear_object (&tmp_ui_manager); + g_clear_pointer (&group, g_ptr_array_unref); } diff --git a/src/shell/e-shell-window-actions.h b/src/shell/e-shell-window-actions.h index 65aed59e6b..7aa1b76b23 100644 --- a/src/shell/e-shell-window-actions.h +++ b/src/shell/e-shell-window-actions.h @@ -22,10 +22,10 @@ #define E_SHELL_WINDOW_ACTIONS_H #define E_SHELL_WINDOW_ACTION(window, name) \ - (e_shell_window_get_action (E_SHELL_WINDOW (window), (name))) + (e_shell_window_get_ui_action (E_SHELL_WINDOW (window), (name))) #define E_SHELL_WINDOW_ACTION_GROUP(window, name) \ - (e_shell_window_get_action_group (E_SHELL_WINDOW (window), (name))) + (e_shell_window_get_ui_action_group (E_SHELL_WINDOW (window), (name))) /* Actions */ #define E_SHELL_WINDOW_ACTION_ABOUT(window) \ @@ -42,14 +42,6 @@ E_SHELL_WINDOW_ACTION ((window), "cut-clipboard") #define E_SHELL_WINDOW_ACTION_DELETE_SELECTION(window) \ E_SHELL_WINDOW_ACTION ((window), "delete-selection") -#define E_SHELL_WINDOW_ACTION_GAL_CUSTOM_VIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "gal-custom-view") -#define E_SHELL_WINDOW_ACTION_GAL_CUSTOMIZE_VIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "gal-customize-view") -#define E_SHELL_WINDOW_ACTION_GAL_DELETE_VIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "gal-delete-view") -#define E_SHELL_WINDOW_ACTION_GAL_SAVE_CUSTOM_VIEW(window) \ - E_SHELL_WINDOW_ACTION ((window), "gal-save-custom-view") #define E_SHELL_WINDOW_ACTION_IMPORT(window) \ E_SHELL_WINDOW_ACTION ((window), "import") #define E_SHELL_WINDOW_ACTION_NEW_WINDOW(window) \ @@ -62,20 +54,6 @@ E_SHELL_WINDOW_ACTION ((window), "preferences") #define E_SHELL_WINDOW_ACTION_QUIT(window) \ E_SHELL_WINDOW_ACTION ((window), "quit") -#define E_SHELL_WINDOW_ACTION_SEARCH_ADVANCED(window) \ - E_SHELL_WINDOW_ACTION ((window), "search-advanced") -#define E_SHELL_WINDOW_ACTION_SAVED_SEARCHES(window) \ - E_SHELL_WINDOW_ACTION ((window), "saved-searches") -#define E_SHELL_WINDOW_ACTION_SEARCH_CLEAR(window) \ - E_SHELL_WINDOW_ACTION ((window), "search-clear") -#define E_SHELL_WINDOW_ACTION_SEARCH_EDIT(window) \ - E_SHELL_WINDOW_ACTION ((window), "search-edit") -#define E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS(window) \ - E_SHELL_WINDOW_ACTION ((window), "search-options") -#define E_SHELL_WINDOW_ACTION_SEARCH_QUICK(window) \ - E_SHELL_WINDOW_ACTION ((window), "search-quick") -#define E_SHELL_WINDOW_ACTION_SEARCH_SAVE(window) \ - E_SHELL_WINDOW_ACTION ((window), "search-save") #define E_SHELL_WINDOW_ACTION_SELECT_ALL(window) \ E_SHELL_WINDOW_ACTION ((window), "select-all") #define E_SHELL_WINDOW_ACTION_SHORTCUTS(window) \ @@ -94,28 +72,14 @@ E_SHELL_WINDOW_ACTION ((window), "show-webkit-gpu") #define E_SHELL_WINDOW_ACTION_SUBMIT_BUG(window) \ E_SHELL_WINDOW_ACTION ((window), "submit-bug") -#define E_SHELL_WINDOW_ACTION_SWITCHER_INITIAL(window) \ - E_SHELL_WINDOW_ACTION ((window), "switcher-initial") #define E_SHELL_WINDOW_ACTION_SWITCHER_MENU(window) \ E_SHELL_WINDOW_ACTION ((window), "switcher-menu") -#define E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_BOTH(window) \ - E_SHELL_WINDOW_ACTION ((window), "switcher-style-both") -#define E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_ICONS(window) \ - E_SHELL_WINDOW_ACTION ((window), "switcher-style-icons") -#define E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_TEXT(window) \ - E_SHELL_WINDOW_ACTION ((window), "switcher-style-text") -#define E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_USER(window) \ - E_SHELL_WINDOW_ACTION ((window), "switcher-style-user") #define E_SHELL_WINDOW_ACTION_WORK_OFFLINE(window) \ E_SHELL_WINDOW_ACTION ((window), "work-offline") #define E_SHELL_WINDOW_ACTION_WORK_ONLINE(window) \ E_SHELL_WINDOW_ACTION ((window), "work-online") /* Action Groups */ -#define E_SHELL_WINDOW_ACTION_GROUP_CUSTOM_RULES(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "custom-rules") -#define E_SHELL_WINDOW_ACTION_GROUP_GAL_VIEW(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "gal-view") #define E_SHELL_WINDOW_ACTION_GROUP_LOCKDOWN_APPLICATION_HANDLERS(window) \ E_SHELL_WINDOW_ACTION_GROUP ((window), "lockdown-application-handlers") #define E_SHELL_WINDOW_ACTION_GROUP_LOCKDOWN_PRINTING(window) \ @@ -130,9 +94,5 @@ E_SHELL_WINDOW_ACTION_GROUP ((window), "new-source") #define E_SHELL_WINDOW_ACTION_GROUP_SHELL(window) \ E_SHELL_WINDOW_ACTION_GROUP ((window), "shell") -#define E_SHELL_WINDOW_ACTION_GROUP_SWITCHER(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "switcher") -#define E_SHELL_WINDOW_ACTION_GROUP_NEW_WINDOW(window) \ - E_SHELL_WINDOW_ACTION_GROUP ((window), "new-window") #endif /* E_SHELL_WINDOW_ACTIONS_H */ diff --git a/src/shell/e-shell-window-private.c b/src/shell/e-shell-window-private.c index 86cdb43c71..3de2267669 100644 --- a/src/shell/e-shell-window-private.c +++ b/src/shell/e-shell-window-private.c @@ -22,211 +22,6 @@ #include "e-shell-window-private.h" -static void -shell_window_save_switcher_style_cb (GtkRadioAction *action, - GtkRadioAction *current, - EShellWindow *shell_window) -{ - GSettings *settings; - GtkToolbarStyle style; - const gchar *string; - - settings = e_util_ref_settings ("org.gnome.evolution.shell"); - - style = gtk_radio_action_get_current_value (action); - - switch (style) { - case GTK_TOOLBAR_ICONS: - string = "icons"; - break; - - case GTK_TOOLBAR_TEXT: - string = "text"; - break; - - case GTK_TOOLBAR_BOTH: - case GTK_TOOLBAR_BOTH_HORIZ: - string = "both"; - break; - - default: - string = "toolbar"; - break; - } - - g_settings_set_string (settings, "buttons-style", string); - g_object_unref (settings); -} - -static void -shell_window_init_switcher_style (EShellWindow *shell_window) -{ - GtkAction *action; - GSettings *settings; - GtkToolbarStyle style; - gchar *string; - - settings = e_util_ref_settings ("org.gnome.evolution.shell"); - - action = ACTION (SWITCHER_STYLE_ICONS); - string = g_settings_get_string (settings, "buttons-style"); - g_object_unref (settings); - - if (string != NULL) { - if (strcmp (string, "icons") == 0) - style = GTK_TOOLBAR_ICONS; - else if (strcmp (string, "text") == 0) - style = GTK_TOOLBAR_TEXT; - else if (strcmp (string, "both") == 0) - style = GTK_TOOLBAR_BOTH_HORIZ; - else - style = -1; - - gtk_radio_action_set_current_value ( - GTK_RADIO_ACTION (action), style); - - g_free (string); - } - - g_signal_connect ( - action, "changed", - G_CALLBACK (shell_window_save_switcher_style_cb), - shell_window); -} - -static void -shell_window_menu_item_select_cb (EShellWindow *shell_window, - GtkWidget *widget) -{ - GtkAction *action; - GtkActivatable *activatable; - GtkLabel *label; - const gchar *tooltip; - - activatable = GTK_ACTIVATABLE (widget); - action = gtk_activatable_get_related_action (activatable); - tooltip = gtk_action_get_tooltip (action); - - if (tooltip == NULL) - return; - - label = GTK_LABEL (shell_window->priv->tooltip_label); - gtk_label_set_text (label, tooltip); - - gtk_widget_show (shell_window->priv->tooltip_label); - gtk_widget_hide (shell_window->priv->status_notebook); -} - -static void -shell_window_menu_item_deselect_cb (EShellWindow *shell_window) -{ - gtk_widget_hide (shell_window->priv->tooltip_label); - gtk_widget_show (shell_window->priv->status_notebook); -} - -static void -shell_window_connect_proxy_cb (EShellWindow *shell_window, - GtkAction *action, - GtkWidget *proxy) -{ - if (!GTK_IS_MENU_ITEM (proxy)) - return; - - g_signal_connect_swapped ( - proxy, "select", - G_CALLBACK (shell_window_menu_item_select_cb), - shell_window); - - g_signal_connect_swapped ( - proxy, "deselect", - G_CALLBACK (shell_window_menu_item_deselect_cb), - shell_window); -} - -static GtkWidget * -shell_window_construct_menubar (EShellWindow *shell_window) -{ - EShellWindowClass *class; - - class = E_SHELL_WINDOW_GET_CLASS (shell_window); - if (class->construct_menubar == NULL) - return NULL; - - return class->construct_menubar (shell_window); -} - -static GtkWidget * -shell_window_construct_toolbar (EShellWindow *shell_window) -{ - EShellWindowClass *class; - - class = E_SHELL_WINDOW_GET_CLASS (shell_window); - if (class->construct_toolbar == NULL) - return NULL; - - return class->construct_toolbar (shell_window); -} - -static GtkWidget * -shell_window_construct_sidebar (EShellWindow *shell_window) -{ - EShellWindowClass *class; - - class = E_SHELL_WINDOW_GET_CLASS (shell_window); - if (class->construct_sidebar == NULL) - return NULL; - - return class->construct_sidebar (shell_window); -} - -static GtkWidget * -shell_window_construct_content (EShellWindow *shell_window) -{ - EShellWindowClass *class; - - class = E_SHELL_WINDOW_GET_CLASS (shell_window); - if (class->construct_content == NULL) - return NULL; - - return class->construct_content (shell_window); -} - -static GtkWidget * -shell_window_construct_taskbar (EShellWindow *shell_window) -{ - EShellWindowClass *class; - - class = E_SHELL_WINDOW_GET_CLASS (shell_window); - if (class->construct_taskbar == NULL) - return NULL; - - return class->construct_taskbar (shell_window); -} - -static gboolean -shell_window_active_view_to_prefer_item (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - GObject *source_object; - EShell *shell; - EShellBackend *shell_backend; - const gchar *active_view; - const gchar *prefer_item; - - active_view = g_value_get_string (source_value); - - source_object = g_binding_get_source (binding); - shell = e_shell_window_get_shell (E_SHELL_WINDOW (source_object)); - shell_backend = e_shell_get_backend_by_name (shell, active_view); - prefer_item = e_shell_backend_get_prefer_new_item (shell_backend); - - g_value_set_string (target_value, prefer_item); - - return TRUE; -} - void e_shell_window_private_init (EShellWindow *shell_window) { @@ -241,59 +36,15 @@ e_shell_window_private_init (EShellWindow *shell_window) signal_handler_ids = g_array_new (FALSE, FALSE, sizeof (gulong)); - priv->ui_manager = gtk_ui_manager_new (); priv->loaded_views = loaded_views; priv->signal_handler_ids = signal_handler_ids; - priv->action_groups_by_view = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref); + priv->action_groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); /* XXX This kind of violates the shell window being unaware * of specific shell views, but we need a sane fallback. */ - priv->active_view = "mail"; - - e_shell_window_add_action_group (shell_window, "shell"); - e_shell_window_add_action_group (shell_window, "gal-view"); - e_shell_window_add_action_group (shell_window, "new-item"); - e_shell_window_add_action_group (shell_window, "new-source"); - e_shell_window_add_action_group (shell_window, "custom-rules"); - e_shell_window_add_action_group (shell_window, "switcher"); - e_shell_window_add_action_group (shell_window, "new-window"); - e_shell_window_add_action_group (shell_window, "lockdown-application-handlers"); - e_shell_window_add_action_group (shell_window, "lockdown-printing"); - e_shell_window_add_action_group (shell_window, "lockdown-print-setup"); - e_shell_window_add_action_group (shell_window, "lockdown-save-to-disk"); + g_warn_if_fail (g_snprintf (priv->active_view, sizeof (priv->active_view), "mail") < sizeof (priv->active_view)); gtk_window_set_title (GTK_WINDOW (shell_window), _("Evolution")); - - g_signal_connect_swapped ( - priv->ui_manager, "connect-proxy", - G_CALLBACK (shell_window_connect_proxy_cb), shell_window); -} - -static gboolean -e_shell_window_key_press_event_cb (GtkWidget *widget, - GdkEventKey *event) -{ - g_return_val_if_fail (E_IS_SHELL_WINDOW (widget), FALSE); - - if ((event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0 || - event->keyval == GDK_KEY_Tab || - event->keyval == GDK_KEY_Return || - event->keyval == GDK_KEY_Escape || - event->keyval == GDK_KEY_KP_Tab || - event->keyval == GDK_KEY_KP_Enter) - return FALSE; - - if (e_shell_window_get_need_input (E_SHELL_WINDOW (widget), event)) { - GtkWidget *focused; - - focused = gtk_window_get_focus (GTK_WINDOW (widget)); - if (focused) - gtk_widget_event (focused, (GdkEvent *) event); - - return TRUE; - } - - return FALSE; } static gboolean @@ -321,92 +72,81 @@ e_shell_window_private_constructed (EShellWindow *shell_window) { EShellWindowPrivate *priv = shell_window->priv; EShell *shell; - GtkAction *action; - GtkAccelGroup *accel_group; - GtkUIManager *ui_manager; + EUIAction *action; GtkBox *box; - GtkPaned *paned; - GtkWidget *widget, *menubar, *menu_button = NULL; + GtkWidget *widget; GtkWindow *window; - guint merge_id; - const gchar *id; GSettings *settings; #ifndef G_OS_WIN32 - GtkActionGroup *action_group; + EUIActionGroup *action_group; #endif window = GTK_WINDOW (shell_window); shell = e_shell_window_get_shell (shell_window); shell_window->priv->is_main_instance = shell_window_check_is_main_instance (GTK_APPLICATION (shell), window); + shell_window->priv->switch_to_menu = g_menu_new (); - ui_manager = e_shell_window_get_ui_manager (shell_window); - - /* Defer actions and menu merging until we have set express mode */ - - e_shell_window_actions_init (shell_window); - - accel_group = gtk_ui_manager_get_accel_group (ui_manager); - gtk_window_add_accel_group (GTK_WINDOW (shell_window), accel_group); - - merge_id = gtk_ui_manager_new_merge_id (ui_manager); - priv->custom_rule_merge_id = merge_id; - - merge_id = gtk_ui_manager_new_merge_id (ui_manager); - priv->gal_view_merge_id = merge_id; - - /* Construct window widgets. */ - - menubar = shell_window_construct_menubar (shell_window); - if (menubar) - shell_window->priv->menu_bar = e_menu_bar_new (GTK_MENU_BAR (menubar), window, &menu_button); - - if (e_util_get_use_header_bar ()) { - priv->headerbar = e_shell_header_bar_new (shell_window, menu_button); - gtk_window_set_titlebar (window, priv->headerbar); - gtk_widget_show (priv->headerbar); - } else if (menu_button) { - g_object_ref_sink (menu_button); - gtk_widget_destroy (menu_button); - } + e_shell_window_actions_constructed (shell_window); widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (shell_window), widget); - gtk_widget_show (widget); + g_object_set (widget, + "halign", GTK_ALIGN_FILL, + "hexpand", TRUE, + "valign", GTK_ALIGN_FILL, + "vexpand", TRUE, + "visible", TRUE, + NULL); + + /* it draws some children differently with it in some themes */ + gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "vertical"); box = GTK_BOX (widget); - if (menubar) - gtk_box_pack_start (box, menubar, FALSE, FALSE, 0); + if (e_util_get_use_header_bar ()) { + GtkStyleContext *style_context; + GtkCssProvider *provider; + GError *local_error = NULL; - widget = shell_window_construct_toolbar (shell_window); - if (widget != NULL) - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_visible (widget, TRUE); + shell_window->priv->headerbar_box = GTK_BOX (g_object_ref_sink (widget)); - widget = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); + provider = gtk_css_provider_new (); + + if (!gtk_css_provider_load_from_data (provider, "#evo-titlebar-box { padding:0px; margin:0px; border:0px; }", -1, &local_error)) + g_critical ("%s: Failed to load CSS data: %s", G_STRFUNC, local_error ? local_error->message : "Unknown error"); + + g_clear_error (&local_error); + + gtk_widget_set_name (widget, "evo-titlebar-box"); + style_context = gtk_widget_get_style_context (widget); + gtk_style_context_add_provider (style_context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + gtk_style_context_remove_class (style_context, "vertical"); + g_clear_object (&provider); + + gtk_window_set_titlebar (window, widget); + } + + widget = e_alert_bar_new (); + gtk_box_pack_start (box, widget, FALSE, FALSE, 0); + shell_window->priv->alert_bar = g_object_ref (widget); + /* EAlertBar controls its own visibility. */ + + widget = gtk_notebook_new (); + g_object_set (widget, + "halign", GTK_ALIGN_FILL, + "hexpand", TRUE, + "valign", GTK_ALIGN_FILL, + "vexpand", TRUE, + "visible", TRUE, + "show-tabs", FALSE, + "show-border", FALSE, + NULL); gtk_box_pack_start (box, widget, TRUE, TRUE, 0); - priv->content_pane = g_object_ref (widget); - gtk_widget_show (widget); - - widget = shell_window_construct_taskbar (shell_window); - if (widget != NULL) - gtk_box_pack_start (box, widget, FALSE, FALSE, 0); - - paned = GTK_PANED (priv->content_pane); - - widget = shell_window_construct_sidebar (shell_window); - if (widget != NULL) - gtk_paned_pack1 (paned, widget, FALSE, FALSE); - - widget = shell_window_construct_content (shell_window); - if (widget != NULL) - gtk_paned_pack2 (paned, widget, TRUE, FALSE); - - /* Create the switcher actions before we set the initial - * shell view, because the shell view relies on them for - * default settings during construction. */ - e_shell_window_create_switcher_actions (shell_window); + shell_window->priv->views_notebook = g_object_ref (GTK_NOTEBOOK (widget)); /* Bunch of chores to do when the active view changes. */ @@ -418,16 +158,12 @@ e_shell_window_private_constructed (EShellWindow *shell_window) shell_window, "notify::active-view", G_CALLBACK (e_shell_window_update_title), NULL); - e_signal_connect_notify ( - shell_window, "notify::active-view", - G_CALLBACK (e_shell_window_update_view_menu), NULL); - #ifndef G_OS_WIN32 /* Support lockdown. */ settings = e_util_ref_settings ("org.gnome.desktop.lockdown"); - action_group = ACTION_GROUP (LOCKDOWN_PRINTING); + action_group = g_hash_table_lookup (shell_window->priv->action_groups, "lockdown-printing"); g_settings_bind ( settings, "disable-printing", @@ -435,7 +171,7 @@ e_shell_window_private_constructed (EShellWindow *shell_window) G_SETTINGS_BIND_GET | G_SETTINGS_BIND_INVERT_BOOLEAN); - action_group = ACTION_GROUP (LOCKDOWN_PRINT_SETUP); + action_group = g_hash_table_lookup (shell_window->priv->action_groups, "lockdown-print-setup"); g_settings_bind ( settings, "disable-print-setup", @@ -443,7 +179,7 @@ e_shell_window_private_constructed (EShellWindow *shell_window) G_SETTINGS_BIND_GET | G_SETTINGS_BIND_INVERT_BOOLEAN); - action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK); + action_group = g_hash_table_lookup (shell_window->priv->action_groups, "lockdown-save-to-disk"); g_settings_bind ( settings, "disable-save-to-disk", @@ -481,6 +217,11 @@ e_shell_window_private_constructed (EShellWindow *shell_window) action, "sensitive", G_BINDING_SYNC_CREATE); + /* claim the window before the view is created, thus the shell backend has + added actions into the "new-item" and the "new-source" action groups, + ready for the New header bar or the New tool bar buttons */ + gtk_application_add_window (GTK_APPLICATION (shell), window); + /* Bind GObject properties to GSettings keys. */ settings = e_util_ref_settings ("org.gnome.evolution.shell"); @@ -495,74 +236,6 @@ e_shell_window_private_constructed (EShellWindow *shell_window) G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_GET_NO_CHANGES); - if (e_shell_window_is_main_instance (shell_window)) { - g_settings_bind ( - settings, "folder-bar-width", - priv->content_pane, "position", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "menubar-visible", - shell_window, "menubar-visible", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "sidebar-visible", - shell_window, "sidebar-visible", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "statusbar-visible", - shell_window, "taskbar-visible", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "buttons-visible", - shell_window, "switcher-visible", - G_SETTINGS_BIND_DEFAULT); - - g_settings_bind ( - settings, "toolbar-visible", - shell_window, "toolbar-visible", - G_SETTINGS_BIND_DEFAULT); - } else { - g_settings_bind ( - settings, "menubar-visible-sub", - shell_window, "menubar-visible", - G_SETTINGS_BIND_DEFAULT | - G_SETTINGS_BIND_GET_NO_CHANGES); - - g_settings_bind ( - settings, "folder-bar-width-sub", - priv->content_pane, "position", - G_SETTINGS_BIND_DEFAULT | - G_SETTINGS_BIND_GET_NO_CHANGES); - - g_settings_bind ( - settings, "sidebar-visible-sub", - shell_window, "sidebar-visible", - G_SETTINGS_BIND_DEFAULT | - G_SETTINGS_BIND_GET_NO_CHANGES); - - g_settings_bind ( - settings, "statusbar-visible-sub", - shell_window, "taskbar-visible", - G_SETTINGS_BIND_DEFAULT | - G_SETTINGS_BIND_GET_NO_CHANGES); - - g_settings_bind ( - settings, "buttons-visible-sub", - shell_window, "switcher-visible", - G_SETTINGS_BIND_DEFAULT | - G_SETTINGS_BIND_GET_NO_CHANGES); - - g_settings_bind ( - settings, "toolbar-visible-sub", - shell_window, "toolbar-visible", - G_SETTINGS_BIND_DEFAULT | - G_SETTINGS_BIND_GET_NO_CHANGES); - } - /* Configure the initial size and position of the window by way * of either a user-supplied geometry string or the last recorded * values. Note that if a geometry string is applied, the window @@ -581,40 +254,7 @@ e_shell_window_private_constructed (EShellWindow *shell_window) E_RESTORE_WINDOW_SIZE | E_RESTORE_WINDOW_POSITION); } - shell_window_init_switcher_style (shell_window); - - id = "org.gnome.evolution.shell"; - e_plugin_ui_register_manager (ui_manager, id, shell_window); - e_plugin_ui_enable_manager (ui_manager, id); - - gtk_application_add_window (GTK_APPLICATION (shell), window); - g_object_unref (settings); - - g_signal_connect (shell_window, "key-press-event", - G_CALLBACK (e_shell_window_key_press_event_cb), NULL); - - if (e_util_get_use_header_bar ()) { - /* XXX The ECalShellBackend has a hack where it forces the - * EMenuButton to update its button image by forcing - * a "notify::active-view" signal emission on the window. - * This will trigger the property binding, which will set - * EMenuButton's "prefer-item" property, which will - * invoke header_bar_update_new_menu(), which - * will cause EMenuButton to update its button image. - * - * It's a bit of a Rube Goldberg machine and should be - * reworked, but it's just serving one (now documented) - * corner case and works for now. */ - e_binding_bind_property_full ( - shell_window, "active-view", - e_shell_header_bar_get_new_button (E_SHELL_HEADER_BAR (priv->headerbar)), - "prefer-item", - G_BINDING_SYNC_CREATE, - shell_window_active_view_to_prefer_item, - (GBindingTransformFunc) NULL, - NULL, (GDestroyNotify) NULL); - } } void @@ -622,7 +262,7 @@ e_shell_window_private_dispose (EShellWindow *shell_window) { EShellWindowPrivate *priv = shell_window->priv; - if (priv->active_view && *priv->active_view) { + if (*priv->active_view) { GSettings *settings; settings = e_util_ref_settings ("org.gnome.evolution.shell"); @@ -652,18 +292,13 @@ e_shell_window_private_dispose (EShellWindow *shell_window) } g_clear_object (&priv->focus_tracker); - g_clear_object (&priv->ui_manager); g_hash_table_remove_all (priv->loaded_views); + g_hash_table_remove_all (priv->action_groups); g_clear_object (&priv->alert_bar); - g_clear_object (&priv->content_pane); - g_clear_object (&priv->content_notebook); - g_clear_object (&priv->sidebar_notebook); - g_clear_object (&priv->switcher); - g_clear_object (&priv->tooltip_label); - g_clear_object (&priv->status_notebook); - g_clear_object (&priv->menu_bar); + g_clear_object (&priv->headerbar_box); + g_clear_object (&priv->switch_to_menu); } void @@ -672,65 +307,66 @@ e_shell_window_private_finalize (EShellWindow *shell_window) EShellWindowPrivate *priv = shell_window->priv; g_hash_table_destroy (priv->loaded_views); - g_hash_table_destroy (priv->action_groups_by_view); + g_hash_table_destroy (priv->action_groups); g_slist_free_full (priv->postponed_alerts, g_object_unref); g_free (priv->geometry); } -static void -e_shell_window_activate_action_groups_for_view (EShellWindow *shell_window, - const gchar *view_name) -{ - GHashTableIter iter; - gpointer key, value; - - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - if (!e_shell_window_get_ui_manager (shell_window)) - return; - - g_hash_table_iter_init (&iter, shell_window->priv->action_groups_by_view); - - while (g_hash_table_iter_next (&iter, &key, &value)) { - gboolean is_active = g_strcmp0 (key, view_name) == 0; - GPtrArray *action_groups = value; - guint ii; - - /* The 'calendar' view uses actions from 'memos' and 'tasks', - thus make sure these are active too. */ - if (!is_active && g_strcmp0 (view_name, "calendar") == 0 && - (g_strcmp0 (key, "memos") == 0 || g_strcmp0 (key, "tasks") == 0)) - is_active = TRUE; - - for (ii = 0; ii < action_groups->len; ii++) { - GtkActionGroup *action_group = g_ptr_array_index (action_groups, ii); - - /* Set both, because using 'visible' doesn't work for the first key press, - while 'sensitive' does, even it is used by some 'update-actions' handlers. */ - gtk_action_group_set_visible (action_group, is_active); - gtk_action_group_set_sensitive (action_group, is_active); - } - } -} - void e_shell_window_switch_to_view (EShellWindow *shell_window, const gchar *view_name) { EShellView *shell_view; + GtkWidget *headerbar; + gint page_num, visible_page_num; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); g_return_if_fail (view_name != NULL); - if (shell_window->priv->active_view == view_name) + if (g_strcmp0 (shell_window->priv->active_view, view_name) == 0) return; shell_view = e_shell_window_get_shell_view (shell_window, view_name); + if (!shell_view) { + GHashTableIter iter; + gpointer value; - e_shell_window_activate_action_groups_for_view (shell_window, view_name); + g_warning ("%s: Shell view '%s' not found among %u loaded views", G_STRFUNC, + view_name, g_hash_table_size (shell_window->priv->loaded_views)); - shell_window->priv->active_view = view_name; + g_hash_table_iter_init (&iter, shell_window->priv->loaded_views); + if (!g_hash_table_iter_next (&iter, NULL, &value)) + return; + + shell_view = value; + } + + page_num = e_shell_view_get_page_num (shell_view); + visible_page_num = gtk_notebook_get_current_page (shell_window->priv->views_notebook); + if (page_num != visible_page_num && visible_page_num >= 0 && + visible_page_num < gtk_notebook_get_n_pages (shell_window->priv->views_notebook)) { + GtkWidget *page; + + page = gtk_notebook_get_nth_page (shell_window->priv->views_notebook, visible_page_num); + if (page) { + EShellView *visible_view = E_SHELL_VIEW (page); + + if (visible_view) { + headerbar = e_shell_view_get_headerbar (visible_view); + if (headerbar) + gtk_widget_set_visible (headerbar, FALSE); + } + } + } + + gtk_notebook_set_current_page (shell_window->priv->views_notebook, page_num); + + headerbar = e_shell_view_get_headerbar (shell_view); + if (headerbar) + gtk_widget_set_visible (headerbar, TRUE); + + g_warn_if_fail (g_snprintf (shell_window->priv->active_view, sizeof (shell_window->priv->active_view), "%s", view_name) < sizeof (shell_window->priv->active_view)); g_object_notify (G_OBJECT (shell_window), "active-view"); e_shell_view_update_actions (shell_view); @@ -740,19 +376,16 @@ void e_shell_window_update_icon (EShellWindow *shell_window) { EShellView *shell_view; - GtkAction *action; + EUIAction *action; const gchar *view_name; - gchar *icon_name = NULL; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); view_name = e_shell_window_get_active_view (shell_window); shell_view = e_shell_window_get_shell_view (shell_window, view_name); - action = e_shell_view_get_action (shell_view); - g_object_get (action, "icon-name", &icon_name, NULL); - gtk_window_set_icon_name (GTK_WINDOW (shell_window), icon_name); - g_free (icon_name); + action = e_shell_view_get_switcher_action (shell_view); + gtk_window_set_icon_name (GTK_WINDOW (shell_window), e_ui_action_get_icon_name (action)); } void @@ -779,3 +412,14 @@ e_shell_window_update_title (EShellWindow *shell_window) g_free (window_title); } } + +GMenuModel * +e_shell_window_ref_switch_to_menu_model (EShellWindow *self) +{ + g_return_val_if_fail (E_IS_SHELL_WINDOW (self), NULL); + + if (!self->priv->switch_to_menu) + return NULL; + + return G_MENU_MODEL (g_object_ref (self->priv->switch_to_menu)); +} diff --git a/src/shell/e-shell-window-private.h b/src/shell/e-shell-window-private.h index a172e82999..253fe7a79f 100644 --- a/src/shell/e-shell-window-private.h +++ b/src/shell/e-shell-window-private.h @@ -32,7 +32,6 @@ #include "shell/e-shell.h" #include "shell/e-shell-content.h" -#include "shell/e-shell-headerbar.h" #include "shell/e-shell-view.h" #include "shell/e-shell-searchbar.h" #include "shell/e-shell-switcher.h" @@ -45,11 +44,7 @@ #define ACTION_GROUP(name) \ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window)) -/* Format for switcher action names. - * The last part is the shell view name. - * (e.g. switch-to-mail, switch-to-calendar) */ -#define E_SHELL_SWITCHER_FORMAT "switch-to-%s" -#define E_SHELL_NEW_WINDOW_FORMAT "new-%s-window" +#define E_SHELL_SWITCHER_FORMAT "switch-to-%s" G_BEGIN_DECLS @@ -60,27 +55,19 @@ struct _EShellWindowPrivate { /*** UI Management ***/ EFocusTracker *focus_tracker; - GtkUIManager *ui_manager; - guint custom_rule_merge_id; - guint gal_view_merge_id; + GHashTable *action_groups; /* gchar *name ~> EUIActionGroup * */ /*** Shell Views ***/ GHashTable *loaded_views; - const gchar *active_view; - GHashTable *action_groups_by_view; + gchar active_view[32]; + GMenu *switch_to_menu; /*** Widgetry ***/ + GtkBox *headerbar_box; GtkWidget *alert_bar; - GtkWidget *content_pane; - GtkWidget *content_notebook; - GtkWidget *sidebar_notebook; - GtkWidget *switcher; - GtkWidget *tooltip_label; - GtkWidget *status_notebook; - GtkWidget *headerbar; - EMenuBar *menu_bar; + GtkNotebook *views_notebook; /* Shell signal handlers. */ GArray *signal_handler_ids; @@ -88,10 +75,6 @@ struct _EShellWindowPrivate { gchar *geometry; guint safe_mode : 1; - guint sidebar_visible : 1; - guint switcher_visible : 1; - guint taskbar_visible : 1; - guint toolbar_visible : 1; guint is_main_instance : 1; GSList *postponed_alerts; /* EAlert * */ @@ -105,19 +88,20 @@ void e_shell_window_private_finalize (EShellWindow *shell_window); /* Private Utilities */ -void e_shell_window_actions_init (EShellWindow *shell_window); +void e_shell_window_actions_constructed + (EShellWindow *shell_window); +void e_shell_window_init_ui_data (EShellWindow *shell_window, + EShellView *shell_view); +void e_shell_window_fill_switcher_actions + (EShellWindow *shell_window, + EUIManager *ui_manager, + EShellSwitcher *switcher); void e_shell_window_switch_to_view (EShellWindow *shell_window, const gchar *view_name); -GtkWidget * e_shell_window_create_new_menu (EShellWindow *shell_window); -void e_shell_window_create_switcher_actions - (EShellWindow *shell_window); -void e_shell_window_update_gal_view (EShellWindow *shell_window); void e_shell_window_update_icon (EShellWindow *shell_window); void e_shell_window_update_title (EShellWindow *shell_window); -void e_shell_window_update_new_menu (EShellWindow *shell_window); -void e_shell_window_update_view_menu (EShellWindow *shell_window); -void e_shell_window_update_search_menu - (EShellWindow *shell_window); +GMenuModel * e_shell_window_ref_switch_to_menu_model + (EShellWindow *self); G_END_DECLS diff --git a/src/shell/e-shell-window.c b/src/shell/e-shell-window.c index 21940d08f0..84cc8c8035 100644 --- a/src/shell/e-shell-window.c +++ b/src/shell/e-shell-window.c @@ -35,13 +35,7 @@ enum { PROP_FOCUS_TRACKER, PROP_GEOMETRY, PROP_SAFE_MODE, - PROP_SHELL, - PROP_MENUBAR_VISIBLE, - PROP_SIDEBAR_VISIBLE, - PROP_SWITCHER_VISIBLE, - PROP_TASKBAR_VISIBLE, - PROP_TOOLBAR_VISIBLE, - PROP_UI_MANAGER + PROP_SHELL }; enum { @@ -90,98 +84,11 @@ toolbar {\ }\ "; -static void -shell_window_menubar_update_new_menu (EShellWindow *shell_window) -{ - GtkWidget *menu; - GtkWidget *widget; - const gchar *path; - - /* Update the "File -> New" submenu. */ - path = "/main-menu/file-menu/new-menu"; - menu = e_shell_window_create_new_menu (shell_window); - widget = e_shell_window_get_managed_widget (shell_window, path); - gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), menu); - gtk_widget_show (widget); -} - -static void -shell_window_toolbar_update_new_menu (EShellWindow *shell_window, - GtkMenuToolButton *menu_tool_button) -{ - GtkWidget *menu; - - /* Update the "New" menu tool button submenu. */ - menu = e_shell_window_create_new_menu (shell_window); - gtk_menu_tool_button_set_menu (menu_tool_button, menu); -} - -static void -shell_window_toolbar_prefer_item_cb (GtkMenuToolButton *menu_tool_button, - GParamSpec *pspec, - EShellWindow *shell_window) -{ - shell_window_toolbar_update_new_menu (shell_window, menu_tool_button); -} - -static gboolean -shell_window_active_view_to_prefer_item (GBinding *binding, - const GValue *source_value, - GValue *target_value, - gpointer user_data) -{ - GObject *source_object; - EShell *shell; - EShellBackend *shell_backend; - const gchar *active_view; - const gchar *prefer_item; - - active_view = g_value_get_string (source_value); - - source_object = g_binding_get_source (binding); - shell = e_shell_window_get_shell (E_SHELL_WINDOW (source_object)); - shell_backend = e_shell_get_backend_by_name (shell, active_view); - prefer_item = e_shell_backend_get_prefer_new_item (shell_backend); - - g_value_set_string (target_value, prefer_item); - - return TRUE; -} - -static void -shell_window_set_notebook_page (EShellWindow *shell_window, - GParamSpec *pspec, - GtkNotebook *notebook) -{ - EShellView *shell_view; - const gchar *view_name; - gint page_num; - - view_name = e_shell_window_get_active_view (shell_window); - shell_view = e_shell_window_get_shell_view (shell_window, view_name); - - page_num = e_shell_view_get_page_num (shell_view); - g_return_if_fail (page_num >= 0); - - gtk_notebook_set_current_page (notebook, page_num); - - g_signal_emit (shell_window, signals[UPDATE_NEW_MENU], 0, NULL); -} - -static void -shell_window_online_button_clicked_cb (EOnlineButton *button, - EShellWindow *shell_window) -{ - if (e_online_button_get_online (button)) - gtk_action_activate (ACTION (WORK_OFFLINE)); - else - gtk_action_activate (ACTION (WORK_ONLINE)); -} - static void shell_window_update_close_action_cb (EShellWindow *shell_window) { EShell *shell; + EUIAction *action; GtkApplication *application; GList *list; gint n_shell_windows = 0; @@ -192,15 +99,17 @@ shell_window_update_close_action_cb (EShellWindow *shell_window) list = gtk_application_get_windows (application); /* Count the shell windows. */ - while (list != NULL) { + while (list != NULL && n_shell_windows <= 1) { if (E_IS_SHELL_WINDOW (list->data)) n_shell_windows++; list = g_list_next (list); } + action = e_shell_window_get_ui_action (shell_window, "close"); + /* Disable Close Window if there's only one shell window. * Helps prevent users from accidentally quitting. */ - gtk_action_set_sensitive (ACTION (CLOSE), n_shell_windows > 1); + e_ui_action_set_sensitive (action, n_shell_windows > 1); } static void @@ -277,36 +186,6 @@ shell_window_set_property (GObject *object, E_SHELL_WINDOW (object), g_value_get_object (value)); return; - - case PROP_MENUBAR_VISIBLE: - e_shell_window_set_menubar_visible ( - E_SHELL_WINDOW (object), - g_value_get_boolean (value)); - return; - - case PROP_SIDEBAR_VISIBLE: - e_shell_window_set_sidebar_visible ( - E_SHELL_WINDOW (object), - g_value_get_boolean (value)); - return; - - case PROP_SWITCHER_VISIBLE: - e_shell_window_set_switcher_visible ( - E_SHELL_WINDOW (object), - g_value_get_boolean (value)); - return; - - case PROP_TASKBAR_VISIBLE: - e_shell_window_set_taskbar_visible ( - E_SHELL_WINDOW (object), - g_value_get_boolean (value)); - return; - - case PROP_TOOLBAR_VISIBLE: - e_shell_window_set_toolbar_visible ( - E_SHELL_WINDOW (object), - g_value_get_boolean (value)); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -348,42 +227,6 @@ shell_window_get_property (GObject *object, value, e_shell_window_get_shell ( E_SHELL_WINDOW (object))); return; - - case PROP_MENUBAR_VISIBLE: - g_value_set_boolean ( - value, e_shell_window_get_menubar_visible ( - E_SHELL_WINDOW (object))); - return; - - case PROP_SIDEBAR_VISIBLE: - g_value_set_boolean ( - value, e_shell_window_get_sidebar_visible ( - E_SHELL_WINDOW (object))); - return; - - case PROP_SWITCHER_VISIBLE: - g_value_set_boolean ( - value, e_shell_window_get_switcher_visible ( - E_SHELL_WINDOW (object))); - return; - - case PROP_TASKBAR_VISIBLE: - g_value_set_boolean ( - value, e_shell_window_get_taskbar_visible ( - E_SHELL_WINDOW (object))); - return; - - case PROP_TOOLBAR_VISIBLE: - g_value_set_boolean ( - value, e_shell_window_get_toolbar_visible ( - E_SHELL_WINDOW (object))); - return; - - case PROP_UI_MANAGER: - g_value_set_object ( - value, e_shell_window_get_ui_manager ( - E_SHELL_WINDOW (object))); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -412,12 +255,12 @@ shell_window_constructed (GObject *object) { EShellWindow *shell_window = E_SHELL_WINDOW (object); + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_shell_window_parent_class)->constructed (object); + e_shell_window_private_constructed (shell_window); e_extensible_load_extensions (E_EXTENSIBLE (object)); - - /* Chain up to parent's constructed() method. */ - G_OBJECT_CLASS (e_shell_window_parent_class)->constructed (object); } static void @@ -442,269 +285,27 @@ shell_window_close_alert (EShellWindow *shell_window) } static void -shell_window_menubar_deactivate_cb (GtkWidget *main_menu, - gpointer user_data) +e_shell_window_update_icon_for_active_view (EUIAction *action, + GParamSpec *param, + gpointer user_data) { - EShellWindow *shell_window = user_data; + EShellWindow *self = user_data; + EUIAction *active_view_action; - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - if (!e_shell_window_get_menubar_visible (shell_window)) - gtk_widget_hide (main_menu); + active_view_action = e_shell_window_get_shell_view_action (self, e_shell_window_get_active_view (self)); + if (active_view_action == action) + e_shell_window_update_icon (self); } -static GtkWidget * -shell_window_construct_menubar (EShellWindow *shell_window) +static void +e_shell_window_update_title_for_active_view (EShellView *shell_view, + GParamSpec *param, + gpointer user_data) { - GtkWidget *main_menu; + EShellWindow *self = user_data; - main_menu = e_shell_window_get_managed_widget ( - shell_window, "/main-menu"); - - g_signal_connect (main_menu, "deactivate", - G_CALLBACK (shell_window_menubar_deactivate_cb), shell_window); - - e_binding_bind_property ( - shell_window, "menubar-visible", - main_menu, "visible", - G_BINDING_SYNC_CREATE); - - g_signal_connect ( - shell_window, "update-new-menu", - G_CALLBACK (shell_window_menubar_update_new_menu), NULL); - - return main_menu; -} - -static GtkWidget * -shell_window_construct_toolbar (EShellWindow *shell_window) -{ - GtkWidget *toolbar; - GtkWidget *box; - - box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); - gtk_widget_show (box); - - e_binding_bind_property ( - shell_window, "toolbar-visible", - box, "visible", - G_BINDING_SYNC_CREATE); - - toolbar = e_shell_window_get_managed_widget ( - shell_window, "/main-toolbar"); - e_util_setup_toolbar_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON); - - gtk_style_context_add_class ( - gtk_widget_get_style_context (toolbar), - GTK_STYLE_CLASS_PRIMARY_TOOLBAR); - - if (!e_util_get_use_header_bar ()) { - GtkUIManager *ui_manager; - GtkToolItem *item; - - ui_manager = e_shell_window_get_ui_manager (shell_window); - /* XXX Having this separator in the UI definition doesn't work - * because GtkUIManager is unaware of the "New" button, so - * it makes the separator invisible. One possibility is to - * define a GtkAction subclass for which create_tool_item() - * return an EMenuToolButton. Then both this separator - * and the "New" button could be added to the UI definition. - * Tempting, but the "New" button and its dynamically - * generated menu is already a complex beast, and I'm not - * convinced having it proxy some new type of GtkAction - * is worth the extra effort. */ - item = gtk_separator_tool_item_new (); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0); - gtk_widget_show (GTK_WIDGET (item)); - - /* Translators: a 'New' toolbar button caption which is context sensitive and - runs one of the actions under File->New menu */ - item = e_menu_tool_button_new (C_("toolbar-button", "New")); - gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE); - gtk_widget_add_accelerator ( - GTK_WIDGET (item), "clicked", - gtk_ui_manager_get_accel_group (ui_manager), - GDK_KEY_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); - gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0); - gtk_widget_show (GTK_WIDGET (item)); - - /* XXX The ECalShellBackend has a hack where it forces the - * EMenuToolButton to update its button image by forcing - * a "notify::active-view" signal emission on the window. - * This will trigger the property binding, which will set - * EMenuToolButton's "prefer-item" property, which will - * invoke shell_window_toolbar_update_new_menu(), which - * will cause EMenuToolButton to update its button image. - * - * It's a bit of a Rube Goldberg machine and should be - * reworked, but it's just serving one (now documented) - * corner case and works for now. */ - e_binding_bind_property_full ( - shell_window, "active-view", - item, "prefer-item", - G_BINDING_SYNC_CREATE, - shell_window_active_view_to_prefer_item, - (GBindingTransformFunc) NULL, - NULL, (GDestroyNotify) NULL); - - g_signal_connect_object ( - item, "notify::prefer-item", - G_CALLBACK (shell_window_toolbar_prefer_item_cb), - shell_window, 0); - - g_signal_connect_object ( - shell_window, "update-new-menu", - G_CALLBACK (shell_window_toolbar_update_new_menu), - item, 0); - } - - gtk_box_pack_start (GTK_BOX (box), toolbar, TRUE, TRUE, 0); - - toolbar = e_shell_window_get_managed_widget ( - shell_window, "/search-toolbar"); - gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE); - e_util_setup_toolbar_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON); - - toolbar = e_shell_window_get_managed_widget ( - shell_window, "/close-toolbar"); - gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE); - e_util_setup_toolbar_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_BUTTON); - - return box; -} - -static GtkWidget * -shell_window_construct_sidebar (EShellWindow *shell_window) -{ - GtkWidget *notebook; - GtkWidget *switcher; - - switcher = e_shell_switcher_new (); - shell_window->priv->switcher = g_object_ref_sink (switcher); - - e_binding_bind_property ( - shell_window, "sidebar-visible", - switcher, "visible", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - shell_window, "switcher-visible", - switcher, "toolbar-visible", - G_BINDING_SYNC_CREATE); - - notebook = gtk_notebook_new (); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE); - gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE); - gtk_container_add (GTK_CONTAINER (switcher), notebook); - shell_window->priv->sidebar_notebook = g_object_ref (notebook); - gtk_widget_show (notebook); - - e_signal_connect_notify ( - shell_window, "notify::active-view", - G_CALLBACK (shell_window_set_notebook_page), notebook); - - return switcher; -} - -static GtkWidget * -shell_window_construct_content (EShellWindow *shell_window) -{ - GtkWidget *box; - GtkWidget *widget; - - box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_show (box); - - widget = e_alert_bar_new (); - gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0); - shell_window->priv->alert_bar = g_object_ref (widget); - /* EAlertBar controls its own visibility. */ - - widget = gtk_notebook_new (); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); - gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE); - gtk_box_pack_start (GTK_BOX (box), widget, TRUE, TRUE, 0); - shell_window->priv->content_notebook = g_object_ref (widget); - gtk_widget_show (widget); - - e_signal_connect_notify ( - shell_window, "notify::active-view", - G_CALLBACK (shell_window_set_notebook_page), widget); - - return box; -} - -static GtkWidget * -shell_window_construct_taskbar (EShellWindow *shell_window) -{ - EShell *shell; - GtkWidget *box; - GtkWidget *notebook; - GtkWidget *status_area; - GtkWidget *online_button; - GtkWidget *tooltip_label; - GtkStyleContext *style_context; - gint height; - - shell = e_shell_window_get_shell (shell_window); - - box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3); - gtk_container_set_border_width (GTK_CONTAINER (box), 3); - gtk_widget_show (box); - - status_area = gtk_frame_new (NULL); - style_context = gtk_widget_get_style_context (status_area); - gtk_style_context_add_class (style_context, "taskbar"); - gtk_container_add (GTK_CONTAINER (status_area), box); - - e_binding_bind_property ( - shell_window, "taskbar-visible", - status_area, "visible", - G_BINDING_SYNC_CREATE); - - /* Make the status area as large as the task bar. */ - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &height); - gtk_widget_set_size_request (status_area, -1, (height * 2) + 6); - - online_button = e_online_button_new (); - gtk_box_pack_start ( - GTK_BOX (box), online_button, FALSE, TRUE, 0); - gtk_widget_show (online_button); - - e_binding_bind_property ( - shell, "online", - online_button, "online", - G_BINDING_SYNC_CREATE); - - e_binding_bind_property ( - shell, "network-available", - online_button, "sensitive", - G_BINDING_SYNC_CREATE); - - g_signal_connect ( - online_button, "clicked", - G_CALLBACK (shell_window_online_button_clicked_cb), - shell_window); - - tooltip_label = gtk_label_new (""); - gtk_misc_set_alignment (GTK_MISC (tooltip_label), 0.0, 0.5); - gtk_box_pack_start ( - GTK_BOX (box), tooltip_label, TRUE, TRUE, 0); - shell_window->priv->tooltip_label = g_object_ref (tooltip_label); - gtk_widget_hide (tooltip_label); - - notebook = gtk_notebook_new (); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (notebook), FALSE); - gtk_notebook_set_show_border (GTK_NOTEBOOK (notebook), FALSE); - gtk_box_pack_start (GTK_BOX (box), notebook, TRUE, TRUE, 0); - shell_window->priv->status_notebook = g_object_ref (notebook); - gtk_widget_show (notebook); - - e_signal_connect_notify ( - shell_window, "notify::active-view", - G_CALLBACK (shell_window_set_notebook_page), notebook); - - return status_area; + if (e_shell_view_is_active (shell_view)) + e_shell_window_update_title (self); } static EShellView * @@ -715,12 +316,10 @@ shell_window_create_shell_view (EShellWindow *shell_window, EShellView *shell_view; EShellBackend *shell_backend; GHashTable *loaded_views; - GtkUIManager *ui_manager; GtkNotebook *notebook; - GtkAction *action; - GtkWidget *widget; + GSettings *settings; + EUIAction *action; const gchar *name; - const gchar *id; gint page_num; GType type; @@ -728,8 +327,48 @@ shell_window_create_shell_view (EShellWindow *shell_window, shell_backend = e_shell_get_backend_by_name (shell, view_name); if (shell_backend == NULL) { + GList *backends; + g_critical ("Unknown shell view name: %s", view_name); - return NULL; + + backends = e_shell_get_shell_backends (shell); + if (!backends) { + notebook = GTK_NOTEBOOK (shell_window->priv->views_notebook); + + if (!gtk_notebook_get_n_pages (notebook)) { + GtkWidget *widget; + + if (shell_window->priv->headerbar_box) { + widget = gtk_header_bar_new (); + + gtk_header_bar_set_show_close_button (GTK_HEADER_BAR (widget), TRUE); + gtk_widget_set_visible (widget, TRUE); + + gtk_box_pack_start (shell_window->priv->headerbar_box, widget, FALSE, FALSE, 0); + + e_binding_bind_property (widget, "title", + shell_window, "title", + G_BINDING_DEFAULT); + + gtk_header_bar_set_title (GTK_HEADER_BAR (widget), _("Evolution")); + } + + widget = gtk_label_new ("Failed to load any view. Is installation broken?"); + gtk_widget_set_visible (widget, TRUE); + + gtk_notebook_set_current_page (notebook, gtk_notebook_append_page (notebook, widget, NULL)); + } + + return NULL; + } + + /* fallback to one of the existing shell views, to not have shown an empty window */ + shell_backend = E_SHELL_BACKEND (backends->data); + + /* does the fallback already exist? */ + shell_view = g_hash_table_lookup (shell_window->priv->loaded_views, E_SHELL_BACKEND_GET_CLASS (shell_backend)->name); + if (shell_view) + return shell_view; } name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name; @@ -739,65 +378,128 @@ shell_window_create_shell_view (EShellWindow *shell_window, e_shell_backend_start (shell_backend); /* Determine the page number for the new shell view. */ - notebook = GTK_NOTEBOOK (shell_window->priv->content_notebook); + notebook = GTK_NOTEBOOK (shell_window->priv->views_notebook); page_num = gtk_notebook_get_n_pages (notebook); /* Get the switcher action for this view. */ action = e_shell_window_get_shell_view_action (shell_window, name); /* Create the shell view. */ - shell_view = g_object_new ( - type, "action", action, "page-num", page_num, - "shell-window", shell_window, NULL); + shell_view = g_object_new (type, + "switcher-action", action, + "page-num", page_num, + "shell-window", shell_window, + NULL); /* Register the shell view. */ loaded_views = shell_window->priv->loaded_views; - g_hash_table_insert (loaded_views, g_strdup (name), shell_view); - - /* Register the GtkUIManager ID for the shell view. */ - id = E_SHELL_VIEW_GET_CLASS (shell_view)->ui_manager_id; - ui_manager = e_shell_window_get_ui_manager (shell_window); - e_plugin_ui_register_manager (ui_manager, id, shell_view); - - /* Add pages to the various shell window notebooks. */ + g_hash_table_insert (loaded_views, g_strdup (name), g_object_ref_sink (shell_view)); /* We can't determine the shell view's page number until after the * shell view is fully initialized because the shell view may load * other shell views during initialization, and those other shell * views will append their widgets to the notebooks before us. */ - page_num = gtk_notebook_get_n_pages (notebook); + page_num = gtk_notebook_append_page (notebook, GTK_WIDGET (shell_view), NULL); e_shell_view_set_page_num (shell_view, page_num); - notebook = GTK_NOTEBOOK (shell_window->priv->content_notebook); - widget = GTK_WIDGET (e_shell_view_get_shell_content (shell_view)); - gtk_notebook_append_page (notebook, widget, NULL); + if (e_shell_view_get_headerbar (shell_view) && + shell_window->priv->headerbar_box) { + GtkWidget *headerbar; - notebook = GTK_NOTEBOOK (shell_window->priv->sidebar_notebook); - widget = GTK_WIDGET (e_shell_view_get_shell_sidebar (shell_view)); - gtk_notebook_append_page (notebook, widget, NULL); + headerbar = g_object_ref (e_shell_view_get_headerbar (shell_view)); + gtk_widget_unparent (headerbar); - notebook = GTK_NOTEBOOK (shell_window->priv->status_notebook); - widget = GTK_WIDGET (e_shell_view_get_shell_taskbar (shell_view)); - gtk_notebook_append_page (notebook, widget, NULL); + gtk_box_pack_start (shell_window->priv->headerbar_box, headerbar, FALSE, FALSE, 0); + gtk_widget_set_visible (headerbar, g_hash_table_size (loaded_views) == 1); - e_binding_bind_property ( - widget, "height-request", - shell_window->priv->tooltip_label, "height-request", - G_BINDING_SYNC_CREATE); + e_binding_bind_property (shell_window, "title", + headerbar, "title", + G_BINDING_SYNC_CREATE); + + g_clear_object (&headerbar); + } + + settings = e_util_ref_settings ("org.gnome.evolution.shell"); + + if (e_shell_window_is_main_instance (shell_window)) { + g_settings_bind ( + settings, "folder-bar-width", + shell_view, "sidebar-width", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind ( + settings, "menubar-visible", + shell_view, "menubar-visible", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind ( + settings, "sidebar-visible", + shell_view, "sidebar-visible", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind ( + settings, "statusbar-visible", + shell_view, "taskbar-visible", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind ( + settings, "buttons-visible", + shell_view, "switcher-visible", + G_SETTINGS_BIND_DEFAULT); + + g_settings_bind ( + settings, "toolbar-visible", + shell_view, "toolbar-visible", + G_SETTINGS_BIND_DEFAULT); + } else { + g_settings_bind ( + settings, "folder-bar-width-sub", + shell_view, "sidebar-width", + G_SETTINGS_BIND_DEFAULT | + G_SETTINGS_BIND_GET_NO_CHANGES); + + g_settings_bind ( + settings, "menubar-visible-sub", + shell_view, "menubar-visible", + G_SETTINGS_BIND_DEFAULT | + G_SETTINGS_BIND_GET_NO_CHANGES); + + g_settings_bind ( + settings, "sidebar-visible-sub", + shell_view, "sidebar-visible", + G_SETTINGS_BIND_DEFAULT | + G_SETTINGS_BIND_GET_NO_CHANGES); + + g_settings_bind ( + settings, "statusbar-visible-sub", + shell_view, "taskbar-visible", + G_SETTINGS_BIND_DEFAULT | + G_SETTINGS_BIND_GET_NO_CHANGES); + + g_settings_bind ( + settings, "buttons-visible-sub", + shell_view, "switcher-visible", + G_SETTINGS_BIND_DEFAULT | + G_SETTINGS_BIND_GET_NO_CHANGES); + + g_settings_bind ( + settings, "toolbar-visible-sub", + shell_view, "toolbar-visible", + G_SETTINGS_BIND_DEFAULT | + G_SETTINGS_BIND_GET_NO_CHANGES); + } + + g_clear_object (&settings); /* Listen for changes that affect the shell window. */ - e_signal_connect_notify_swapped ( + e_signal_connect_notify_object ( action, "notify::icon-name", - G_CALLBACK (e_shell_window_update_icon), shell_window); + G_CALLBACK (e_shell_window_update_icon_for_active_view), shell_window, 0); - e_signal_connect_notify_swapped ( + e_signal_connect_notify_object ( shell_view, "notify::title", - G_CALLBACK (e_shell_window_update_title), shell_window); - - e_signal_connect_notify_swapped ( - shell_view, "notify::view-id", - G_CALLBACK (e_shell_window_update_view_menu), shell_window); + G_CALLBACK (e_shell_window_update_title_for_active_view), shell_window, 0); return shell_view; } @@ -906,12 +608,6 @@ e_shell_window_class_init (EShellWindowClass *class) widget_class->map = shell_window_map; class->close_alert = shell_window_close_alert; - class->construct_menubar = shell_window_construct_menubar; - class->construct_toolbar = shell_window_construct_toolbar; - class->construct_sidebar = shell_window_construct_sidebar; - class->construct_content = shell_window_construct_content; - class->construct_taskbar = shell_window_construct_taskbar; - class->create_shell_view = shell_window_create_shell_view; /** * EShellWindow:active-view @@ -1012,105 +708,6 @@ e_shell_window_class_init (EShellWindowClass *class) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - /** - * EShellWindow:menubar-visible - * - * Whether the shell window's menu bar is visible. - * - * Since: 3.24 - **/ - g_object_class_install_property ( - object_class, - PROP_MENUBAR_VISIBLE, - g_param_spec_boolean ( - "menubar-visible", - "Menubar Visible", - "Whether the shell window's menu bar is visible", - TRUE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - /** - * EShellWindow:sidebar-visible - * - * Whether the shell window's side bar is visible. - **/ - g_object_class_install_property ( - object_class, - PROP_SIDEBAR_VISIBLE, - g_param_spec_boolean ( - "sidebar-visible", - "Sidebar Visible", - "Whether the shell window's side bar is visible", - TRUE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - /** - * EShellWindow:switcher-visible - * - * Whether the shell window's switcher buttons are visible. - **/ - g_object_class_install_property ( - object_class, - PROP_SWITCHER_VISIBLE, - g_param_spec_boolean ( - "switcher-visible", - "Switcher Visible", - "Whether the shell window's " - "switcher buttons are visible", - TRUE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - /** - * EShellWindow:taskbar-visible - * - * Whether the shell window's task bar is visible. - **/ - g_object_class_install_property ( - object_class, - PROP_TASKBAR_VISIBLE, - g_param_spec_boolean ( - "taskbar-visible", - "Taskbar Visible", - "Whether the shell window's task bar is visible", - TRUE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - /** - * EShellWindow:toolbar-visible - * - * Whether the shell window's tool bar is visible. - **/ - g_object_class_install_property ( - object_class, - PROP_TOOLBAR_VISIBLE, - g_param_spec_boolean ( - "toolbar-visible", - "Toolbar Visible", - "Whether the shell window's tool bar is visible", - TRUE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - /** - * EShellWindow:ui-manager - * - * The shell window's #GtkUIManager. - **/ - g_object_class_install_property ( - object_class, - PROP_UI_MANAGER, - g_param_spec_object ( - "ui-manager", - "UI Manager", - "The shell window's GtkUIManager", - GTK_TYPE_UI_MANAGER, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** * EShellWindow::close-alert * @shell_window: the #EShellWindow which emitted the signal @@ -1284,7 +881,6 @@ e_shell_window_get_shell_view (EShellWindow *shell_window, const gchar *view_name) { EShellView *shell_view; - EShellWindowClass *class; g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL); g_return_val_if_fail (view_name != NULL, NULL); @@ -1293,11 +889,12 @@ e_shell_window_get_shell_view (EShellWindow *shell_window, if (shell_view != NULL) return shell_view; - class = E_SHELL_WINDOW_GET_CLASS (shell_window); - g_return_val_if_fail (class != NULL, NULL); - g_return_val_if_fail (class->create_shell_view != NULL, NULL); + shell_view = shell_window_create_shell_view (shell_window, view_name); - shell_view = class->create_shell_view (shell_window, view_name); + if (shell_view) { + /* it can fallback to a different view, if the @view_name does not exist */ + view_name = e_shell_view_get_name (shell_view); + } g_signal_emit ( shell_window, signals[SHELL_VIEW_CREATED], @@ -1341,7 +938,7 @@ e_shell_window_peek_shell_view (EShellWindow *shell_window, * * Returns the switcher action for @view_name. * - * An #EShellWindow creates a #GtkRadioAction for each registered subclass + * An #EShellWindow creates an #EUIAction for each registered subclass * of #EShellView. This action gets passed to the #EShellSwitcher, which * displays a button that proxies the action. When the #EShellView named * @view_name is active, the action's icon becomes the @shell_window icon. @@ -1349,21 +946,18 @@ e_shell_window_peek_shell_view (EShellWindow *shell_window, * Returns: the switcher action for the #EShellView named @view_name, * or %NULL if no such shell view exists **/ -GtkAction * +EUIAction * e_shell_window_get_shell_view_action (EShellWindow *shell_window, const gchar *view_name) { - GtkAction *action; - gchar *action_name; + gchar action_name[128]; g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL); g_return_val_if_fail (view_name != NULL, NULL); - action_name = g_strdup_printf (E_SHELL_SWITCHER_FORMAT, view_name); - action = e_shell_window_get_action (shell_window, action_name); - g_free (action_name); + g_warn_if_fail (g_snprintf (action_name, sizeof (action_name), E_SHELL_SWITCHER_FORMAT, view_name) < sizeof (action_name)); - return action; + return e_shell_window_get_ui_action (shell_window, action_name); } /** @@ -1401,96 +995,61 @@ e_shell_window_get_focus_tracker (EShellWindow *shell_window) } /** - * e_shell_window_get_ui_manager: - * @shell_window: an #EShellWindow - * - * Returns @shell_window's user interface manager, which - * manages the window's menus and toolbars via #GtkActions. - * This is the mechanism by which shell views and plugins can extend - * Evolution's menus and toolbars. - * - * Returns: the #GtkUIManager for @shell_window - **/ -GtkUIManager * -e_shell_window_get_ui_manager (EShellWindow *shell_window) -{ - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL); - - return shell_window->priv->ui_manager; -} - -/** - * e_shell_window_get_action: + * e_shell_window_get_ui_action: * @shell_window: an #EShellWindow * @action_name: the name of an action * - * Returns the #GtkAction named @action_name in @shell_window's - * user interface manager, or %NULL if no such action exists. + * Returns the #EUIAction named @action_name provided by the @shell_window + * itself, or %NULL if no such action exists. * - * Returns: the #GtkAction named @action_name + * Returns: (transfer none) (nullable): the #EUIAction named @action_name, or %NULL if not found + * + * Since: 3.56 **/ -GtkAction * -e_shell_window_get_action (EShellWindow *shell_window, - const gchar *action_name) +EUIAction * +e_shell_window_get_ui_action (EShellWindow *shell_window, + const gchar *action_name) { - GtkUIManager *ui_manager; + GHashTableIter iter; + gpointer value = NULL; g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL); g_return_val_if_fail (action_name != NULL, NULL); - ui_manager = e_shell_window_get_ui_manager (shell_window); + g_hash_table_iter_init (&iter, shell_window->priv->action_groups); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + EUIActionGroup *group = value; + EUIAction *action; - return e_lookup_action (ui_manager, action_name); + action = e_ui_action_group_get_action (group, action_name); + if (action) + return action; + } + + return NULL; } /** - * e_shell_window_get_action_group: + * e_shell_window_get_ui_action_group: * @shell_window: an #EShellWindow * @group_name: the name of an action group * - * Returns the #GtkActionGroup named @group_name in - * @shell_window's user interface manager, or %NULL if no - * such action group exists. + * Returns the #EUIActionGroup named @group_name provided by + * the @shell_window itself, or %NULL if no such action + * group exists. * - * Returns: the #GtkActionGroup named @group_name + * Returns: (transfer none) (nullable): the #EUIActionGroup named @group_name, or %NULL if not found + * + * Since: 3.56 **/ -GtkActionGroup * -e_shell_window_get_action_group (EShellWindow *shell_window, - const gchar *group_name) +EUIActionGroup * +e_shell_window_get_ui_action_group (EShellWindow *shell_window, + const gchar *group_name) { - GtkUIManager *ui_manager; - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL); g_return_val_if_fail (group_name != NULL, NULL); - ui_manager = e_shell_window_get_ui_manager (shell_window); - - return e_lookup_action_group (ui_manager, group_name); -} - -/** - * e_shell_window_get_managed_widget: - * @shell_window: an #EShellWindow - * @widget_path: path in the UI definition - * - * Looks up a widget in @shell_window's user interface manager by - * following a path. See gtk_ui_manager_get_widget() for more information - * about paths. - * - * Returns: the widget found by following the path, or %NULL if no widget - * was found - **/ -GtkWidget * -e_shell_window_get_managed_widget (EShellWindow *shell_window, - const gchar *widget_path) -{ - GtkUIManager *ui_manager; - - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), NULL); - g_return_val_if_fail (widget_path != NULL, NULL); - - ui_manager = e_shell_window_get_ui_manager (shell_window); - return gtk_ui_manager_get_widget (ui_manager, widget_path); + return g_hash_table_lookup (shell_window->priv->action_groups, group_name); } /** @@ -1528,7 +1087,7 @@ void e_shell_window_set_active_view (EShellWindow *shell_window, const gchar *view_name) { - GtkAction *action; + EUIAction *action; EShellView *shell_view; g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); @@ -1537,8 +1096,12 @@ e_shell_window_set_active_view (EShellWindow *shell_window, shell_view = e_shell_window_get_shell_view (shell_window, view_name); g_return_if_fail (shell_view != NULL); - action = e_shell_view_get_action (shell_view); - gtk_action_activate (action); + /* the shell_view might not necessarily be the view_name, if such does not exist, + thus use the name from the view itself here */ + e_shell_window_switch_to_view (shell_window, e_shell_view_get_name (shell_view)); + + action = e_shell_view_get_switcher_action (shell_view); + e_ui_action_set_active (action, TRUE); /* Renegotiate the shell window size in case a newly-created * shell view needs tweaked to accommodate a smaller screen. */ @@ -1590,287 +1153,6 @@ e_shell_window_set_safe_mode (EShellWindow *shell_window, g_object_notify (G_OBJECT (shell_window), "safe-mode"); } -/** - * e_shell_window_add_action_group: - * @shell_window: an #EShellWindow - * @group_name: the name of the new action group - * - * Creates a new #GtkActionGroup and adds it to @shell_window's - * user interface manager. This also takes care of details like setting - * the translation domain. - **/ -void -e_shell_window_add_action_group (EShellWindow *shell_window, - const gchar *group_name) -{ - e_shell_window_add_action_group_full (shell_window, group_name, NULL); -} - -void -e_shell_window_add_action_group_full (EShellWindow *shell_window, - const gchar *group_name, - const gchar *for_view_name) -{ - GtkActionGroup *action_group; - GtkUIManager *ui_manager; - const gchar *domain; - - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - g_return_if_fail (group_name != NULL); - - ui_manager = e_shell_window_get_ui_manager (shell_window); - domain = GETTEXT_PACKAGE; - - action_group = gtk_action_group_new (group_name); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - - if (for_view_name) { - GPtrArray *view_groups; - - view_groups = g_hash_table_lookup (shell_window->priv->action_groups_by_view, for_view_name); - - if (!view_groups) { - view_groups = g_ptr_array_new_with_free_func (g_object_unref); - g_hash_table_insert (shell_window->priv->action_groups_by_view, g_strdup (for_view_name), view_groups); - } - - /* Takes ownership of the action_group. */ - g_ptr_array_add (view_groups, action_group); - } else { - g_object_unref (action_group); - } -} - -static void -shell_window_menubar_info_response_cb (EAlert *alert, - gint response_id, - gpointer user_data) -{ - GWeakRef *weakref = user_data; - - g_return_if_fail (weakref != NULL); - - if (response_id == GTK_RESPONSE_APPLY) { - EShellWindow *shell_window; - - shell_window = g_weak_ref_get (weakref); - if (shell_window) { - e_shell_window_set_menubar_visible (shell_window, TRUE); - g_object_unref (shell_window); - } - } -} - -/** - * e_shell_window_get_menubar_visible: - * @shell_window: an #EShellWindow - * - * Returns %TRUE if @shell_window's menu bar is visible. - * - * Returns: %TRUE is the menu bar is visible - * - * Since: 3.24 - **/ -gboolean -e_shell_window_get_menubar_visible (EShellWindow *shell_window) -{ - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE); - - return shell_window->priv->menu_bar && - e_menu_bar_get_visible (E_MENU_BAR (shell_window->priv->menu_bar)); -} - -/** - * e_shell_window_set_menubar_visible: - * @shell_window: an #EShellWindow - * @menubar_visible: whether the menu bar should be visible - * - * Makes @shell_window's menu bar visible or invisible. - * - * Since: 3.24 - **/ -void -e_shell_window_set_menubar_visible (EShellWindow *shell_window, - gboolean menubar_visible) -{ - GSettings *settings; - - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - if (e_menu_bar_get_visible (E_MENU_BAR (shell_window->priv->menu_bar)) == menubar_visible) - return; - - e_menu_bar_set_visible (E_MENU_BAR (shell_window->priv->menu_bar), menubar_visible); - - settings = e_util_ref_settings ("org.gnome.evolution.shell"); - if (!menubar_visible && - g_settings_get_boolean (settings, e_shell_window_is_main_instance (shell_window) ? "menubar-visible" : "menubar-visible-sub")) { - /* The menu bar had been just hidden. Show a hint how to enable it. */ - EAlert *alert; - - alert = e_alert_new ("shell:menubar-hidden", NULL); - - g_signal_connect_data (alert, "response", G_CALLBACK (shell_window_menubar_info_response_cb), - e_weak_ref_new (shell_window), (GClosureNotify) e_weak_ref_free, 0); - - e_alert_sink_submit_alert (E_ALERT_SINK (shell_window), alert); - e_alert_start_timer (alert, 30); - g_object_unref (alert); - } - g_object_unref (settings); - - g_object_notify (G_OBJECT (shell_window), "menubar-visible"); -} - -/** - * e_shell_window_get_sidebar_visible: - * @shell_window: an #EShellWindow - * - * Returns %TRUE if @shell_window's side bar is visible. - * - * Returns: %TRUE is the side bar is visible - **/ -gboolean -e_shell_window_get_sidebar_visible (EShellWindow *shell_window) -{ - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE); - - return shell_window->priv->sidebar_visible; -} - -/** - * e_shell_window_set_sidebar_visible: - * @shell_window: an #EShellWindow - * @sidebar_visible: whether the side bar should be visible - * - * Makes @shell_window's side bar visible or invisible. - **/ -void -e_shell_window_set_sidebar_visible (EShellWindow *shell_window, - gboolean sidebar_visible) -{ - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - if (shell_window->priv->sidebar_visible == sidebar_visible) - return; - - shell_window->priv->sidebar_visible = sidebar_visible; - - g_object_notify (G_OBJECT (shell_window), "sidebar-visible"); -} - -/** - * e_shell_window_get_switcher_visible: - * @shell_window: an #EShellWindow - * - * Returns %TRUE if @shell_window's switcher buttons are visible. - * - * Returns: %TRUE is the switcher buttons are visible - **/ -gboolean -e_shell_window_get_switcher_visible (EShellWindow *shell_window) -{ - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE); - - return shell_window->priv->switcher_visible; -} - -/** - * e_shell_window_set_switcher_visible: - * @shell_window: an #EShellWindow - * @switcher_visible: whether the switcher buttons should be visible - * - * Makes @shell_window's switcher buttons visible or invisible. - **/ -void -e_shell_window_set_switcher_visible (EShellWindow *shell_window, - gboolean switcher_visible) -{ - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - if (shell_window->priv->switcher_visible == switcher_visible) - return; - - shell_window->priv->switcher_visible = switcher_visible; - - g_object_notify (G_OBJECT (shell_window), "switcher-visible"); -} - -/** - * e_shell_window_get_taskbar_visible: - * @shell_window: an #EShellWindow - * - * Returns %TRUE if @shell_window's task bar is visible. - * - * Returns: %TRUE is the task bar is visible - **/ -gboolean -e_shell_window_get_taskbar_visible (EShellWindow *shell_window) -{ - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE); - - return shell_window->priv->taskbar_visible; -} - -/** - * e_shell_window_set_taskbar_visible: - * @shell_window: an #EShellWindow - * @taskbar_visible: whether the task bar should be visible - * - * Makes @shell_window's task bar visible or invisible. - **/ -void -e_shell_window_set_taskbar_visible (EShellWindow *shell_window, - gboolean taskbar_visible) -{ - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - if (shell_window->priv->taskbar_visible == taskbar_visible) - return; - - shell_window->priv->taskbar_visible = taskbar_visible; - - g_object_notify (G_OBJECT (shell_window), "taskbar-visible"); -} - -/** - * e_shell_window_get_toolbar_visible: - * @shell_window: an #EShellWindow - * - * Returns %TRUE if @shell_window's tool bar is visible. - * - * Returns: %TRUE if the tool bar is visible - **/ -gboolean -e_shell_window_get_toolbar_visible (EShellWindow *shell_window) -{ - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE); - - return shell_window->priv->toolbar_visible; -} - -/** - * e_shell_window_set_toolbar_visible: - * @shell_window: an #EShellWindow - * @toolbar_visible: whether the tool bar should be visible - * - * Makes @shell_window's tool bar visible or invisible. - **/ -void -e_shell_window_set_toolbar_visible (EShellWindow *shell_window, - gboolean toolbar_visible) -{ - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); - - if (shell_window->priv->toolbar_visible == toolbar_visible) - return; - - shell_window->priv->toolbar_visible = toolbar_visible; - - g_object_notify (G_OBJECT (shell_window), "toolbar-visible"); -} - typedef struct { EShellWindow *shell_window; ESource *source; @@ -1992,14 +1274,80 @@ e_shell_window_connect_client (EShellWindow *shell_window, g_free (alert_arg_0); } +static void +shell_window_register_actions (EShellWindow *shell_window, + const gchar *backend_name, + const EUIActionEntry *entries, + guint n_entries, + EUIActionGroup *dest_action_group, + gboolean with_primary) +{ + EUIActionGroup *tmp_action_group; + EUIManager *ui_manager; + guint ii; + EUIAction *primary_action = NULL; + + g_return_if_fail (E_IS_UI_ACTION_GROUP (dest_action_group)); + + backend_name = g_intern_string (backend_name); + + ui_manager = e_ui_manager_new (); + + e_ui_manager_add_actions (ui_manager, e_ui_action_group_get_name (dest_action_group), NULL, entries, n_entries, shell_window); + + tmp_action_group = e_ui_manager_get_action_group (ui_manager, e_ui_action_group_get_name (dest_action_group)); + + for (ii = 0; ii < n_entries; ii++) { + EUIAction *action; + + action = e_ui_action_group_get_action (tmp_action_group, entries[ii].name); + + /* XXX The action label translations are retrieved from the + * message context "New", but e_ui_action_group_add_actions() + * does not support message contexts. */ + e_ui_action_set_label (action, g_dpgettext2 (GETTEXT_PACKAGE, "New", entries[ii].label)); + + g_object_set_data (G_OBJECT (action), "backend-name", (gpointer) backend_name); + + /* The first action becomes the first item in the "New" + * menu, and consequently its icon is shown in the "New" + * button when the shell backend's view is active. This + * is all sorted out in shell_view_extract_actions(). + * Note, the data value just needs to be non-zero. */ + if (with_primary && ii == 0) { + g_object_set_data (G_OBJECT (action), "primary", GINT_TO_POINTER (TRUE)); + primary_action = g_object_ref (action); + } + + /* "copy" the action to the permanent action group */ + e_ui_action_group_add (dest_action_group, action); + } + + g_clear_object (&ui_manager); + + if (primary_action) { + EShellBackend *shell_backend; + + shell_backend = e_shell_get_backend_by_name (e_shell_window_get_shell (shell_window), backend_name); + + /* set it only if not set from the settings */ + if (!e_shell_backend_get_prefer_new_item (shell_backend)) + e_shell_backend_set_prefer_new_item (shell_backend, g_action_get_name (G_ACTION (primary_action))); + + g_clear_object (&primary_action); + } + + g_signal_emit (shell_window, signals[UPDATE_NEW_MENU], 0, NULL); +} + /** * e_shell_window_register_new_item_actions: * @shell_window: an #EShellWindow * @backend_name: name of an #EShellBackend - * @entries: an array of #GtkActionEntrys + * @entries: an array of #EUIActionEntrys * @n_entries: number of elements in the array * - * Registers a list of #GtkActions to appear in + * Registers a list of #EUIActions to appear in * @shell_window's "New" menu and toolbar button. This * function should be called from an #EShell's * #GtkApplication::window-added signal handler. The #EShellBackend @@ -2007,7 +1355,7 @@ e_shell_window_connect_client (EShellWindow *shell_window, * argument (i.e. the name field from its own * #EShellBackendInfo). * - * The registered #GtkActions should be for creating individual + * The registered #EUIActions should be for creating individual * items such as an email message or a calendar appointment. The action * labels should be marked for translation with the "New" context using * the NC_() macro. @@ -2015,80 +1363,24 @@ e_shell_window_connect_client (EShellWindow *shell_window, void e_shell_window_register_new_item_actions (EShellWindow *shell_window, const gchar *backend_name, - GtkActionEntry *entries, + const EUIActionEntry *entries, guint n_entries) { - GtkActionGroup *action_group; - GtkAccelGroup *accel_group; - GtkUIManager *ui_manager; - guint ii; - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); g_return_if_fail (backend_name != NULL); g_return_if_fail (entries != NULL); - action_group = ACTION_GROUP (NEW_ITEM); - ui_manager = e_shell_window_get_ui_manager (shell_window); - accel_group = gtk_ui_manager_get_accel_group (ui_manager); - backend_name = g_intern_string (backend_name); - - /* XXX The action label translations are retrieved from the - * message context "New", but gtk_action_group_add_actions() - * does not support message contexts. So we have to fetch - * the label translations ourselves before adding them to - * the action group. - * - * gtk_action_group_set_translate_func() does not help here - * because the action tooltips do not use a message context - * (though I suppose they could). */ - for (ii = 0; ii < n_entries; ii++) - entries[ii].label = g_dpgettext2 ( - GETTEXT_PACKAGE, "New", entries[ii].label); - - gtk_action_group_add_actions ( - action_group, entries, n_entries, shell_window); - - /* Tag each action with the name of the shell backend that - * registered it. This is used to help sort actions in the - * "New" menu. */ - - for (ii = 0; ii < n_entries; ii++) { - const gchar *action_name; - GtkAction *action; - - action_name = entries[ii].name; - - action = gtk_action_group_get_action ( - action_group, action_name); - - gtk_action_set_accel_group (action, accel_group); - - g_object_set_data ( - G_OBJECT (action), - "backend-name", (gpointer) backend_name); - - /* The first action becomes the first item in the "New" - * menu, and consequently its icon is shown in the "New" - * button when the shell backend's view is active. This - * is all sorted out in shell_window_extract_actions(). - * Note, the data value just needs to be non-zero. */ - if (ii == 0) - g_object_set_data ( - G_OBJECT (action), - "primary", GINT_TO_POINTER (TRUE)); - } - - g_signal_emit (shell_window, signals[UPDATE_NEW_MENU], 0, NULL); + shell_window_register_actions (shell_window, backend_name, entries, n_entries, ACTION_GROUP (NEW_ITEM), TRUE); } /** * e_shell_window_register_new_source_actions: * @shell_window: an #EShellWindow * @backend_name: name of an #EShellBackend - * @entries: an array of #GtkActionEntrys + * @entries: an array of #EUIActionEntrys * @n_entries: number of elements in the array * - * Registers a list of #GtkActions to appear in + * Registers a list of #EUIActions to appear in * @shell_window's "New" menu and toolbar button. This * function should be called from an #EShell's * #GtkApplication::window-added signal handler. The #EShellBackend @@ -2096,7 +1388,7 @@ e_shell_window_register_new_item_actions (EShellWindow *shell_window, * argument (i.e. the name field from its own * #EShellBackendInfo). * - * The registered #GtkActions should be for creating item + * The registered #EUIActions should be for creating item * containers such as an email folder or a calendar. The action labels * should be marked for translation with the "New" context using the * NC_() macro. @@ -2104,105 +1396,12 @@ e_shell_window_register_new_item_actions (EShellWindow *shell_window, void e_shell_window_register_new_source_actions (EShellWindow *shell_window, const gchar *backend_name, - GtkActionEntry *entries, + const EUIActionEntry *entries, guint n_entries) { - GtkActionGroup *action_group; - GtkAccelGroup *accel_group; - GtkUIManager *ui_manager; - guint ii; - g_return_if_fail (E_IS_SHELL_WINDOW (shell_window)); g_return_if_fail (backend_name != NULL); g_return_if_fail (entries != NULL); - action_group = ACTION_GROUP (NEW_SOURCE); - ui_manager = e_shell_window_get_ui_manager (shell_window); - accel_group = gtk_ui_manager_get_accel_group (ui_manager); - backend_name = g_intern_string (backend_name); - - /* XXX The action label translations are retrieved from the - * message context "New", but gtk_action_group_add_actions() - * does not support message contexts. So we have to fetch - * the label translations ourselves before adding them to - * the action group. - * - * gtk_action_group_set_translate_func() does not help here - * because the action tooltips do not use a message context - * (though I suppose they could). */ - for (ii = 0; ii < n_entries; ii++) - entries[ii].label = g_dpgettext2 ( - GETTEXT_PACKAGE, "New", entries[ii].label); - - gtk_action_group_add_actions ( - action_group, entries, n_entries, shell_window); - - /* Tag each action with the name of the shell backend that - * registered it. This is used to help sort actions in the - * "New" menu. */ - - for (ii = 0; ii < n_entries; ii++) { - const gchar *action_name; - GtkAction *action; - - action_name = entries[ii].name; - - action = gtk_action_group_get_action ( - action_group, action_name); - - gtk_action_set_accel_group (action, accel_group); - - g_object_set_data ( - G_OBJECT (action), - "backend-name", (gpointer) backend_name); - } - - g_signal_emit (shell_window, signals[UPDATE_NEW_MENU], 0, NULL); -} - -/** - * e_shell_window_get_need_input: - * @shell_window: an #EShellWindow - * @event: a #GdkEventKey - * - * Returns: Whether the key @event should be processed by currently - * focused widget in the @window, instead of being processed - * bu usual means including accelerators. - * - * Since: 3.32 - **/ -gboolean -e_shell_window_get_need_input (EShellWindow *shell_window, - GdkEventKey *event) -{ - GtkWidget *focused; - - g_return_val_if_fail (E_IS_SHELL_WINDOW (shell_window), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - if ((event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)) != 0) - return FALSE; - - if (event->keyval == GDK_KEY_F1 || - event->keyval == GDK_KEY_F2 || - event->keyval == GDK_KEY_F3 || - event->keyval == GDK_KEY_F4 || - event->keyval == GDK_KEY_F5 || - event->keyval == GDK_KEY_F6 || - event->keyval == GDK_KEY_F7 || - event->keyval == GDK_KEY_F8 || - event->keyval == GDK_KEY_F9 || - event->keyval == GDK_KEY_F10 || - event->keyval == GDK_KEY_F11 || - event->keyval == GDK_KEY_F12 || - event->keyval == GDK_KEY_Tab || - event->keyval == GDK_KEY_KP_Tab) - return FALSE; - - focused = gtk_window_get_focus (GTK_WINDOW (shell_window)); - - /* The F2 is used as a shortcut to rename folder in the Mail view */ - return focused && (GTK_IS_ENTRY (focused) || - GTK_IS_EDITABLE (focused) || - (GTK_IS_TREE_VIEW (focused) && event->keyval != GDK_KEY_F2 && gtk_tree_view_get_search_column (GTK_TREE_VIEW (focused)) >= 0)); + shell_window_register_actions (shell_window, backend_name, entries, n_entries, ACTION_GROUP (NEW_SOURCE), FALSE); } diff --git a/src/shell/e-shell-window.h b/src/shell/e-shell-window.h index df0a07cc4c..5d0d02cac3 100644 --- a/src/shell/e-shell-window.h +++ b/src/shell/e-shell-window.h @@ -21,6 +21,7 @@ #ifndef E_SHELL_WINDOW_H #define E_SHELL_WINDOW_H +#include #include /* Standard GObject macros */ @@ -69,16 +70,6 @@ struct _EShellWindowClass { void (*close_alert) (EShellWindow *shell_window); void (*shell_view_created) (EShellWindow *shell_window, struct _EShellView *shell_view); - - /* These are all protected methods. Not for public use. */ - GtkWidget * (*construct_menubar) (EShellWindow *shell_window); - GtkWidget * (*construct_toolbar) (EShellWindow *shell_window); - GtkWidget * (*construct_sidebar) (EShellWindow *shell_window); - GtkWidget * (*construct_content) (EShellWindow *shell_window); - GtkWidget * (*construct_taskbar) (EShellWindow *shell_window); - struct _EShellView * - (*create_shell_view) (EShellWindow *shell_window, - const gchar *view_name); }; GType e_shell_window_get_type (void); @@ -93,24 +84,17 @@ struct _EShellView * struct _EShellView * e_shell_window_peek_shell_view (EShellWindow *shell_window, const gchar *view_name); -GtkAction * e_shell_window_get_shell_view_action +EUIAction * e_shell_window_get_shell_view_action (EShellWindow *shell_window, const gchar *view_name); GtkWidget * e_shell_window_get_alert_bar (EShellWindow *shell_window); EFocusTracker * e_shell_window_get_focus_tracker (EShellWindow *shell_window); -GtkUIManager * e_shell_window_get_ui_manager (EShellWindow *shell_window); -GtkAction * e_shell_window_get_action (EShellWindow *shell_window, +EUIAction * e_shell_window_get_ui_action (EShellWindow *shell_window, const gchar *action_name); -void e_shell_window_add_action_group_full +EUIActionGroup *e_shell_window_get_ui_action_group (EShellWindow *shell_window, - const gchar *group_name, - const gchar *for_view_name); -GtkActionGroup *e_shell_window_get_action_group (EShellWindow *shell_window, const gchar *group_name); -GtkWidget * e_shell_window_get_managed_widget - (EShellWindow *shell_window, - const gchar *widget_path); const gchar * e_shell_window_get_active_view (EShellWindow *shell_window); void e_shell_window_set_active_view (EShellWindow *shell_window, const gchar *view_name); @@ -119,31 +103,6 @@ void e_shell_window_set_safe_mode (EShellWindow *shell_window, gboolean safe_mode); void e_shell_window_add_action_group (EShellWindow *shell_window, const gchar *group_name); -gboolean e_shell_window_get_menubar_visible - (EShellWindow *shell_window); -void e_shell_window_set_menubar_visible - (EShellWindow *shell_window, - gboolean menubar_visible); -gboolean e_shell_window_get_sidebar_visible - (EShellWindow *shell_window); -void e_shell_window_set_sidebar_visible - (EShellWindow *shell_window, - gboolean sidebar_visible); -gboolean e_shell_window_get_switcher_visible - (EShellWindow *shell_window); -void e_shell_window_set_switcher_visible - (EShellWindow *shell_window, - gboolean switcher_visible); -gboolean e_shell_window_get_taskbar_visible - (EShellWindow *shell_window); -void e_shell_window_set_taskbar_visible - (EShellWindow *shell_window, - gboolean taskbar_visible); -gboolean e_shell_window_get_toolbar_visible - (EShellWindow *shell_window); -void e_shell_window_set_toolbar_visible - (EShellWindow *shell_window, - gboolean toolbar_visible); /* Helper function to open clients from shell's client cache in a dedicated thread with a callback being called in the main thread */ @@ -159,20 +118,17 @@ void e_shell_window_connect_client (EShellWindow *shell_window, gpointer user_data, GDestroyNotify destroy_user_data); -gboolean e_shell_window_get_need_input (EShellWindow *shell_window, - GdkEventKey *event); - /* These should be called from the shell backend's window_created() handler. */ void e_shell_window_register_new_item_actions (EShellWindow *shell_window, const gchar *backend_name, - GtkActionEntry *entries, + const EUIActionEntry *entries, guint n_entries); void e_shell_window_register_new_source_actions (EShellWindow *shell_window, const gchar *backend_name, - GtkActionEntry *entries, + const EUIActionEntry *entries, guint n_entries); G_END_DECLS diff --git a/src/shell/e-shell.c b/src/shell/e-shell.c index b014929aa2..359c6f39dd 100644 --- a/src/shell/e-shell.c +++ b/src/shell/e-shell.c @@ -1592,9 +1592,6 @@ categories_icon_theme_hack (void) gchar *filename; gchar *dirname; - /* XXX Allow the category icons to be referenced as named - * icons, since GtkAction does not support GdkPixbufs. */ - icon_theme = gtk_icon_theme_get_default (); dirnames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);