[evolution/kill-bonobo: 40/42] Merge branch 'master' into kill-bonobo
- From: Matthew Barnes <mbarnes src gnome org>
- To: svn-commits-list gnome org
- Subject: [evolution/kill-bonobo: 40/42] Merge branch 'master' into kill-bonobo
- Date: Thu, 28 May 2009 00:51:07 -0400 (EDT)
commit cc3a98fc1ad5bb87aa7335f3de404ee7feee1541
Merge: 10f8406... e4afd3f...
Author: Matthew Barnes <mbarnes redhat com>
Date: Wed May 27 08:37:17 2009 -0400
Merge branch 'master' into kill-bonobo
Conflicts:
a11y/widgets/ea-combo-button.c
a11y/widgets/ea-combo-button.h
addressbook/gui/component/addressbook-component.c
addressbook/gui/component/addressbook-component.h
addressbook/gui/component/addressbook-view.c
addressbook/gui/component/addressbook-view.h
addressbook/gui/component/component-factory.c
addressbook/gui/widgets/e-addressbook-view.c
addressbook/gui/widgets/eab-contact-display.c
addressbook/gui/widgets/eab-gui-util.h
addressbook/gui/widgets/eab-menu.c
addressbook/gui/widgets/eab-menu.h
addressbook/gui/widgets/eab-popup-control.c
addressbook/gui/widgets/eab-popup-control.h
addressbook/gui/widgets/eab-popup.c
addressbook/gui/widgets/eab-popup.h
calendar/gui/cal-search-bar.c
calendar/gui/calendar-commands.c
calendar/gui/calendar-component.c
calendar/gui/comp-editor-factory.c
calendar/gui/comp-editor-factory.h
calendar/gui/control-factory.c
calendar/gui/dialogs/comp-editor.c
calendar/gui/e-cal-component-memo-preview.c
calendar/gui/e-cal-component-memo-preview.h
calendar/gui/e-calendar-table.c
calendar/gui/e-memo-table.c
calendar/gui/e-memos.c
calendar/gui/e-tasks.c
calendar/gui/gnome-cal.c
calendar/gui/gnome-cal.h
calendar/gui/itip-bonobo-control.c
calendar/gui/itip-bonobo-control.h
calendar/gui/main.c
calendar/gui/memos-component.c
calendar/gui/memos-control.c
calendar/gui/memos-control.h
calendar/gui/migration.c
calendar/gui/migration.h
calendar/gui/tasks-component.c
calendar/gui/tasks-control.c
calendar/importers/main.c
composer/Makefile.am
composer/e-composer-header-table.c
composer/e-composer-header.c
composer/e-composer-header.h
composer/e-composer-name-header.c
composer/e-composer-private.c
composer/e-composer-text-header.c
composer/e-msg-composer.c
composer/e-msg-composer.h
e-util/e-corba-utils.h
e-util/e-logger.c
e-util/e-logger.h
e-util/e-util-labels.c
e-util/e-util-labels.h
em-format/em-format.c
mail/Makefile.am
mail/e-mail-shell-migrate.c
mail/em-account-editor.c
mail/em-account-editor.h
mail/em-composer-prefs.c
mail/em-composer-utils.c
mail/em-composer-utils.h
mail/em-folder-browser.c
mail/em-folder-tree-model.c
mail/em-folder-tree.c
mail/em-folder-tree.h
mail/em-folder-utils.c
mail/em-folder-utils.h
mail/em-folder-view.c
mail/em-format-html-display.c
mail/em-format-html.c
mail/em-mailer-prefs.c
mail/em-mailer-prefs.h
mail/em-message-browser.c
mail/em-message-browser.h
mail/em-network-prefs.h
mail/em-popup.c
mail/em-utils.c
mail/importers/Makefile.am
mail/mail-component-factory.c
mail/mail-component.c
mail/mail-config-factory.c
mail/mail-config-factory.h
mail/mail-config.c
mail/mail-dialogs.glade
mail/mail-types.h
plugins/calendar-weather/calendar-weather.c
plugins/mail-account-disable/mail-account-disable.c
plugins/select-one-source/select-one-source.c
po/POTFILES.in
shell/e-component-registry.c
shell/e-component-registry.h
shell/e-component-view.c
shell/e-component-view.h
shell/e-corba-config-page.c
shell/e-corba-config-page.h
shell/e-shell-constants.h
shell/e-shell-settings-dialog.c
shell/e-shell-settings-dialog.h
shell/e-shell-window-commands.c
shell/e-shell-window.c
shell/e-shell.h
shell/e-sidebar.c
shell/e-sidebar.h
shell/e-user-creatable-items-handler.c
shell/e-user-creatable-items-handler.h
shell/es-menu.c
shell/es-menu.h
shell/evolution-component.h
shell/evolution-config-control.c
shell/evolution-config-control.h
shell/evolution-listener.c
shell/evolution-listener.h
shell/evolution-shell-component-utils.c
shell/evolution-shell-component-utils.h
shell/importer/evolution-importer-client.c
shell/importer/evolution-importer-client.h
shell/importer/evolution-importer-listener.c
shell/importer/evolution-importer-listener.h
shell/importer/evolution-importer.c
shell/importer/evolution-importer.h
shell/importer/evolution-intelligent-importer.c
shell/importer/evolution-intelligent-importer.h
shell/importer/intelligent.c
shell/main.c
shell/test/evolution-test-component.c
shell/test/evolution-test-component.h
widgets/menus/gal-view-instance.c
widgets/menus/gal-view-menus.c
widgets/menus/gal-view-menus.h
widgets/misc/Makefile.am
widgets/misc/e-activity-handler.c
widgets/misc/e-activity-handler.h
widgets/misc/e-charset-picker.c
widgets/misc/e-combo-button.c
widgets/misc/e-combo-button.h
widgets/misc/e-config-page.h
widgets/misc/e-dropdown-button.c
widgets/misc/e-dropdown-button.h
widgets/misc/e-filter-bar.c
widgets/misc/e-info-label.c
widgets/misc/e-info-label.h
widgets/misc/e-multi-config-dialog.c
widgets/misc/e-multi-config-dialog.h
widgets/misc/e-search-bar.c
widgets/misc/e-search-bar.h
widgets/misc/e-task-bar.c
widgets/misc/e-task-bar.h
widgets/misc/e-task-widget.c
widgets/misc/e-task-widget.h
widgets/misc/test-dropdown-button.c
widgets/misc/test-error.c
widgets/misc/test-info-label.c
widgets/table/e-table-example-1.c
NEWS | 54 +
a11y/ea-cell-table.c | 2 +-
a11y/ea-cell-table.h | 2 +-
a11y/ea-factory.h | 2 +-
a11y/gal-a11y-factory.h | 2 +-
a11y/gal-a11y-util.c | 2 +-
a11y/gal-a11y-util.h | 2 +-
acinclude.m4 | 62 +
addressbook/conduit/address-conduit.c | 12 +-
addressbook/gui/component/addressbook-config.c | 46 +-
addressbook/gui/component/addressbook-config.h | 2 +-
addressbook/gui/component/autocompletion-config.c | 2 +-
addressbook/gui/component/autocompletion-config.h | 2 +-
addressbook/gui/component/e-book-shell-backend.c | 2 +-
addressbook/gui/component/e-book-shell-backend.h | 2 +-
addressbook/gui/component/e-book-shell-content.c | 2 +-
addressbook/gui/component/e-book-shell-content.h | 2 +-
addressbook/gui/component/e-book-shell-migrate.c | 2 +-
addressbook/gui/component/e-book-shell-migrate.h | 2 +-
addressbook/gui/component/e-book-shell-sidebar.c | 2 +-
addressbook/gui/component/e-book-shell-sidebar.h | 2 +-
.../gui/component/e-book-shell-view-actions.c | 2 +-
.../gui/component/e-book-shell-view-actions.h | 2 +-
.../gui/component/e-book-shell-view-private.c | 2 +-
.../gui/component/e-book-shell-view-private.h | 2 +-
addressbook/gui/component/e-book-shell-view.c | 2 +-
addressbook/gui/component/e-book-shell-view.h | 2 +-
addressbook/gui/component/eab-composer-util.c | 2 +-
addressbook/gui/component/eab-composer-util.h | 2 +-
.../gui/component/evolution-module-addressbook.c | 2 +-
.../gui/contact-editor/e-contact-editor-fullname.c | 11 +-
.../gui/contact-editor/e-contact-editor-fullname.h | 2 +-
addressbook/gui/contact-editor/e-contact-editor.c | 14 +-
addressbook/gui/contact-editor/e-contact-editor.h | 2 +-
.../gui/contact-editor/e-contact-quick-add.c | 6 +-
.../gui/contact-editor/e-contact-quick-add.h | 2 +-
addressbook/gui/contact-editor/eab-editor.c | 2 +-
addressbook/gui/contact-editor/eab-editor.h | 2 +-
addressbook/gui/contact-editor/test-editor.c | 2 +-
.../contact-list-editor/e-contact-list-editor.c | 18 +-
.../contact-list-editor/e-contact-list-editor.h | 2 +-
.../gui/contact-list-editor/e-contact-list-model.c | 2 +-
.../gui/contact-list-editor/e-contact-list-model.h | 2 +-
addressbook/gui/merging/eab-contact-compare.c | 4 +-
addressbook/gui/merging/eab-contact-compare.h | 2 +-
addressbook/gui/merging/eab-contact-merging.c | 2 +-
addressbook/gui/merging/eab-contact-merging.h | 2 +-
addressbook/gui/widgets/a11y/ea-addressbook-view.c | 2 +-
addressbook/gui/widgets/a11y/ea-addressbook-view.h | 2 +-
addressbook/gui/widgets/a11y/ea-addressbook.c | 2 +-
addressbook/gui/widgets/a11y/ea-addressbook.h | 2 +-
addressbook/gui/widgets/a11y/ea-minicard-view.c | 2 +-
addressbook/gui/widgets/a11y/ea-minicard-view.h | 2 +-
addressbook/gui/widgets/a11y/ea-minicard.c | 2 +-
addressbook/gui/widgets/a11y/ea-minicard.h | 2 +-
addressbook/gui/widgets/e-addressbook-model.c | 2 +-
addressbook/gui/widgets/e-addressbook-model.h | 2 +-
.../gui/widgets/e-addressbook-reflow-adapter.c | 2 +-
.../gui/widgets/e-addressbook-reflow-adapter.h | 2 +-
addressbook/gui/widgets/e-addressbook-selector.c | 4 +-
.../gui/widgets/e-addressbook-table-adapter.c | 2 +-
.../gui/widgets/e-addressbook-table-adapter.h | 2 +-
addressbook/gui/widgets/e-addressbook-view.c | 6 +-
addressbook/gui/widgets/e-addressbook-view.h | 2 +-
addressbook/gui/widgets/e-minicard-label.c | 2 +-
addressbook/gui/widgets/e-minicard-label.h | 2 +-
addressbook/gui/widgets/e-minicard-view-widget.c | 2 +-
addressbook/gui/widgets/e-minicard-view-widget.h | 2 +-
addressbook/gui/widgets/e-minicard-view.c | 6 +-
addressbook/gui/widgets/e-minicard-view.h | 2 +-
addressbook/gui/widgets/e-minicard.c | 10 +-
addressbook/gui/widgets/e-minicard.h | 2 +-
addressbook/gui/widgets/eab-config.c | 2 +-
addressbook/gui/widgets/eab-config.h | 2 +-
addressbook/gui/widgets/eab-contact-display.c | 13 +-
addressbook/gui/widgets/eab-contact-display.h | 2 +-
addressbook/gui/widgets/eab-gui-util.c | 4 +-
addressbook/gui/widgets/eab-gui-util.h | 2 +-
.../gui/widgets/gal-view-factory-minicard.c | 2 +-
.../gui/widgets/gal-view-factory-minicard.h | 2 +-
addressbook/gui/widgets/gal-view-minicard.c | 2 +-
addressbook/gui/widgets/gal-view-minicard.h | 2 +-
.../importers/evolution-addressbook-importers.h | 2 +-
addressbook/importers/evolution-csv-importer.c | 6 +-
addressbook/importers/evolution-ldif-importer.c | 6 +-
addressbook/importers/evolution-vcard-importer.c | 2 +-
addressbook/printing/Makefile.am | 2 -
addressbook/printing/e-contact-print-types.h | 2 +-
addressbook/printing/e-contact-print.c | 2 +-
addressbook/printing/e-contact-print.h | 2 +-
addressbook/printing/test-print.c | 10 +-
.../evolution-addressbook-export-list-cards.c | 5 +-
.../evolution-addressbook-export-list-folders.c | 2 +-
addressbook/tools/evolution-addressbook-export.c | 2 +-
addressbook/tools/evolution-addressbook-export.h | 2 +-
addressbook/util/Makefile.am | 1 -
addressbook/util/addressbook.c | 4 +-
addressbook/util/addressbook.h | 2 +-
addressbook/util/eab-book-util.c | 2 +-
addressbook/util/eab-book-util.h | 2 +-
art/broken-image-16.xpm | 2 +-
art/broken-image-24.xpm | 2 +-
art/empty.xpm | 2 +-
art/jump.xpm | 4 +-
calendar/common/authentication.c | 4 +-
calendar/common/authentication.h | 2 +-
calendar/conduits/calendar/calendar-conduit.c | 4 +-
.../conduits/common/libecalendar-common-conduit.c | 2 +-
.../conduits/common/libecalendar-common-conduit.h | 2 +-
calendar/conduits/memo/memo-conduit.c | 2 +-
calendar/conduits/todo/todo-conduit.c | 2 +-
calendar/gui/a11y/ea-cal-view-event.c | 9 +-
calendar/gui/a11y/ea-cal-view-event.h | 2 +-
calendar/gui/a11y/ea-cal-view.c | 2 +-
calendar/gui/a11y/ea-cal-view.h | 2 +-
calendar/gui/a11y/ea-calendar-helpers.c | 2 +-
calendar/gui/a11y/ea-calendar-helpers.h | 2 +-
calendar/gui/a11y/ea-calendar.c | 2 +-
calendar/gui/a11y/ea-calendar.h | 2 +-
calendar/gui/a11y/ea-day-view-cell.c | 2 +-
calendar/gui/a11y/ea-day-view-cell.h | 2 +-
calendar/gui/a11y/ea-day-view-main-item.c | 4 +-
calendar/gui/a11y/ea-day-view-main-item.h | 2 +-
calendar/gui/a11y/ea-day-view.c | 2 +-
calendar/gui/a11y/ea-day-view.h | 2 +-
calendar/gui/a11y/ea-gnome-calendar.c | 2 +-
calendar/gui/a11y/ea-gnome-calendar.h | 2 +-
calendar/gui/a11y/ea-jump-button.c | 4 +-
calendar/gui/a11y/ea-jump-button.h | 2 +-
calendar/gui/a11y/ea-week-view-cell.c | 2 +-
calendar/gui/a11y/ea-week-view-cell.h | 2 +-
calendar/gui/a11y/ea-week-view-main-item.c | 2 +-
calendar/gui/a11y/ea-week-view-main-item.h | 2 +-
calendar/gui/a11y/ea-week-view.c | 2 +-
calendar/gui/a11y/ea-week-view.h | 2 +-
calendar/gui/alarm-notify/alarm-notify-dialog.c | 2 +-
calendar/gui/alarm-notify/alarm-notify-dialog.h | 2 +-
calendar/gui/alarm-notify/alarm-notify.c | 4 +-
calendar/gui/alarm-notify/alarm-notify.h | 2 +-
calendar/gui/alarm-notify/alarm-queue.c | 7 +-
calendar/gui/alarm-notify/alarm-queue.h | 2 +-
calendar/gui/alarm-notify/alarm.c | 2 +-
calendar/gui/alarm-notify/alarm.h | 2 +-
calendar/gui/alarm-notify/config-data.c | 2 +-
calendar/gui/alarm-notify/config-data.h | 2 +-
calendar/gui/alarm-notify/notify-main.c | 2 +-
calendar/gui/alarm-notify/util.c | 2 +-
calendar/gui/alarm-notify/util.h | 2 +-
calendar/gui/cal-search-bar.c | 4 +-
calendar/gui/cal-search-bar.h | 2 +-
calendar/gui/calendar-commands.c | 4 +-
calendar/gui/calendar-commands.h | 2 +-
calendar/gui/calendar-component.c | 13 +-
calendar/gui/calendar-component.h | 2 +-
calendar/gui/calendar-config-keys.h | 2 +-
calendar/gui/calendar-config.c | 2 +-
calendar/gui/calendar-config.h | 2 +-
calendar/gui/calendar-view-factory.c | 2 +-
calendar/gui/calendar-view-factory.h | 2 +-
calendar/gui/calendar-view.c | 2 +-
calendar/gui/calendar-view.h | 2 +-
calendar/gui/comp-util.c | 8 +-
calendar/gui/comp-util.h | 2 +-
calendar/gui/dialogs/alarm-dialog.c | 2 +-
calendar/gui/dialogs/alarm-dialog.h | 2 +-
calendar/gui/dialogs/alarm-list-dialog.c | 2 +-
calendar/gui/dialogs/alarm-list-dialog.h | 2 +-
calendar/gui/dialogs/cal-attachment-select-file.c | 2 +-
calendar/gui/dialogs/cal-attachment-select-file.h | 2 +-
calendar/gui/dialogs/cal-prefs-dialog.c | 24 +-
calendar/gui/dialogs/cal-prefs-dialog.h | 2 +-
calendar/gui/dialogs/calendar-setup.c | 46 +-
calendar/gui/dialogs/calendar-setup.h | 2 +-
calendar/gui/dialogs/cancel-comp.c | 2 +-
calendar/gui/dialogs/cancel-comp.h | 2 +-
calendar/gui/dialogs/changed-comp.c | 2 +-
calendar/gui/dialogs/changed-comp.h | 2 +-
calendar/gui/dialogs/comp-editor-page.c | 2 +-
calendar/gui/dialogs/comp-editor-page.h | 2 +-
calendar/gui/dialogs/comp-editor-util.c | 10 +-
calendar/gui/dialogs/comp-editor-util.h | 2 +-
calendar/gui/dialogs/comp-editor.c | 8 +-
calendar/gui/dialogs/comp-editor.h | 2 +-
calendar/gui/dialogs/copy-source-dialog.c | 2 +-
calendar/gui/dialogs/copy-source-dialog.h | 2 +-
calendar/gui/dialogs/delete-comp.c | 2 +-
calendar/gui/dialogs/delete-comp.h | 2 +-
calendar/gui/dialogs/delete-error.c | 2 +-
calendar/gui/dialogs/delete-error.h | 2 +-
calendar/gui/dialogs/e-delegate-dialog.c | 2 +-
calendar/gui/dialogs/e-delegate-dialog.h | 2 +-
calendar/gui/dialogs/e-send-options-utils.c | 4 +-
calendar/gui/dialogs/e-send-options-utils.h | 4 +-
calendar/gui/dialogs/event-editor.c | 2 +-
calendar/gui/dialogs/event-editor.h | 4 +-
calendar/gui/dialogs/event-page.c | 22 +-
calendar/gui/dialogs/event-page.h | 2 +-
calendar/gui/dialogs/memo-editor.c | 2 +-
calendar/gui/dialogs/memo-editor.h | 2 +-
calendar/gui/dialogs/memo-page.c | 2 +-
calendar/gui/dialogs/memo-page.h | 2 +-
calendar/gui/dialogs/recur-comp.c | 2 +-
calendar/gui/dialogs/recur-comp.h | 2 +-
calendar/gui/dialogs/recurrence-page.c | 2 +-
calendar/gui/dialogs/recurrence-page.h | 2 +-
calendar/gui/dialogs/save-comp.c | 2 +-
calendar/gui/dialogs/save-comp.h | 4 +-
calendar/gui/dialogs/schedule-page.c | 2 +-
calendar/gui/dialogs/schedule-page.h | 2 +-
calendar/gui/dialogs/select-source-dialog.c | 2 +-
calendar/gui/dialogs/select-source-dialog.h | 2 +-
calendar/gui/dialogs/send-comp.c | 2 +-
calendar/gui/dialogs/send-comp.h | 2 +-
calendar/gui/dialogs/task-details-page.c | 2 +-
calendar/gui/dialogs/task-details-page.h | 2 +-
calendar/gui/dialogs/task-editor.c | 2 +-
calendar/gui/dialogs/task-editor.h | 2 +-
calendar/gui/dialogs/task-page.c | 8 +-
calendar/gui/dialogs/task-page.h | 2 +-
calendar/gui/e-alarm-list.c | 2 +-
calendar/gui/e-alarm-list.h | 4 +-
calendar/gui/e-attachment-handler-calendar.c | 2 +-
calendar/gui/e-attachment-handler-calendar.h | 2 +-
calendar/gui/e-cal-component-preview.c | 2 +-
calendar/gui/e-cal-component-preview.h | 2 +-
calendar/gui/e-cal-config.c | 2 +-
calendar/gui/e-cal-config.h | 2 +-
calendar/gui/e-cal-event.c | 2 +-
calendar/gui/e-cal-event.h | 2 +-
calendar/gui/e-cal-list-view-config.c | 2 +-
calendar/gui/e-cal-list-view-config.h | 2 +-
calendar/gui/e-cal-list-view.c | 2 +-
calendar/gui/e-cal-list-view.h | 2 +-
calendar/gui/e-cal-menu.c | 2 +-
calendar/gui/e-cal-menu.h | 2 +-
calendar/gui/e-cal-model-calendar.c | 8 +-
calendar/gui/e-cal-model-calendar.h | 2 +-
calendar/gui/e-cal-model-memos.c | 6 +-
calendar/gui/e-cal-model-memos.h | 2 +-
calendar/gui/e-cal-model-tasks.c | 36 +-
calendar/gui/e-cal-model-tasks.h | 2 +-
calendar/gui/e-cal-model.c | 46 +-
calendar/gui/e-cal-model.h | 4 +-
calendar/gui/e-cal-popup.c | 2 +-
calendar/gui/e-cal-popup.h | 2 +-
calendar/gui/e-calendar-table-config.c | 2 +-
calendar/gui/e-calendar-table-config.h | 2 +-
calendar/gui/e-calendar-table.c | 2 +-
calendar/gui/e-calendar-table.h | 2 +-
calendar/gui/e-calendar-view.c | 78 +-
calendar/gui/e-calendar-view.h | 2 +-
calendar/gui/e-cell-date-edit-config.c | 2 +-
calendar/gui/e-cell-date-edit-config.h | 2 +-
calendar/gui/e-cell-date-edit-text.c | 2 +-
calendar/gui/e-cell-date-edit-text.h | 2 +-
calendar/gui/e-comp-editor-registry.c | 2 +-
calendar/gui/e-comp-editor-registry.h | 2 +-
calendar/gui/e-date-edit-config.c | 2 +-
calendar/gui/e-date-edit-config.h | 2 +-
calendar/gui/e-date-time-list.c | 2 +-
calendar/gui/e-date-time-list.h | 2 +-
calendar/gui/e-day-view-config.c | 2 +-
calendar/gui/e-day-view-config.h | 2 +-
calendar/gui/e-day-view-layout.c | 2 +-
calendar/gui/e-day-view-layout.h | 2 +-
calendar/gui/e-day-view-main-item.c | 9 +-
calendar/gui/e-day-view-main-item.h | 2 +-
calendar/gui/e-day-view-time-item.c | 7 +-
calendar/gui/e-day-view-time-item.h | 2 +-
calendar/gui/e-day-view-top-item.c | 6 +-
calendar/gui/e-day-view-top-item.h | 2 +-
calendar/gui/e-day-view.c | 40 +-
calendar/gui/e-day-view.h | 4 +-
calendar/gui/e-itip-control.c | 6 +-
calendar/gui/e-itip-control.h | 2 +-
calendar/gui/e-meeting-attendee.c | 5 +-
calendar/gui/e-meeting-attendee.h | 2 +-
calendar/gui/e-meeting-list-view.c | 13 +-
calendar/gui/e-meeting-list-view.h | 2 +-
calendar/gui/e-meeting-store.c | 4 +-
calendar/gui/e-meeting-store.h | 2 +-
calendar/gui/e-meeting-time-sel-item.c | 2 +-
calendar/gui/e-meeting-time-sel-item.h | 2 +-
calendar/gui/e-meeting-time-sel.c | 2 +-
calendar/gui/e-meeting-time-sel.h | 2 +-
calendar/gui/e-meeting-types.h | 2 +-
calendar/gui/e-meeting-utils.c | 2 +-
calendar/gui/e-meeting-utils.h | 2 +-
calendar/gui/e-memo-list-selector.c | 4 +-
calendar/gui/e-memo-table-config.c | 2 +-
calendar/gui/e-memo-table-config.h | 2 +-
calendar/gui/e-memo-table.c | 6 +-
calendar/gui/e-memo-table.h | 2 +-
calendar/gui/e-memos.c | 2 +-
calendar/gui/e-memos.h | 2 +-
calendar/gui/e-mini-calendar-config.c | 2 +-
calendar/gui/e-mini-calendar-config.h | 2 +-
calendar/gui/e-select-names-editable.c | 8 +-
calendar/gui/e-select-names-editable.h | 2 +-
calendar/gui/e-select-names-renderer.c | 4 +-
calendar/gui/e-select-names-renderer.h | 2 +-
calendar/gui/e-task-list-selector.c | 4 +-
calendar/gui/e-tasks.c | 2 +-
calendar/gui/e-tasks.h | 2 +-
calendar/gui/e-timezone-entry.c | 2 +-
calendar/gui/e-timezone-entry.h | 2 +-
calendar/gui/e-week-view-config.c | 2 +-
calendar/gui/e-week-view-config.h | 2 +-
calendar/gui/e-week-view-event-item.c | 5 +-
calendar/gui/e-week-view-event-item.h | 2 +-
calendar/gui/e-week-view-layout.c | 2 +-
calendar/gui/e-week-view-layout.h | 2 +-
calendar/gui/e-week-view-main-item.c | 2 +-
calendar/gui/e-week-view-main-item.h | 2 +-
calendar/gui/e-week-view-titles-item.c | 2 +-
calendar/gui/e-week-view-titles-item.h | 2 +-
calendar/gui/e-week-view.c | 34 +-
calendar/gui/e-week-view.h | 4 +-
calendar/gui/gnome-cal.c | 40 +-
calendar/gui/gnome-cal.h | 4 +-
calendar/gui/goto.c | 2 +-
calendar/gui/goto.h | 2 +-
calendar/gui/itip-utils.c | 8 +-
calendar/gui/itip-utils.h | 2 +-
calendar/gui/memos-component.c | 2 +-
calendar/gui/memos-component.h | 2 +-
calendar/gui/misc.c | 2 +-
calendar/gui/misc.h | 2 +-
calendar/gui/print.c | 29 +-
calendar/gui/print.h | 2 +-
calendar/gui/tag-calendar.c | 2 +-
calendar/gui/tag-calendar.h | 2 +-
calendar/gui/tasks-component.c | 26 +-
calendar/gui/tasks-component.h | 2 +-
calendar/gui/tasks-control.c | 6 +-
calendar/gui/tasks-control.h | 2 +-
calendar/gui/weekday-picker.c | 4 +-
calendar/gui/weekday-picker.h | 2 +-
calendar/importers/evolution-calendar-importer.h | 2 +-
calendar/importers/icalendar-importer.c | 12 +-
calendar/module/e-cal-shell-backend.c | 4 +-
calendar/module/e-cal-shell-backend.h | 2 +-
calendar/module/e-cal-shell-content.c | 2 +-
calendar/module/e-cal-shell-content.h | 2 +-
calendar/module/e-cal-shell-migrate.c | 2 +-
calendar/module/e-cal-shell-migrate.h | 2 +-
calendar/module/e-cal-shell-settings.c | 2 +-
calendar/module/e-cal-shell-settings.h | 2 +-
calendar/module/e-cal-shell-sidebar.c | 2 +-
calendar/module/e-cal-shell-sidebar.h | 2 +-
calendar/module/e-cal-shell-view-actions.c | 4 +-
calendar/module/e-cal-shell-view-actions.h | 2 +-
calendar/module/e-cal-shell-view-memopad.c | 2 +-
calendar/module/e-cal-shell-view-private.c | 4 +-
calendar/module/e-cal-shell-view-private.h | 2 +-
calendar/module/e-cal-shell-view-taskpad.c | 2 +-
calendar/module/e-cal-shell-view.c | 2 +-
calendar/module/e-cal-shell-view.h | 2 +-
calendar/module/e-memo-shell-backend.c | 2 +-
calendar/module/e-memo-shell-backend.h | 2 +-
calendar/module/e-memo-shell-content.c | 6 +-
calendar/module/e-memo-shell-content.h | 2 +-
calendar/module/e-memo-shell-migrate.c | 2 +-
calendar/module/e-memo-shell-migrate.h | 2 +-
calendar/module/e-memo-shell-sidebar.c | 2 +-
calendar/module/e-memo-shell-sidebar.h | 2 +-
calendar/module/e-memo-shell-view-actions.c | 2 +-
calendar/module/e-memo-shell-view-actions.h | 2 +-
calendar/module/e-memo-shell-view-private.c | 2 +-
calendar/module/e-memo-shell-view-private.h | 2 +-
calendar/module/e-memo-shell-view.c | 2 +-
calendar/module/e-memo-shell-view.h | 2 +-
calendar/module/e-task-shell-backend.c | 2 +-
calendar/module/e-task-shell-backend.h | 2 +-
calendar/module/e-task-shell-content.c | 6 +-
calendar/module/e-task-shell-content.h | 4 +-
calendar/module/e-task-shell-migrate.c | 2 +-
calendar/module/e-task-shell-migrate.h | 2 +-
calendar/module/e-task-shell-sidebar.c | 4 +-
calendar/module/e-task-shell-sidebar.h | 2 +-
calendar/module/e-task-shell-view-actions.c | 4 +-
calendar/module/e-task-shell-view-actions.h | 2 +-
calendar/module/e-task-shell-view-private.c | 2 +-
calendar/module/e-task-shell-view-private.h | 2 +-
calendar/module/e-task-shell-view.c | 2 +-
calendar/module/e-task-shell-view.h | 2 +-
calendar/module/evolution-module-calendar.c | 2 +-
calendar/zones.h | 2 +-
composer/Makefile.am | 1 -
composer/e-composer-actions.c | 2 +-
composer/e-composer-actions.h | 2 +-
composer/e-composer-autosave.c | 2 +-
composer/e-composer-autosave.h | 2 +-
composer/e-composer-common.h | 2 +-
composer/e-composer-from-header.c | 2 +-
composer/e-composer-from-header.h | 2 +-
composer/e-composer-header-table.c | 17 +-
composer/e-composer-header-table.h | 2 +-
composer/e-composer-header.c | 8 +-
composer/e-composer-header.h | 4 +-
composer/e-composer-name-header.c | 18 +-
composer/e-composer-name-header.h | 2 +-
composer/e-composer-post-header.c | 2 +-
composer/e-composer-post-header.h | 2 +-
composer/e-composer-private.c | 9 +-
composer/e-composer-private.h | 2 +-
composer/e-composer-text-header.c | 4 +-
composer/e-composer-text-header.h | 2 +-
composer/e-msg-composer.c | 10 +-
composer/e-msg-composer.h | 2 +-
configure.ac | 44 +-
devel-docs/camel/Makefile.am | 2 +-
e-util/e-account-utils.c | 2 +-
e-util/e-account-utils.h | 2 +-
e-util/e-bconf-map.c | 2 +-
e-util/e-bconf-map.h | 16 +-
e-util/e-binding.c | 2 +-
e-util/e-binding.h | 2 +-
e-util/e-bit-array.c | 2 +-
e-util/e-bit-array.h | 5 +-
e-util/e-categories-config.c | 2 +-
e-util/e-categories-config.h | 2 +-
e-util/e-config-listener.c | 2 +-
e-util/e-config-listener.h | 2 +-
e-util/e-config.c | 2 +-
e-util/e-config.h | 2 +-
e-util/e-cursor.c | 2 +-
e-util/e-cursor.h | 2 +-
e-util/e-dialog-utils.c | 2 +-
e-util/e-dialog-utils.h | 2 +-
e-util/e-dialog-widgets.c | 2 +-
e-util/e-dialog-widgets.h | 2 +-
e-util/e-error.c | 62 +-
e-util/e-error.h | 2 +-
e-util/e-event.c | 2 +-
e-util/e-event.h | 2 +-
e-util/e-folder-map.c | 4 +-
e-util/e-folder-map.h | 5 +-
e-util/e-fsutils.c | 2 +-
e-util/e-fsutils.h | 2 +-
e-util/e-html-utils.c | 4 +-
e-util/e-html-utils.h | 2 +-
e-util/e-icon-factory.c | 2 +-
e-util/e-icon-factory.h | 2 +-
e-util/e-import.c | 2 +-
e-util/e-import.h | 2 +-
e-util/e-logger.c | 6 +-
e-util/e-logger.h | 2 +-
e-util/e-marshal.list | 1 +
e-util/e-menu.c | 2 +-
e-util/e-menu.h | 2 +-
e-util/e-mktemp.c | 2 +-
e-util/e-mktemp.h | 2 +-
e-util/e-module.c | 2 +-
e-util/e-module.h | 2 +-
e-util/e-non-intrusive-error-dialog.c | 2 +-
e-util/e-non-intrusive-error-dialog.h | 8 +-
e-util/e-pilot-map.c | 2 +-
e-util/e-pilot-map.h | 2 +-
e-util/e-pilot-util.c | 2 +-
e-util/e-pilot-util.h | 2 +-
e-util/e-plugin-ui.c | 4 +-
e-util/e-plugin-ui.h | 2 +-
e-util/e-plugin.c | 4 +-
e-util/e-plugin.h | 6 +-
e-util/e-popup.c | 2 +-
e-util/e-popup.h | 2 +-
e-util/e-print.c | 2 +-
e-util/e-print.h | 2 +-
e-util/e-profile-event.c | 2 +-
e-util/e-profile-event.h | 2 +-
e-util/e-request.c | 2 +-
e-util/e-request.h | 2 +-
e-util/e-signature-list.c | 2 +-
e-util/e-signature-list.h | 2 +-
e-util/e-signature-utils.c | 2 +-
e-util/e-signature-utils.h | 2 +-
e-util/e-signature.c | 2 +-
e-util/e-signature.h | 2 +-
e-util/e-sorter-array.c | 2 +-
e-util/e-sorter-array.h | 2 +-
e-util/e-sorter.c | 2 +-
e-util/e-sorter.h | 2 +-
e-util/e-text-event-processor-emacs-like.c | 4 +-
e-util/e-text-event-processor-emacs-like.h | 2 +-
e-util/e-text-event-processor-types.h | 8 +-
e-util/e-text-event-processor.c | 5 +-
e-util/e-text-event-processor.h | 2 +-
e-util/e-unicode.c | 6 +-
e-util/e-unicode.h | 3 +-
e-util/e-util-private.h | 2 +-
e-util/e-util.c | 8 +-
e-util/e-util.h | 12 +-
e-util/e-win32-reloc.c | 2 +-
e-util/e-xml-utils.c | 2 +-
e-util/e-xml-utils.h | 4 +-
e-util/gconf-bridge.c | 43 +-
e-util/gconf-bridge.h | 6 +-
em-format/em-format-quote.c | 50 +-
em-format/em-format-quote.h | 2 +-
em-format/em-format.c | 39 +-
em-format/em-format.h | 4 +-
em-format/em-stripsig-filter.c | 2 +-
em-format/em-stripsig-filter.h | 2 +-
filter/filter-code.c | 2 +-
filter/filter-code.h | 2 +-
filter/filter-colour.c | 2 +-
filter/filter-colour.h | 2 +-
filter/filter-datespec.c | 2 +-
filter/filter-datespec.h | 2 +-
filter/filter-element.c | 2 +-
filter/filter-element.h | 2 +-
filter/filter-file.c | 4 +-
filter/filter-file.h | 2 +-
filter/filter-input.c | 4 +-
filter/filter-input.h | 2 +-
filter/filter-int.c | 2 +-
filter/filter-int.h | 2 +-
filter/filter-option.c | 2 +-
filter/filter-option.h | 2 +-
filter/filter-part.c | 2 +-
filter/filter-part.h | 2 +-
filter/filter-rule.c | 6 +-
filter/filter-rule.h | 2 +-
filter/rule-context.c | 2 +-
filter/rule-context.h | 2 +-
filter/rule-editor.c | 4 +-
filter/rule-editor.h | 2 +-
help/el/el.po | 5479 +++++++---
help/el/figures/account_editor_a.png | Bin 0 -> 74930 bytes
help/el/figures/attach_reminder_a.png | Bin 0 -> 32748 bytes
help/el/figures/categories_a.png | Bin 0 -> 67805 bytes
help/el/figures/collap_head_a.png | Bin 0 -> 18934 bytes
help/el/figures/contacts_mainwindow_a.png | Bin 0 -> 80979 bytes
help/el/figures/evo_Wcal_prop_a.png | Bin 0 -> 47371 bytes
help/el/figures/evo_account_editor_a.png | Bin 0 -> 65027 bytes
help/el/figures/evo_adv_search_a.png | Bin 0 -> 45662 bytes
help/el/figures/evo_allday_a.png | Bin 0 -> 145643 bytes
help/el/figures/evo_attachreminder_plugin.png | Bin 0 -> 85023 bytes
help/el/figures/evo_backup.png | Bin 0 -> 30348 bytes
help/el/figures/evo_backup_prgsbar.png | Bin 0 -> 49216 bytes
help/el/figures/evo_backup_warning.png | Bin 0 -> 42326 bytes
help/el/figures/evo_cal_a.png | Bin 0 -> 126981 bytes
help/el/figures/evo_cal_advsearch.png | Bin 0 -> 35989 bytes
help/el/figures/evo_cal_callout_a.png | Bin 0 -> 106234 bytes
help/el/figures/evo_cal_prop_a.png | Bin 0 -> 25784 bytes
help/el/figures/evo_calender_appointmnt.png | Bin 0 -> 56722 bytes
help/el/figures/evo_contacteditor_a.png | Bin 0 -> 81465 bytes
help/el/figures/evo_custom_header.png | Bin 0 -> 19553 bytes
help/el/figures/evo_edit_rule_a.png | Bin 0 -> 47996 bytes
help/el/figures/evo_edit_search.png | Bin 0 -> 33644 bytes
help/el/figures/evo_exchng_mapi.png | Bin 0 -> 78289 bytes
help/el/figures/evo_flag_follow_up_a.png | Bin 0 -> 40660 bytes
help/el/figures/evo_gwreceive_a.png | Bin 0 -> 60909 bytes
help/el/figures/evo_identity_a.png | Bin 0 -> 60016 bytes
help/el/figures/evo_imapreceive_a.png | Bin 0 -> 87180 bytes
help/el/figures/evo_import.png | Bin 0 -> 43519 bytes
help/el/figures/evo_import_asst_a.png | Bin 0 -> 48093 bytes
help/el/figures/evo_mail_a.png | Bin 0 -> 169456 bytes
help/el/figures/evo_mail_callout_a.png | Bin 0 -> 182740 bytes
help/el/figures/evo_maildirreceive_a.png | Bin 0 -> 36563 bytes
help/el/figures/evo_mboxreceive_a.png | Bin 0 -> 42352 bytes
help/el/figures/evo_memo_a.png | Bin 0 -> 40120 bytes
help/el/figures/evo_mereceive_a.png | Bin 0 -> 83588 bytes
help/el/figures/evo_message_filters_a.png | Bin 0 -> 37127 bytes
help/el/figures/evo_mhreceive_a.png | Bin 0 -> 36894 bytes
help/el/figures/evo_newmail.png | Bin 0 -> 7738 bytes
help/el/figures/evo_newmess_a.png | Bin 0 -> 43220 bytes
help/el/figures/evo_offline.png | Bin 0 -> 31953 bytes
help/el/figures/evo_popreceive_a.png | Bin 0 -> 87180 bytes
help/el/figures/evo_receive_setup_a.png | Bin 0 -> 64065 bytes
help/el/figures/evo_rule_a.png | Bin 0 -> 75174 bytes
help/el/figures/evo_select_folder.png | Bin 0 -> 36423 bytes
help/el/figures/evo_send_setup_a.png | Bin 0 -> 77180 bytes
help/el/figures/evo_timezone_a.png | Bin 0 -> 198129 bytes
help/el/figures/evo_usereceive_a.png | Bin 0 -> 42446 bytes
help/el/figures/exchg-identity.png | Bin 0 -> 60015 bytes
help/el/figures/exchng-rec-mails.png | Bin 0 -> 65564 bytes
help/el/figures/exchng-rec-options.png | Bin 0 -> 84818 bytes
help/el/figures/filter-new-fig.png | Bin 0 -> 46393 bytes
help/el/figures/free_busy.png | Bin 0 -> 50895 bytes
help/el/figures/google_cal_view.png | Bin 0 -> 46299 bytes
help/el/figures/mail-threaded.png | Bin 0 -> 17136 bytes
help/el/figures/quick_add_a.png | Bin 0 -> 28292 bytes
help/el/figures/ver_view_a.png | Bin 0 -> 183841 bytes
iconv-detect.c | 2 +-
mail/Makefile.am | 1 -
mail/e-attachment-handler-mail.c | 6 +-
mail/e-attachment-handler-mail.h | 2 +-
mail/e-mail-attachment-bar.c | 2 +-
mail/e-mail-attachment-bar.h | 2 +-
mail/e-mail-browser.c | 2 +-
mail/e-mail-browser.h | 2 +-
mail/e-mail-display.c | 2 +-
mail/e-mail-display.h | 2 +-
mail/e-mail-label-dialog.c | 2 +-
mail/e-mail-label-dialog.h | 2 +-
mail/e-mail-label-list-store.c | 2 +-
mail/e-mail-label-list-store.h | 2 +-
mail/e-mail-label-manager.c | 2 +-
mail/e-mail-label-manager.h | 2 +-
mail/e-mail-label-tree-view.c | 2 +-
mail/e-mail-label-tree-view.h | 2 +-
mail/e-mail-reader-utils.c | 2 +-
mail/e-mail-reader-utils.h | 2 +-
mail/e-mail-reader.c | 4 +-
mail/e-mail-reader.h | 2 +-
mail/e-mail-search-bar.c | 2 +-
mail/e-mail-search-bar.h | 2 +-
mail/e-mail-shell-backend.c | 4 +-
mail/e-mail-shell-backend.h | 2 +-
mail/e-mail-shell-content.c | 2 +-
mail/e-mail-shell-content.h | 2 +-
mail/e-mail-shell-migrate.c | 158 +-
mail/e-mail-shell-migrate.h | 2 +-
mail/e-mail-shell-sidebar.c | 2 +-
mail/e-mail-shell-sidebar.h | 2 +-
mail/e-mail-shell-view-actions.c | 2 +-
mail/e-mail-shell-view-actions.h | 2 +-
mail/e-mail-shell-view-private.c | 2 +-
mail/e-mail-shell-view-private.h | 2 +-
mail/e-mail-shell-view.c | 2 +-
mail/e-mail-shell-view.h | 2 +-
mail/e-searching-tokenizer.c | 7 +-
mail/e-searching-tokenizer.h | 2 +-
mail/em-account-editor.c | 208 +-
mail/em-account-editor.h | 4 +-
mail/em-account-prefs.c | 2 +-
mail/em-account-prefs.h | 2 +-
mail/em-composer-prefs.c | 18 +-
mail/em-composer-prefs.h | 2 +-
mail/em-composer-utils.c | 29 +-
mail/em-composer-utils.h | 4 +-
mail/em-config.c | 2 +-
mail/em-config.h | 2 +-
mail/em-event.c | 2 +-
mail/em-event.h | 2 +-
mail/em-filter-context.c | 2 +-
mail/em-filter-context.h | 2 +-
mail/em-filter-editor.c | 4 +-
mail/em-filter-editor.h | 6 +-
mail/em-filter-folder-element.c | 2 +-
mail/em-filter-folder-element.h | 2 +-
mail/em-filter-rule.c | 4 +-
mail/em-filter-rule.h | 2 +-
mail/em-filter-source-element.c | 2 +-
mail/em-filter-source-element.h | 2 +-
mail/em-folder-browser.c | 10 +-
mail/em-folder-browser.h | 2 +-
mail/em-folder-properties.c | 14 +-
mail/em-folder-properties.h | 2 +-
mail/em-folder-selection-button.c | 2 +-
mail/em-folder-selection-button.h | 2 +-
mail/em-folder-selection.c | 2 +-
mail/em-folder-selection.h | 2 +-
mail/em-folder-selector.c | 2 +-
mail/em-folder-selector.h | 2 +-
mail/em-folder-tree-model.c | 3 +-
mail/em-folder-tree-model.h | 2 +-
mail/em-folder-tree.c | 30 +-
mail/em-folder-tree.h | 2 +-
mail/em-folder-utils.c | 8 +-
mail/em-folder-utils.h | 2 +-
mail/em-folder-view.c | 17 +-
mail/em-folder-view.h | 2 +-
mail/em-format-hook.c | 2 +-
mail/em-format-hook.h | 2 +-
mail/em-format-html-display.c | 52 +-
mail/em-format-html-display.h | 2 +-
mail/em-format-html-print.c | 2 +-
mail/em-format-html-print.h | 2 +-
mail/em-format-html.c | 128 +-
mail/em-format-html.h | 2 +-
mail/em-html-stream.c | 2 +-
mail/em-html-stream.h | 2 +-
mail/em-icon-stream.c | 2 +-
mail/em-icon-stream.h | 2 +-
mail/em-inline-filter.c | 2 +-
mail/em-inline-filter.h | 2 +-
mail/em-junk-hook.c | 2 +-
mail/em-junk-hook.h | 2 +-
mail/em-mailer-prefs.c | 38 +-
mail/em-mailer-prefs.h | 6 +-
mail/em-menu.c | 2 +-
mail/em-menu.h | 2 +-
mail/em-network-prefs.c | 89 +-
mail/em-network-prefs.h | 8 +-
mail/em-popup.c | 2 +-
mail/em-popup.h | 2 +-
mail/em-search-context.c | 2 +-
mail/em-search-context.h | 2 +-
mail/em-subscribe-editor.c | 13 +-
mail/em-subscribe-editor.h | 2 +-
mail/em-sync-stream.c | 2 +-
mail/em-sync-stream.h | 2 +-
mail/em-utils.c | 20 +-
mail/em-utils.h | 2 +-
mail/em-vfolder-context.c | 2 +-
mail/em-vfolder-context.h | 2 +-
mail/em-vfolder-editor.c | 2 +-
mail/em-vfolder-editor.h | 2 +-
mail/em-vfolder-rule.c | 8 +-
mail/em-vfolder-rule.h | 2 +-
mail/evolution-module-mail.c | 2 +-
mail/importers/elm-importer.c | 2 +-
mail/importers/evolution-mbox-importer.c | 2 +-
mail/importers/mail-importer.c | 2 +-
mail/importers/mail-importer.h | 4 +-
mail/importers/pine-importer.c | 2 +-
mail/mail-autofilter.c | 2 +-
mail/mail-autofilter.h | 2 +-
mail/mail-component.c | 5 +-
mail/mail-component.h | 2 +-
mail/mail-config.c | 30 +-
mail/mail-config.h | 2 +-
mail/mail-dialogs.glade | 56 +-
mail/mail-folder-cache.c | 5 +-
mail/mail-folder-cache.h | 2 +-
mail/mail-mt.c | 2 +-
mail/mail-mt.h | 2 +-
mail/mail-ops.c | 24 +-
mail/mail-ops.h | 6 +-
mail/mail-send-recv.c | 14 +-
mail/mail-send-recv.h | 2 +-
mail/mail-session.c | 2 +-
mail/mail-session.h | 2 +-
mail/mail-tools.c | 2 +-
mail/mail-tools.h | 2 +-
mail/mail-vfolder.c | 5 +-
mail/mail-vfolder.h | 2 +-
mail/message-list.c | 46 +-
mail/message-list.h | 2 +-
mail/message-tag-editor.c | 2 +-
mail/message-tag-editor.h | 2 +-
mail/message-tag-followup.c | 4 +-
mail/message-tag-followup.h | 2 +-
plugins/addressbook-file/addressbook-file.c | 2 +-
plugins/attachment-reminder/attachment-reminder.c | 2 +-
plugins/audio-inline/audio-inline.c | 4 +-
plugins/backup-restore/backup-restore.c | 6 +-
plugins/backup-restore/backup.c | 39 +-
plugins/bbdb/bbdb.c | 5 +-
plugins/bbdb/bbdb.h | 2 +-
plugins/bbdb/gaimbuddies.c | 10 +-
plugins/bbdb/test-evobuddy.c | 2 +-
plugins/bogo-junk-plugin/bf-junk-filter.c | 30 +-
plugins/caldav/caldav-source.c | 57 +-
plugins/calendar-file/calendar-file.c | 2 +-
plugins/copy-tool/copy-tool.c | 2 +-
plugins/default-mailer/default-mailer.c | 2 +-
plugins/default-source/default-source.c | 2 +-
plugins/email-custom-header/Makefile.am | 1 -
plugins/email-custom-header/email-custom-header.c | 92 +-
plugins/email-custom-header/email-custom-header.h | 4 +-
.../exchange-operations/exchange-account-setup.c | 46 +-
plugins/exchange-operations/exchange-calendar.c | 2 +-
.../exchange-operations/exchange-change-password.c | 2 +-
.../exchange-operations/exchange-change-password.h | 2 +-
.../exchange-operations/exchange-config-listener.c | 8 +-
.../exchange-operations/exchange-config-listener.h | 2 +-
plugins/exchange-operations/exchange-contacts.c | 4 +-
.../exchange-operations/exchange-delegates-user.c | 15 +-
.../exchange-operations/exchange-delegates-user.h | 2 +-
plugins/exchange-operations/exchange-delegates.c | 2 +-
plugins/exchange-operations/exchange-delegates.h | 2 +-
.../exchange-folder-permission.c | 4 +-
.../exchange-folder-size-display.c | 2 +-
.../exchange-folder-size-display.h | 2 +-
.../exchange-folder-subscription.c | 8 +-
.../exchange-folder-subscription.h | 4 +-
plugins/exchange-operations/exchange-folder.c | 23 +-
.../exchange-mail-send-options.c | 2 +-
plugins/exchange-operations/exchange-operations.c | 40 +-
plugins/exchange-operations/exchange-operations.h | 2 +-
.../exchange-permissions-dialog.c | 2 +-
.../exchange-permissions-dialog.h | 2 +-
.../exchange-operations/exchange-send-options.c | 2 +-
.../exchange-operations/exchange-send-options.h | 2 +-
plugins/exchange-operations/exchange-user-dialog.c | 2 +-
plugins/exchange-operations/exchange-user-dialog.h | 2 +-
plugins/face/Makefile.am | 1 -
plugins/face/face.c | 2 +-
plugins/folder-unsubscribe/folder-unsubscribe.c | 2 +-
.../google-account-setup/google-contacts-source.c | 2 +-
.../google-account-setup/google-contacts-source.h | 2 +-
plugins/google-account-setup/google-source.c | 4 +-
.../groupwise-account-setup/camel-gw-listener.c | 18 +-
.../groupwise-account-setup/camel-gw-listener.h | 2 +-
.../groupwise-account-setup.c | 6 +-
plugins/groupwise-features/Makefile.am | 1 -
plugins/groupwise-features/addressbook-groupwise.c | 2 +-
plugins/groupwise-features/install-shared.c | 2 +-
plugins/groupwise-features/junk-mail-settings.c | 4 +-
plugins/groupwise-features/junk-settings.c | 19 +-
plugins/groupwise-features/junk-settings.h | 2 +-
plugins/groupwise-features/mail-retract.c | 12 +-
plugins/groupwise-features/mail-send-options.c | 2 +-
plugins/groupwise-features/mail-send-options.h | 2 +-
.../org-gnome-process-meeting.error.xml | 44 +
plugins/groupwise-features/process-meeting.c | 38 +-
plugins/groupwise-features/proxy-login.c | 10 +-
plugins/groupwise-features/proxy-login.h | 2 +-
plugins/groupwise-features/proxy.c | 5 +-
plugins/groupwise-features/proxy.h | 3 +-
plugins/groupwise-features/send-options.c | 9 +-
plugins/groupwise-features/share-folder-common.c | 6 +-
plugins/groupwise-features/share-folder.c | 16 +-
plugins/groupwise-features/share-folder.h | 6 +-
plugins/groupwise-features/status-track.c | 4 +-
plugins/hula-account-setup/camel-hula-listener.c | 2 +-
plugins/hula-account-setup/camel-hula-listener.h | 2 +-
plugins/hula-account-setup/hula-account-setup.c | 2 +-
plugins/imap-features/Makefile.am | 1 -
plugins/imap-features/imap-headers.c | 4 +-
plugins/ipod-sync/evolution-ipod-sync.c | 2 +-
plugins/ipod-sync/evolution-ipod-sync.h | 2 +-
plugins/ipod-sync/format-handler.h | 2 +-
plugins/ipod-sync/ical-format.c | 4 +-
plugins/ipod-sync/ipod-sync.c | 4 +-
plugins/ipod-sync/ipod.c | 2 +-
plugins/ipod-sync/sync.c | 4 +-
plugins/itip-formatter/itip-formatter.c | 27 +-
plugins/itip-formatter/itip-view.c | 29 +-
plugins/itip-formatter/itip-view.h | 2 +-
plugins/mail-notification/mail-notification.c | 24 +-
plugins/mail-to-task/mail-to-task.c | 6 +-
.../mailing-list-actions/mailing-list-actions.c | 2 +-
plugins/mark-all-read/Makefile.am | 1 -
plugins/mark-all-read/mark-all-read.c | 2 +-
plugins/mono/mono-plugin.c | 8 +-
plugins/mono/mono-plugin.h | 2 +-
plugins/plugin-manager/plugin-manager.c | 6 +-
plugins/prefer-plain/prefer-plain.c | 2 +-
plugins/profiler/profiler.c | 2 +-
plugins/pst-import/pst-importer.c | 240 +-
plugins/publish-calendar/publish-calendar.c | 14 +-
plugins/publish-calendar/publish-format-fb.c | 2 +-
plugins/publish-calendar/publish-format-fb.h | 2 +-
plugins/publish-calendar/publish-format-ical.c | 2 +-
plugins/publish-calendar/publish-format-ical.h | 2 +-
plugins/publish-calendar/publish-location.c | 2 +-
plugins/publish-calendar/publish-location.h | 2 +-
plugins/publish-calendar/url-editor-dialog.c | 5 +-
plugins/publish-calendar/url-editor-dialog.h | 2 +-
plugins/python/python-plugin-loader.c | 12 +-
plugins/python/python-plugin-loader.h | 2 +-
plugins/sa-junk-plugin/em-junk-filter.c | 68 +-
plugins/save-calendar/csv-format.c | 4 +-
plugins/save-calendar/format-handler.h | 2 +-
plugins/save-calendar/ical-format.c | 2 +-
plugins/save-calendar/rdf-format.c | 2 +-
plugins/save-calendar/save-calendar.c | 2 +-
plugins/startup-wizard/startup-wizard.c | 4 +-
plugins/subject-thread/subject-thread.c | 2 +-
plugins/templates/templates.c | 66 +-
plugins/tnef-attachments/tnef-plugin.c | 4 +-
plugins/vcard-inline/vcard-inline.c | 2 +-
.../webdav-account-setup/webdav-contacts-source.c | 2 +-
po/es.po | 2026 ++--
po/he.po |12295 +++++++++-----------
po/ta.po | 8361 ++++++--------
po/th.po | 14 +-
shell/e-config-upgrade.c | 2 +-
shell/e-config-upgrade.h | 2 +-
shell/e-shell-backend.c | 2 +-
shell/e-shell-backend.h | 2 +-
shell/e-shell-common.h | 2 +-
shell/e-shell-content.c | 4 +-
shell/e-shell-content.h | 2 +-
shell/e-shell-importer.c | 6 +-
shell/e-shell-importer.h | 2 +-
shell/e-shell-migrate.c | 2 +-
shell/e-shell-migrate.h | 2 +-
shell/e-shell-nm.c | 2 +-
shell/e-shell-settings.c | 2 +-
shell/e-shell-settings.h | 2 +-
shell/e-shell-sidebar.c | 4 +-
shell/e-shell-sidebar.h | 2 +-
shell/e-shell-switcher.c | 2 +-
shell/e-shell-switcher.h | 2 +-
shell/e-shell-taskbar.c | 2 +-
shell/e-shell-taskbar.h | 2 +-
shell/e-shell-view.c | 2 +-
shell/e-shell-view.h | 2 +-
shell/e-shell-window-actions.c | 4 +-
shell/e-shell-window-actions.h | 2 +-
shell/e-shell-window-private.c | 2 +-
shell/e-shell-window-private.h | 2 +-
shell/e-shell-window.c | 2 +-
shell/e-shell-window.h | 2 +-
shell/e-shell.c | 2 +-
shell/e-shell.h | 2 +-
shell/es-event.c | 2 +-
shell/es-event.h | 2 +-
shell/main.c | 7 +-
shell/test/e-test-shell-backend.c | 2 +-
shell/test/e-test-shell-backend.h | 2 +-
shell/test/e-test-shell-view.c | 2 +-
shell/test/e-test-shell-view.h | 2 +-
shell/test/evolution-module-test.c | 2 +-
smime/gui/ca-trust-dialog.c | 2 +-
smime/gui/ca-trust-dialog.h | 2 +-
smime/gui/cert-trust-dialog.c | 2 +-
smime/gui/cert-trust-dialog.h | 2 +-
smime/gui/certificate-manager.c | 2 +-
smime/gui/certificate-manager.h | 2 +-
smime/gui/certificate-viewer.c | 2 +-
smime/gui/certificate-viewer.h | 2 +-
smime/gui/component.c | 2 +-
smime/gui/component.h | 2 +-
smime/gui/e-cert-selector.c | 2 +-
smime/gui/e-cert-selector.h | 2 +-
smime/lib/e-asn1-object.h | 2 +-
smime/lib/e-cert-db.c | 4 +-
smime/lib/e-cert-db.h | 2 +-
smime/lib/e-cert-trust.h | 2 +-
smime/lib/e-cert.h | 2 +-
smime/lib/e-pkcs12.h | 2 +-
smime/tests/import-cert.c | 2 +-
tools/killev.c | 2 +-
widgets/e-timezone-dialog/e-timezone-dialog.c | 27 +-
widgets/e-timezone-dialog/e-timezone-dialog.h | 2 +-
widgets/menus/gal-define-views-dialog.c | 6 +-
widgets/menus/gal-define-views-dialog.h | 2 +-
widgets/menus/gal-define-views-model.c | 2 +-
widgets/menus/gal-define-views-model.h | 2 +-
widgets/menus/gal-view-collection.c | 2 +-
widgets/menus/gal-view-collection.h | 2 +-
widgets/menus/gal-view-etable.c | 2 +-
widgets/menus/gal-view-etable.h | 2 +-
widgets/menus/gal-view-factory-etable.c | 2 +-
widgets/menus/gal-view-factory-etable.h | 2 +-
widgets/menus/gal-view-factory.c | 2 +-
widgets/menus/gal-view-factory.h | 2 +-
widgets/menus/gal-view-instance-save-as-dialog.c | 2 +-
widgets/menus/gal-view-instance-save-as-dialog.h | 2 +-
widgets/menus/gal-view-instance.c | 2 +-
widgets/menus/gal-view-instance.h | 2 +-
widgets/menus/gal-view-new-dialog.c | 4 +-
widgets/menus/gal-view-new-dialog.h | 2 +-
widgets/menus/gal-view.c | 2 +-
widgets/menus/gal-view.h | 2 +-
widgets/misc/a11y/ea-calendar-cell.c | 2 +-
widgets/misc/a11y/ea-calendar-cell.h | 2 +-
widgets/misc/a11y/ea-calendar-item.c | 4 +-
widgets/misc/a11y/ea-calendar-item.h | 2 +-
widgets/misc/a11y/ea-widgets.c | 2 +-
widgets/misc/a11y/ea-widgets.h | 2 +-
widgets/misc/e-account-combo-box.c | 2 +-
widgets/misc/e-account-combo-box.h | 2 +-
widgets/misc/e-account-manager.c | 2 +-
widgets/misc/e-account-manager.h | 2 +-
widgets/misc/e-account-tree-view.c | 2 +-
widgets/misc/e-account-tree-view.h | 2 +-
widgets/misc/e-activity-proxy.c | 2 +-
widgets/misc/e-activity-proxy.h | 2 +-
widgets/misc/e-activity.c | 4 +-
widgets/misc/e-activity.h | 2 +-
widgets/misc/e-alert-activity.c | 2 +-
widgets/misc/e-alert-activity.h | 2 +-
widgets/misc/e-attachment-button.c | 2 +-
widgets/misc/e-attachment-button.h | 2 +-
widgets/misc/e-attachment-dialog.c | 2 +-
widgets/misc/e-attachment-dialog.h | 2 +-
widgets/misc/e-attachment-handler-image.c | 2 +-
widgets/misc/e-attachment-handler-image.h | 2 +-
widgets/misc/e-attachment-handler.c | 2 +-
widgets/misc/e-attachment-handler.h | 2 +-
widgets/misc/e-attachment-icon-view.c | 2 +-
widgets/misc/e-attachment-icon-view.h | 2 +-
widgets/misc/e-attachment-paned.c | 2 +-
widgets/misc/e-attachment-paned.h | 2 +-
widgets/misc/e-attachment-store.c | 2 +-
widgets/misc/e-attachment-store.h | 2 +-
widgets/misc/e-attachment-tree-view.c | 2 +-
widgets/misc/e-attachment-tree-view.h | 2 +-
widgets/misc/e-attachment-view.c | 8 +-
widgets/misc/e-attachment-view.h | 2 +-
widgets/misc/e-attachment.c | 2 +-
widgets/misc/e-attachment.h | 2 +-
widgets/misc/e-calendar-item.c | 8 +-
widgets/misc/e-calendar-item.h | 11 +-
widgets/misc/e-calendar.c | 2 +-
widgets/misc/e-calendar.h | 2 +-
widgets/misc/e-canvas-background.c | 2 +-
widgets/misc/e-canvas-background.h | 2 +-
widgets/misc/e-canvas-utils.c | 2 +-
widgets/misc/e-canvas-utils.h | 2 +-
widgets/misc/e-canvas-vbox.c | 4 +-
widgets/misc/e-canvas-vbox.h | 2 +-
widgets/misc/e-canvas.c | 4 +-
widgets/misc/e-canvas.h | 2 +-
widgets/misc/e-cell-renderer-combo.c | 2 +-
widgets/misc/e-cell-renderer-combo.h | 2 +-
widgets/misc/e-charset-picker.c | 10 +-
widgets/misc/e-charset-picker.h | 2 +-
widgets/misc/e-colors.c | 2 +-
widgets/misc/e-colors.h | 2 +-
widgets/misc/e-combo-cell-editable.c | 2 +-
widgets/misc/e-combo-cell-editable.h | 2 +-
widgets/misc/e-cursors.c | 10 +-
widgets/misc/e-cursors.h | 2 +-
widgets/misc/e-dateedit.c | 6 +-
widgets/misc/e-file-activity.c | 2 +-
widgets/misc/e-file-activity.h | 2 +-
widgets/misc/e-filter-bar.c | 9 +-
widgets/misc/e-filter-bar.h | 14 +-
widgets/misc/e-gui-utils.c | 2 +-
widgets/misc/e-gui-utils.h | 2 +-
widgets/misc/e-icon-entry.h | 2 +-
widgets/misc/e-image-chooser.c | 4 +-
widgets/misc/e-image-chooser.h | 2 +-
widgets/misc/e-map.c | 2 +-
widgets/misc/e-map.h | 2 +-
widgets/misc/e-menu-tool-button.c | 2 +-
widgets/misc/e-menu-tool-button.h | 2 +-
widgets/misc/e-online-button.c | 2 +-
widgets/misc/e-online-button.h | 2 +-
widgets/misc/e-pilot-settings.c | 2 +-
widgets/misc/e-pilot-settings.h | 2 +-
widgets/misc/e-popup-action.c | 2 +-
widgets/misc/e-popup-action.h | 2 +-
widgets/misc/e-popup-menu.c | 2 +-
widgets/misc/e-popup-menu.h | 70 +-
widgets/misc/e-preferences-window.c | 2 +-
widgets/misc/e-preferences-window.h | 2 +-
widgets/misc/e-printable.c | 2 +-
widgets/misc/e-printable.h | 2 +-
widgets/misc/e-search-bar.c | 23 +-
widgets/misc/e-selection-model-array.c | 2 +-
widgets/misc/e-selection-model-array.h | 2 +-
widgets/misc/e-selection-model-simple.c | 6 +-
widgets/misc/e-selection-model-simple.h | 2 +-
widgets/misc/e-selection-model.c | 2 +-
widgets/misc/e-selection-model.h | 2 +-
widgets/misc/e-send-options.c | 2 +-
widgets/misc/e-send-options.h | 4 +-
widgets/misc/e-signature-combo-box.c | 2 +-
widgets/misc/e-signature-combo-box.h | 2 +-
widgets/misc/e-signature-editor.c | 2 +-
widgets/misc/e-signature-editor.h | 2 +-
widgets/misc/e-signature-manager.c | 2 +-
widgets/misc/e-signature-manager.h | 2 +-
widgets/misc/e-signature-preview.c | 2 +-
widgets/misc/e-signature-preview.h | 2 +-
widgets/misc/e-signature-script-dialog.c | 2 +-
widgets/misc/e-signature-script-dialog.h | 2 +-
widgets/misc/e-signature-tree-view.c | 2 +-
widgets/misc/e-signature-tree-view.h | 2 +-
widgets/misc/e-spinner.c | 6 +-
widgets/misc/e-timeout-activity.c | 2 +-
widgets/misc/e-timeout-activity.h | 2 +-
widgets/misc/e-url-entry.c | 2 +-
widgets/misc/e-url-entry.h | 2 +-
widgets/misc/pixmaps/cursor_cross.xpm | 2 +-
widgets/misc/pixmaps/cursor_hand_closed.xpm | 2 +-
widgets/misc/pixmaps/cursor_hand_open.xpm | 2 +-
widgets/misc/pixmaps/cursor_zoom_in.xpm | 2 +-
widgets/misc/pixmaps/cursor_zoom_out.xpm | 2 +-
widgets/misc/test-calendar.c | 4 +-
widgets/misc/test-dateedit.c | 20 +-
widgets/misc/test-preferences-window.c | 2 +-
widgets/table/a11y/gal-a11y-e-cell-popup.c | 2 +-
widgets/table/a11y/gal-a11y-e-cell-popup.h | 2 +-
widgets/table/a11y/gal-a11y-e-cell-registry.c | 2 +-
widgets/table/a11y/gal-a11y-e-cell-registry.h | 2 +-
widgets/table/a11y/gal-a11y-e-cell-text.c | 2 +-
widgets/table/a11y/gal-a11y-e-cell-text.h | 2 +-
widgets/table/a11y/gal-a11y-e-cell-toggle.c | 2 +-
widgets/table/a11y/gal-a11y-e-cell-toggle.h | 2 +-
widgets/table/a11y/gal-a11y-e-cell-tree.c | 2 +-
widgets/table/a11y/gal-a11y-e-cell-tree.h | 2 +-
widgets/table/a11y/gal-a11y-e-cell-vbox.c | 2 +-
widgets/table/a11y/gal-a11y-e-cell-vbox.h | 2 +-
widgets/table/a11y/gal-a11y-e-cell.c | 2 +-
widgets/table/a11y/gal-a11y-e-cell.h | 2 +-
.../a11y/gal-a11y-e-table-click-to-add-factory.c | 2 +-
.../a11y/gal-a11y-e-table-click-to-add-factory.h | 2 +-
widgets/table/a11y/gal-a11y-e-table-click-to-add.c | 2 +-
widgets/table/a11y/gal-a11y-e-table-click-to-add.h | 2 +-
.../table/a11y/gal-a11y-e-table-column-header.c | 2 +-
.../table/a11y/gal-a11y-e-table-column-header.h | 2 +-
widgets/table/a11y/gal-a11y-e-table-factory.c | 2 +-
widgets/table/a11y/gal-a11y-e-table-factory.h | 2 +-
widgets/table/a11y/gal-a11y-e-table-item-factory.c | 2 +-
widgets/table/a11y/gal-a11y-e-table-item-factory.h | 2 +-
widgets/table/a11y/gal-a11y-e-table-item.c | 2 +-
widgets/table/a11y/gal-a11y-e-table-item.h | 2 +-
widgets/table/a11y/gal-a11y-e-table.c | 2 +-
widgets/table/a11y/gal-a11y-e-table.h | 2 +-
widgets/table/a11y/gal-a11y-e-tree-factory.c | 2 +-
widgets/table/a11y/gal-a11y-e-tree-factory.h | 2 +-
widgets/table/a11y/gal-a11y-e-tree.c | 2 +-
widgets/table/a11y/gal-a11y-e-tree.h | 2 +-
widgets/table/add-col.xpm | 2 +-
widgets/table/e-cell-checkbox.c | 2 +-
widgets/table/e-cell-checkbox.h | 2 +-
widgets/table/e-cell-combo.c | 4 +-
widgets/table/e-cell-combo.h | 2 +-
widgets/table/e-cell-date-edit.c | 6 +-
widgets/table/e-cell-date-edit.h | 2 +-
widgets/table/e-cell-date.c | 4 +-
widgets/table/e-cell-date.h | 2 +-
widgets/table/e-cell-hbox.c | 2 +-
widgets/table/e-cell-hbox.h | 2 +-
widgets/table/e-cell-number.c | 2 +-
widgets/table/e-cell-number.h | 2 +-
widgets/table/e-cell-percent.c | 2 +-
widgets/table/e-cell-percent.h | 2 +-
widgets/table/e-cell-pixbuf.c | 6 +-
widgets/table/e-cell-pixbuf.h | 2 +-
widgets/table/e-cell-popup.c | 4 +-
widgets/table/e-cell-popup.h | 6 +-
widgets/table/e-cell-size.c | 2 +-
widgets/table/e-cell-size.h | 2 +-
widgets/table/e-cell-text.c | 8 +-
widgets/table/e-cell-text.h | 2 +-
widgets/table/e-cell-toggle.c | 10 +-
widgets/table/e-cell-toggle.h | 2 +-
widgets/table/e-cell-vbox.c | 2 +-
widgets/table/e-cell-vbox.h | 2 +-
widgets/table/e-cell.c | 10 +-
widgets/table/e-cell.h | 2 +-
widgets/table/e-table-click-to-add.c | 2 +-
widgets/table/e-table-click-to-add.h | 2 +-
widgets/table/e-table-col-dnd.h | 2 +-
widgets/table/e-table-col.c | 2 +-
widgets/table/e-table-col.h | 2 +-
widgets/table/e-table-column-specification.c | 2 +-
widgets/table/e-table-column-specification.h | 2 +-
widgets/table/e-table-column.c | 2 +-
widgets/table/e-table-config-field.c | 2 +-
widgets/table/e-table-config-field.h | 2 +-
widgets/table/e-table-config.c | 7 +-
widgets/table/e-table-config.h | 2 +-
widgets/table/e-table-defines.h | 2 +-
widgets/table/e-table-example-2.c | 2 +-
widgets/table/e-table-extras.c | 18 +-
widgets/table/e-table-extras.h | 18 +-
widgets/table/e-table-field-chooser-dialog.c | 4 +-
widgets/table/e-table-field-chooser-dialog.h | 2 +-
widgets/table/e-table-field-chooser-item.c | 4 +-
widgets/table/e-table-field-chooser-item.h | 2 +-
widgets/table/e-table-field-chooser.c | 4 +-
widgets/table/e-table-field-chooser.h | 2 +-
widgets/table/e-table-group-container.c | 2 +-
widgets/table/e-table-group-container.h | 2 +-
widgets/table/e-table-group-leaf.c | 2 +-
widgets/table/e-table-group-leaf.h | 2 +-
widgets/table/e-table-group.c | 2 +-
widgets/table/e-table-group.h | 2 +-
widgets/table/e-table-header-item.c | 30 +-
widgets/table/e-table-header-item.h | 2 +-
widgets/table/e-table-header-utils.c | 2 +-
widgets/table/e-table-header-utils.h | 2 +-
widgets/table/e-table-header.c | 2 +-
widgets/table/e-table-header.h | 2 +-
widgets/table/e-table-item.c | 26 +-
widgets/table/e-table-item.h | 2 +-
widgets/table/e-table-memory-callbacks.c | 2 +-
widgets/table/e-table-memory-callbacks.h | 2 +-
widgets/table/e-table-memory-store.c | 2 +-
widgets/table/e-table-memory-store.h | 2 +-
widgets/table/e-table-memory.c | 2 +-
widgets/table/e-table-memory.h | 2 +-
widgets/table/e-table-model.c | 6 +-
widgets/table/e-table-model.h | 4 +-
widgets/table/e-table-one.c | 2 +-
widgets/table/e-table-one.h | 2 +-
widgets/table/e-table-scrolled.c | 2 +-
widgets/table/e-table-scrolled.h | 2 +-
widgets/table/e-table-search.c | 2 +-
widgets/table/e-table-search.h | 2 +-
widgets/table/e-table-selection-model.c | 8 +-
widgets/table/e-table-selection-model.h | 4 +-
widgets/table/e-table-simple.c | 2 +-
widgets/table/e-table-simple.h | 2 +-
widgets/table/e-table-sort-info.c | 2 +-
widgets/table/e-table-sort-info.h | 2 +-
widgets/table/e-table-sorted-variable.c | 2 +-
widgets/table/e-table-sorted-variable.h | 2 +-
widgets/table/e-table-sorted.c | 2 +-
widgets/table/e-table-sorted.h | 2 +-
widgets/table/e-table-sorter.c | 2 +-
widgets/table/e-table-sorter.h | 2 +-
widgets/table/e-table-sorting-utils.c | 2 +-
widgets/table/e-table-sorting-utils.h | 2 +-
widgets/table/e-table-specification.c | 4 +-
widgets/table/e-table-specification.h | 2 +-
widgets/table/e-table-state.c | 2 +-
widgets/table/e-table-state.h | 2 +-
widgets/table/e-table-subset-variable.c | 2 +-
widgets/table/e-table-subset-variable.h | 2 +-
widgets/table/e-table-subset.c | 2 +-
widgets/table/e-table-subset.h | 2 +-
widgets/table/e-table-tooltip.h | 2 +-
widgets/table/e-table-utils.c | 2 +-
widgets/table/e-table-utils.h | 2 +-
widgets/table/e-table-without.c | 2 +-
widgets/table/e-table-without.h | 2 +-
widgets/table/e-table.c | 2 +-
widgets/table/e-table.h | 2 +-
widgets/table/e-tree-memory-callbacks.c | 2 +-
widgets/table/e-tree-memory-callbacks.h | 2 +-
widgets/table/e-tree-memory.c | 2 +-
widgets/table/e-tree-memory.h | 2 +-
widgets/table/e-tree-model.c | 2 +-
widgets/table/e-tree-model.h | 2 +-
widgets/table/e-tree-scrolled.c | 2 +-
widgets/table/e-tree-scrolled.h | 2 +-
widgets/table/e-tree-selection-model.c | 2 +-
widgets/table/e-tree-selection-model.h | 2 +-
widgets/table/e-tree-simple.c | 2 +-
widgets/table/e-tree-simple.h | 2 +-
widgets/table/e-tree-sorted-variable.c | 2 +-
widgets/table/e-tree-sorted-variable.h | 2 +-
widgets/table/e-tree-sorted.c | 2 +-
widgets/table/e-tree-sorted.h | 2 +-
widgets/table/e-tree-table-adapter.c | 3 +-
widgets/table/e-tree-table-adapter.h | 2 +-
widgets/table/e-tree.c | 4 +-
widgets/table/e-tree.h | 2 +-
widgets/table/remove-col.xpm | 2 +-
widgets/table/tree-expanded.xpm | 2 +-
widgets/table/tree-unexpanded.xpm | 2 +-
widgets/text/a11y/gal-a11y-e-text-factory.c | 2 +-
widgets/text/a11y/gal-a11y-e-text-factory.h | 2 +-
widgets/text/a11y/gal-a11y-e-text.c | 2 +-
widgets/text/a11y/gal-a11y-e-text.h | 2 +-
widgets/text/e-reflow-model.c | 2 +-
widgets/text/e-reflow-model.h | 2 +-
widgets/text/e-reflow.c | 2 +-
widgets/text/e-reflow.h | 2 +-
widgets/text/e-text-model-repos.c | 2 +-
widgets/text/e-text-model-repos.h | 2 +-
widgets/text/e-text-model.c | 4 +-
widgets/text/e-text-model.h | 2 +-
widgets/text/e-text.c | 20 +-
widgets/text/e-text.h | 2 +-
1239 files changed, 17613 insertions(+), 16597 deletions(-)
diff --cc addressbook/gui/component/e-book-shell-backend.c
index fd86d57,0000000..68af7ed
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-backend.c
+++ b/addressbook/gui/component/e-book-shell-backend.c
@@@ -1,576 -1,0 +1,576 @@@
+/*
+ * e-book-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-book-shell-backend.h"
+
+#include <config.h>
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libebook/e-book.h>
+#include <libedataserver/e-url.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-group.h>
+
+#include "shell/e-shell.h"
+#include "shell/e-shell-window.h"
+
+#include "e-util/e-import.h"
+#include "addressbook/gui/widgets/eab-gui-util.h"
+#include "addressbook/gui/contact-editor/e-contact-editor.h"
+#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
+#include "addressbook/importers/evolution-addressbook-importers.h"
+
+#include "eab-config.h"
+#include "addressbook-config.h"
+#include "autocompletion-config.h"
+
+#include "e-book-shell-migrate.h"
+#include "e-book-shell-view.h"
+
+#ifdef ENABLE_SMIME
+#include "smime/gui/component.h"
+#include "smime/gui/certificate-manager.h"
+#endif
+
+#define E_BOOK_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendPrivate))
+
+#define LDAP_BASE_URI "ldap://"
+#define PERSONAL_RELATIVE_URI "system"
+
+struct _EBookShellBackendPrivate {
+ ESourceList *source_list;
+};
+
+enum {
+ PROP_0,
+ PROP_SOURCE_LIST
+};
+
+static gpointer parent_class;
+static GType book_shell_backend_type;
+
+static void
+book_shell_backend_ensure_sources (EShellBackend *shell_backend)
+{
+ /* XXX This is basically the same algorithm across all backends.
+ * Maybe we could somehow integrate this into EShellBackend? */
+
+ EBookShellBackendPrivate *priv;
+ ESourceGroup *on_this_computer;
+ ESourceGroup *on_ldap_servers;
+ ESource *personal;
+ GSList *groups, *iter;
+ const gchar *data_dir;
+ const gchar *name;
+ gchar *base_uri;
+ gchar *filename;
+
+ on_this_computer = NULL;
+ on_ldap_servers = NULL;
+ personal = NULL;
+
+ priv = E_BOOK_SHELL_BACKEND_GET_PRIVATE (shell_backend);
+
+ if (!e_book_get_addressbooks (&priv->source_list, NULL)) {
+ g_warning ("Could not get addressbook sources from GConf!");
+ return;
+ }
+
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ filename = g_build_filename (data_dir, "local", NULL);
+ base_uri = g_filename_to_uri (filename, NULL, NULL);
+ g_free (filename);
+
+ groups = e_source_list_peek_groups (priv->source_list);
+ for (iter = groups; iter != NULL; iter = iter->next) {
+ ESourceGroup *source_group = iter->data;
+ const gchar *group_base_uri;
+
+ group_base_uri = e_source_group_peek_base_uri (source_group);
+
+ /* Compare only "file://" part. If the user's home
+ * changes, we do not want to create another group. */
+ if (on_this_computer == NULL &&
+ strncmp (base_uri, group_base_uri, 7) == 0)
+ on_this_computer = source_group;
+
+ else if (on_ldap_servers == NULL &&
+ strcmp (LDAP_BASE_URI, group_base_uri) == 0)
+ on_ldap_servers = source_group;
+ }
+
+ name = _("On This Computer");
+
+ if (on_this_computer != NULL) {
+ GSList *sources;
+ const gchar *group_base_uri;
+
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (on_this_computer, name);
+
+ sources = e_source_group_peek_sources (on_this_computer);
+ group_base_uri = e_source_group_peek_base_uri (on_this_computer);
+
+ /* Make sure this group includes a "Personal" source. */
+ for (iter = sources; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (relative_uri == NULL)
+ continue;
+
+ if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0)
+ continue;
+
+ personal = source;
+ break;
+ }
+
+ /* Make sure we have the correct base URI. This can
+ * change when the user's home directory changes. */
+ if (strcmp (base_uri, group_base_uri) != 0) {
+ e_source_group_set_base_uri (
+ on_this_computer, base_uri);
+
+ /* XXX We shouldn't need this sync call here as
+ * set_base_uri() results in synching to GConf,
+ * but that happens in an idle loop and too late
+ * to prevent the user from seeing a "Cannot
+ * Open ... because of invalid URI" error. */
+ e_source_list_sync (priv->source_list, NULL);
+ }
+
+ } else {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, base_uri);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ }
+
+ name = _("Personal");
+
+ if (personal == NULL) {
+ ESource *source;
+
+ /* Create the default Personal address book. */
+ source = e_source_new (name, PERSONAL_RELATIVE_URI);
+ e_source_group_add_source (on_this_computer, source, -1);
+ e_source_set_property (source, "completion", "true");
+ g_object_unref (source);
+ } else {
+ /* Force the source name to the current locale. */
+ e_source_set_name (personal, name);
+ }
+
+ name = _("On LDAP Servers");
+
+ if (on_ldap_servers == NULL) {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, LDAP_BASE_URI);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ } else {
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (on_ldap_servers, name);
+ }
+
+ g_free (base_uri);
+}
+
+static void
+book_shell_backend_init_importers (void)
+{
+ EImportClass *import_class;
+ EImportImporter *importer;
+
+ import_class = g_type_class_ref (e_import_get_type ());
+
+ importer = evolution_ldif_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = evolution_vcard_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = evolution_csv_outlook_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = evolution_csv_mozilla_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = evolution_csv_evolution_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+}
+
+static void
+book_shell_backend_book_loaded_cb (EBook *book,
+ EBookStatus status,
+ gpointer user_data)
+{
+ EContact *contact;
+ GtkAction *action;
+ GtkWidget *editor;
+ const gchar *action_name;
+
+ /* XXX Handle errors better. */
+ if (status != E_BOOK_ERROR_OK)
+ return;
+
+ contact = e_contact_new ();
+ action = GTK_ACTION (user_data);
+ action_name = gtk_action_get_name (action);
+
+ if (strcmp (action_name, "contact-new") == 0)
+ editor = e_contact_editor_new (book, contact, TRUE, TRUE);
+
+ if (strcmp (action_name, "contact-new-list") == 0)
+ editor = e_contact_list_editor_new (book, contact, TRUE, TRUE);
+
+ eab_editor_show (EAB_EDITOR (editor));
+
+ g_object_unref (contact);
+ g_object_unref (book);
+}
+
+static void
+action_contact_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ EBook *book = NULL;
+ GConfClient *client;
+ ESourceList *source_list;
+ const gchar *key;
+ gchar *uid;
+
+ /* This callback is used for both contacts and contact lists. */
+
+ if (!e_book_get_addressbooks (&source_list, NULL)) {
+ g_warning ("Could not get addressbook sources from GConf!");
+ return;
+ }
+
+ shell = e_shell_window_get_shell (shell_window);
+ client = e_shell_get_gconf_client (shell);
+
+ key = "/apps/evolution/addressbook/display/primary_addressbook";
+ uid = gconf_client_get_string (client, key, NULL);
+
+ if (uid != NULL) {
+ ESource *source;
+
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ if (source != NULL)
+ book = e_book_new (source, NULL);
+ g_free (uid);
+ }
+
+ if (book == NULL)
+ book = e_book_new_default_addressbook (NULL);
+
+ e_book_async_open (
+ book, FALSE, book_shell_backend_book_loaded_cb, action);
+}
+
+static void
+action_address_book_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ addressbook_config_create_new_source (NULL);
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "contact-new",
+ "contact-new",
+ NC_("New", "_Contact"),
+ "<Shift><Control>c",
+ N_("Create a new contact"),
+ G_CALLBACK (action_contact_new_cb) },
+
+ { "contact-new-list",
+ "stock_contact-list",
+ N_("Contact _List"),
+ "<Shift><Control>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_handle_uri_cb (EShellBackend *shell_backend,
+ const gchar *uri)
+{
+ EUri *euri;
+ const gchar *cp;
+ gchar *source_uid = NULL;
+ gchar *contact_uid = NULL;
+
+ if (!g_str_has_prefix (uri, "contacts:"))
+ return FALSE;
+
+ euri = e_uri_new (uri);
+ cp = euri->query;
+
+ if (cp == NULL) {
+ e_uri_free (euri);
+ return FALSE;
+ }
+
+ while (*cp != '\0') {
+ gchar *header;
+ gchar *content;
+ gsize length;
+ gsize content_length;
+
+ length = strcspn (cp, "=&");
+
+ /* If it's malformed, give up. */
+ if (cp[length] != '=')
+ break;
+
+ header = (gchar *) cp;
+ header[length] = '\0';
+ cp += length + 1;
+
+ content_length = strcspn (cp, "&");
+ content = g_strndup (cp, content_length);
+
+ if (g_ascii_strcasecmp (header, "source-uid") == 0)
+ source_uid = g_strdup (content);
+
+ if (g_ascii_strcasecmp (header, "contact-uid") == 0)
+ contact_uid = g_strdup (content);
+
+ g_free (content);
+
+ cp += content_length;
+ if (*cp == '&') {
+ cp++;
+ if (strcmp (cp, "amp;"))
+ cp += 4;
+ }
+ }
+
+ /* FIXME */
+ /*addressbook_view_edit_contact (view, source_uid, contact_uid);*/
+
+ g_free (source_uid);
+ g_free (contact_uid);
+
+ e_uri_free (euri);
+
+ return TRUE;
+}
+
+static void
+book_shell_backend_window_created_cb (EShellBackend *shell_backend,
+ GtkWindow *window)
+{
+ const gchar *backend_name;
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+}
+
+static void
+book_shell_backend_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE_LIST:
+ g_value_set_object (
+ value,
+ e_book_shell_backend_get_source_list (
+ E_BOOK_SHELL_BACKEND (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+book_shell_backend_dispose (GObject *object)
+{
+ EBookShellBackendPrivate *priv;
+
+ priv = E_BOOK_SHELL_BACKEND_GET_PRIVATE (object);
+
+ if (priv->source_list != NULL) {
+ g_object_unref (priv->source_list);
+ priv->source_list = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+book_shell_backend_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ /* XXX Why is this here? Address books aren't the only
+ * things that use S/MIME. Maybe put it in EShell? */
+#ifdef ENABLE_SMIME
+ smime_component_init ();
+ certificate_manager_config_init (shell);
+#endif
+
+ book_shell_backend_init_importers ();
+ book_shell_backend_ensure_sources (shell_backend);
+
+ e_plugin_hook_register_type (eab_config_get_type ());
+
+ g_signal_connect_swapped (
+ shell, "handle-uri",
+ G_CALLBACK (book_shell_backend_handle_uri_cb),
+ shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-created",
+ G_CALLBACK (book_shell_backend_window_created_cb),
+ shell_backend);
+
+ autocompletion_config_init (shell);
+}
+
+static gboolean
+book_shell_backend_is_busy (EShellBackend *shell_backend)
+{
+ return !eab_editor_request_close_all ();
+}
+
+static gboolean
+book_shell_backend_shutdown (EShellBackend *shell_backend)
+{
+ /* FIXME */
+ return TRUE;
+}
+
+static void
+book_shell_backend_class_init (EBookShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EBookShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = book_shell_backend_get_property;
+ object_class->dispose = book_shell_backend_dispose;
+ object_class->constructed = book_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_BOOK_SHELL_VIEW;
+ shell_backend_class->name = "addressbook";
+ shell_backend_class->aliases = "contacts";
+ shell_backend_class->schemes = "";
+ shell_backend_class->sort_order = 300;
+ shell_backend_class->start = NULL;
+ shell_backend_class->is_busy = book_shell_backend_is_busy;
+ shell_backend_class->shutdown = book_shell_backend_shutdown;
+ shell_backend_class->migrate = e_book_shell_backend_migrate;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SOURCE_LIST,
+ g_param_spec_object (
+ "source-list",
+ _("Source List"),
+ _("The registry of address books"),
+ E_TYPE_SOURCE_LIST,
+ G_PARAM_READABLE));
+}
+
+static void
+book_shell_backend_init (EBookShellBackend *book_shell_backend)
+{
+ book_shell_backend->priv =
+ E_BOOK_SHELL_BACKEND_GET_PRIVATE (book_shell_backend);
+}
+
+GType
+e_book_shell_backend_get_type (void)
+{
+ return book_shell_backend_type;
+}
+
+void
+e_book_shell_backend_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EBookShellBackendClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) book_shell_backend_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EBookShellBackend),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) book_shell_backend_init,
+ NULL /* value_table */
+ };
+
+ book_shell_backend_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_BACKEND,
+ "EBookShellBackend", &type_info, 0);
+}
+
+ESourceList *
+e_book_shell_backend_get_source_list (EBookShellBackend *book_shell_backend)
+{
+ g_return_val_if_fail (
+ E_IS_BOOK_SHELL_BACKEND (book_shell_backend), NULL);
+
+ return book_shell_backend->priv->source_list;
+}
diff --cc addressbook/gui/component/e-book-shell-backend.h
index c3fde1c,0000000..c61e43b
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-backend.h
+++ b/addressbook/gui/component/e-book-shell-backend.h
@@@ -1,70 -1,0 +1,70 @@@
+/*
+ * e-book-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_BOOK_SHELL_BACKEND_H
+#define E_BOOK_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+#include <libedataserver/e-source-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_BOOK_SHELL_BACKEND \
+ (e_book_shell_backend_get_type ())
+#define E_BOOK_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackend))
+#define E_BOOK_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendClass))
+#define E_IS_BOOK_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_BOOK_SHELL_BACKEND))
+#define E_IS_BOOK_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_BOOK_SHELL_BACKEND))
+#define E_BOOK_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_BOOK_SHELL_BACKEND, EBookShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EBookShellBackend EBookShellBackend;
+typedef struct _EBookShellBackendClass EBookShellBackendClass;
+typedef struct _EBookShellBackendPrivate EBookShellBackendPrivate;
+
+struct _EBookShellBackend {
+ EShellBackend parent;
+ EBookShellBackendPrivate *priv;
+};
+
+struct _EBookShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+GType e_book_shell_backend_get_type (void);
+void e_book_shell_backend_register_type
+ (GTypeModule *type_module);
+ESourceList * e_book_shell_backend_get_source_list
+ (EBookShellBackend *book_shell_backend);
+
+G_END_DECLS
+
+#endif /* E_BOOK_SHELL_BACKEND_H */
diff --cc addressbook/gui/component/e-book-shell-content.c
index 7f7b948,0000000..cce03b1
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-content.c
+++ b/addressbook/gui/component/e-book-shell-content.c
@@@ -1,492 -1,0 +1,492 @@@
+/*
+ * e-book-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-book-shell-content.h"
+
+#include <glib/gi18n.h>
+
+#include "e-util/gconf-bridge.h"
+
+#define E_BOOK_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentPrivate))
+
+struct _EBookShellContentPrivate {
+ GtkWidget *paned;
+ GtkWidget *notebook;
+ GtkWidget *preview;
+};
+
+enum {
+ PROP_0,
+ PROP_CURRENT_VIEW,
+ PROP_PREVIEW_CONTACT,
+ PROP_PREVIEW_VISIBLE
+};
+
+static gpointer parent_class;
+static GType book_shell_view_type;
+
+static void
+book_shell_content_send_message_cb (EBookShellContent *book_shell_content,
+ EDestination *destination,
+ EABContactDisplay *display)
+{
+ GList node = { destination, NULL, NULL };
+
+ eab_send_as_to (&node);
+}
+
+static void
+book_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_VIEW:
+ e_book_shell_content_set_current_view (
+ E_BOOK_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_PREVIEW_CONTACT:
+ e_book_shell_content_set_preview_contact (
+ E_BOOK_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_PREVIEW_VISIBLE:
+ e_book_shell_content_set_preview_visible (
+ E_BOOK_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+book_shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_VIEW:
+ g_value_set_object (
+ value, e_book_shell_content_get_current_view (
+ E_BOOK_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_PREVIEW_CONTACT:
+ g_value_set_object (
+ value, e_book_shell_content_get_preview_contact (
+ E_BOOK_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_PREVIEW_VISIBLE:
+ g_value_set_boolean (
+ value, e_book_shell_content_get_preview_visible (
+ E_BOOK_SHELL_CONTENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+book_shell_content_dispose (GObject *object)
+{
+ EBookShellContentPrivate *priv;
+
+ priv = E_BOOK_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->notebook != NULL) {
+ g_object_unref (priv->notebook);
+ priv->notebook = NULL;
+ }
+
+ if (priv->preview != NULL) {
+ g_object_unref (priv->preview);
+ priv->preview = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+book_shell_content_constructed (GObject *object)
+{
+ EBookShellContentPrivate *priv;
+ GConfBridge *bridge;
+ GtkWidget *container;
+ GtkWidget *widget;
+ const gchar *key;
+
+ priv = E_BOOK_SHELL_CONTENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ container = GTK_WIDGET (object);
+
+ widget = gtk_vpaned_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
+ gtk_paned_add1 (GTK_PANED (container), widget);
+ priv->notebook = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_paned_add2 (GTK_PANED (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = eab_contact_display_new ();
+ eab_contact_display_set_mode (
+ EAB_CONTACT_DISPLAY (widget),
+ EAB_CONTACT_DISPLAY_RENDER_NORMAL);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->preview = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ priv->preview, "send-message",
+ G_CALLBACK (book_shell_content_send_message_cb), object);
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (priv->paned);
+ key = "/apps/evolution/addressbook/display/vpane_position";
+ gconf_bridge_bind_property_delayed (bridge, key, object, "position");
+}
+
+static guint32
+book_shell_content_check_state (EShellContent *shell_content)
+{
+ EBookShellContent *book_shell_content;
+ ESelectionModel *selection_model;
+ EAddressbookModel *model;
+ EAddressbookView *view;
+ guint32 state = 0;
+ gint n_contacts;
+ gint n_selected;
+
+ book_shell_content = E_BOOK_SHELL_CONTENT (shell_content);
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ model = e_addressbook_view_get_model (view);
+
+ selection_model = e_addressbook_view_get_selection_model (view);
+ n_contacts = (selection_model != NULL) ?
+ e_selection_model_row_count (selection_model) : 0;
+ n_selected = (selection_model != NULL) ?
+ e_selection_model_selected_count (selection_model) : 0;
+
+ /* FIXME Finish the rest of the flags. */
+ if (n_selected == 1)
+ state |= E_BOOK_SHELL_CONTENT_SELECTION_SINGLE;
+ if (n_selected > 1)
+ state |= E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE;
+ if (e_addressbook_model_can_stop (model))
+ state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY;
+ if (e_addressbook_model_get_editable (model))
+ state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE;
+ if (n_contacts == 0)
+ state |= E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY;
+
+ return state;
+}
+
+static void
+book_shell_content_class_init (EBookShellContentClass *class)
+{
+ GObjectClass *object_class;
+ EShellContentClass *shell_content_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EBookShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = book_shell_content_set_property;
+ object_class->get_property = book_shell_content_get_property;
+ object_class->dispose = book_shell_content_dispose;
+ object_class->constructed = book_shell_content_constructed;
+
+ shell_content_class = E_SHELL_CONTENT_CLASS (class);
+ shell_content_class->check_state = book_shell_content_check_state;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CURRENT_VIEW,
+ g_param_spec_object (
+ "current-view",
+ _("Current View"),
+ _("The currently selected address book view"),
+ E_TYPE_ADDRESSBOOK_VIEW,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW_CONTACT,
+ g_param_spec_object (
+ "preview-contact",
+ _("Previewed Contact"),
+ _("The contact being shown in the preview pane"),
+ E_TYPE_CONTACT,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW_VISIBLE,
+ g_param_spec_boolean (
+ "preview-visible",
+ _("Preview is Visible"),
+ _("Whether the preview pane is visible"),
+ TRUE,
+ G_PARAM_READWRITE));
+}
+
+static void
+book_shell_content_init (EBookShellContent *book_shell_content)
+{
+ book_shell_content->priv =
+ E_BOOK_SHELL_CONTENT_GET_PRIVATE (book_shell_content);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_book_shell_content_get_type (void)
+{
+ return book_shell_view_type;
+}
+
+void
+e_book_shell_content_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EBookShellContentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) book_shell_content_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EBookShellContent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) book_shell_content_init,
+ NULL /* value_table */
+ };
+
+ book_shell_view_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_CONTENT,
+ "EBookShellContent", &type_info, 0);
+}
+
+GtkWidget *
+e_book_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_BOOK_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+void
+e_book_shell_content_insert_view (EBookShellContent *book_shell_content,
+ EAddressbookView *addressbook_view)
+{
+ GtkNotebook *notebook;
+ GtkWidget *child;
+
+ g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
+ g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view));
+
+ notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook);
+ child = GTK_WIDGET (addressbook_view);
+ gtk_notebook_append_page (notebook, child, NULL);
+}
+
+void
+e_book_shell_content_remove_view (EBookShellContent *book_shell_content,
+ EAddressbookView *addressbook_view)
+{
+ GtkNotebook *notebook;
+ GtkWidget *child;
+ gint page_num;
+
+ g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
+ g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view));
+
+ notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook);
+ child = GTK_WIDGET (addressbook_view);
+ page_num = gtk_notebook_page_num (notebook, child);
+ g_return_if_fail (page_num >= 0);
+
+ gtk_notebook_remove_page (notebook, page_num);
+}
+
+EAddressbookView *
+e_book_shell_content_get_current_view (EBookShellContent *book_shell_content)
+{
+ GtkNotebook *notebook;
+ GtkWidget *widget;
+ gint page_num;
+
+ g_return_val_if_fail (
+ E_IS_BOOK_SHELL_CONTENT (book_shell_content), NULL);
+
+ notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook);
+ page_num = gtk_notebook_get_current_page (notebook);
+ widget = gtk_notebook_get_nth_page (notebook, page_num);
+ g_return_val_if_fail (widget != NULL, NULL);
+
+ return E_ADDRESSBOOK_VIEW (widget);
+}
+
+void
+e_book_shell_content_set_current_view (EBookShellContent *book_shell_content,
+ EAddressbookView *addressbook_view)
+{
+ GtkNotebook *notebook;
+ GtkWidget *child;
+ gint page_num;
+
+ g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
+ g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (addressbook_view));
+
+ notebook = GTK_NOTEBOOK (book_shell_content->priv->notebook);
+ child = GTK_WIDGET (addressbook_view);
+ page_num = gtk_notebook_page_num (notebook, child);
+ g_return_if_fail (page_num >= 0);
+
+ gtk_notebook_set_current_page (notebook, page_num);
+ g_object_notify (G_OBJECT (book_shell_content), "current-view");
+}
+
+EContact *
+e_book_shell_content_get_preview_contact (EBookShellContent *book_shell_content)
+{
+ EABContactDisplay *display;
+
+ g_return_val_if_fail (
+ E_IS_BOOK_SHELL_CONTENT (book_shell_content), NULL);
+
+ display = EAB_CONTACT_DISPLAY (book_shell_content->priv->preview);
+
+ return eab_contact_display_get_contact (display);
+}
+
+void
+e_book_shell_content_set_preview_contact (EBookShellContent *book_shell_content,
+ EContact *preview_contact)
+{
+ EABContactDisplay *display;
+
+ g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
+
+ display = EAB_CONTACT_DISPLAY (book_shell_content->priv->preview);
+
+ eab_contact_display_set_contact (display, preview_contact);
+ g_object_notify (G_OBJECT (book_shell_content), "preview-contact");
+}
+
+gboolean
+e_book_shell_content_get_preview_visible (EBookShellContent *book_shell_content)
+{
+ GtkPaned *paned;
+ GtkWidget *child;
+
+ g_return_val_if_fail (
+ E_IS_BOOK_SHELL_CONTENT (book_shell_content), FALSE);
+
+ paned = GTK_PANED (book_shell_content->priv->paned);
+ child = gtk_paned_get_child2 (paned);
+
+ return GTK_WIDGET_VISIBLE (child);
+}
+
+void
+e_book_shell_content_set_preview_visible (EBookShellContent *book_shell_content,
+ gboolean preview_visible)
+{
+ GtkPaned *paned;
+ GtkWidget *child;
+
+ g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
+
+ paned = GTK_PANED (book_shell_content->priv->paned);
+ child = gtk_paned_get_child2 (paned);
+
+ if (preview_visible)
+ gtk_widget_show (child);
+ else
+ gtk_widget_hide (child);
+
+ g_object_notify (G_OBJECT (book_shell_content), "preview-visible");
+}
+
+void
+e_book_shell_content_clipboard_copy (EBookShellContent *book_shell_content)
+{
+ EAddressbookView *addressbook_view;
+ GtkHTML *html;
+ gchar *selection;
+
+ g_return_if_fail (E_IS_BOOK_SHELL_CONTENT (book_shell_content));
+
+ html = GTK_HTML (book_shell_content->priv->preview);
+ addressbook_view =
+ e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (addressbook_view != NULL);
+
+ if (!GTK_WIDGET_HAS_FOCUS (html)) {
+ e_addressbook_view_copy (addressbook_view);
+ return;
+ }
+
+ selection = gtk_html_get_selection_html (html, NULL);
+ if (selection != NULL)
+ gtk_html_copy (html);
+ g_free (selection);
+}
diff --cc addressbook/gui/component/e-book-shell-content.h
index a8f8271,0000000..ac5ab10
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-content.h
+++ b/addressbook/gui/component/e-book-shell-content.h
@@@ -1,110 -1,0 +1,110 @@@
+/*
+ * e-book-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_BOOK_SHELL_CONTENT_H
+#define E_BOOK_SHELL_CONTENT_H
+
+#include <libebook/e-contact.h>
+
+#include "shell/e-shell-content.h"
+#include "shell/e-shell-view.h"
+
+#include "addressbook/gui/component/eab-composer-util.h"
+#include "addressbook/gui/widgets/e-addressbook-view.h"
+
+/* Standard GObject macros */
+#define E_TYPE_BOOK_SHELL_CONTENT \
+ (e_book_shell_content_get_type ())
+#define E_BOOK_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContent))
+#define E_BOOK_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentClass))
+#define E_IS_BOOK_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_BOOK_SHELL_CONTENT))
+#define E_IS_BOOK_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_BOOK_SHELL_CONTENT))
+#define E_BOOK_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_BOOK_SHELL_CONTENT, EBookShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EBookShellContent EBookShellContent;
+typedef struct _EBookShellContentClass EBookShellContentClass;
+typedef struct _EBookShellContentPrivate EBookShellContentPrivate;
+
+enum {
+ E_BOOK_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
+ E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
+ E_BOOK_SHELL_CONTENT_SELECTION_HAS_EMAIL = 1 << 2,
+ E_BOOK_SHELL_CONTENT_SELECTION_IS_CONTACT_LIST = 1 << 3,
+ E_BOOK_SHELL_CONTENT_SELECTION_HAS_HTTP_URI = 1 << 4,
+ E_BOOK_SHELL_CONTENT_SELECTION_HAS_MAILTO_URI = 1 << 5,
+ E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY = 1 << 6,
+ E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE = 1 << 7,
+ E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY = 1 << 8
+};
+
+struct _EBookShellContent {
+ EShellContent parent;
+ EBookShellContentPrivate *priv;
+};
+
+struct _EBookShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_book_shell_content_get_type (void);
+void e_book_shell_content_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_book_shell_content_new(EShellView *shell_view);
+void e_book_shell_content_insert_view
+ (EBookShellContent *book_shell_content,
+ EAddressbookView *addressbook_view);
+void e_book_shell_content_remove_view
+ (EBookShellContent *book_shell_content,
+ EAddressbookView *addressbook_view);
+EAddressbookView *
+ e_book_shell_content_get_current_view
+ (EBookShellContent *book_shell_content);
+void e_book_shell_content_set_current_view
+ (EBookShellContent *book_shell_content,
+ EAddressbookView *addressbook_view);
+EContact * e_book_shell_content_get_preview_contact
+ (EBookShellContent *book_shell_content);
+void e_book_shell_content_set_preview_contact
+ (EBookShellContent *book_shell_content,
+ EContact *preview_contact);
+gboolean e_book_shell_content_get_preview_visible
+ (EBookShellContent *book_shell_content);
+void e_book_shell_content_set_preview_visible
+ (EBookShellContent *book_shell_content,
+ gboolean preview_visible);
+void e_book_shell_content_clipboard_copy
+ (EBookShellContent *book_shell_content);
+
+G_END_DECLS
+
+#endif /* E_BOOK_SHELL_CONTENT_H */
diff --cc addressbook/gui/component/e-book-shell-migrate.c
index 08ade1f,0000000..2c9aa6a
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-migrate.c
+++ b/addressbook/gui/component/e-book-shell-migrate.c
@@@ -1,1230 -1,0 +1,1230 @@@
+/*
+ * e-book-shell-backend-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok <toshok ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include <libebook/e-destination.h>
+#include <libebook/e-book.h>
+#include <glib/gi18n.h>
+
+#include <libedataserver/e-xml-utils.h>
+
+#include "e-util/e-util.h"
+#include "e-util/e-util-private.h"
+#include "e-util/e-xml-utils.h"
+#include "e-util/e-folder-map.h"
+
+#include "e-book-shell-migrate.h"
+
+/*#define SLOW_MIGRATION*/
+
+typedef struct {
+ /* this hash table maps old folder uris to new uids. It's
+ build in migrate_contact_folder and it's used in
+ migrate_completion_folders. */
+ GHashTable *folder_uid_map;
+
+ ESourceList *source_list;
+
+ const gchar *data_dir;
+
+ GtkWidget *window;
+ GtkWidget *label;
+ GtkWidget *folder_label;
+ GtkWidget *progress;
+} MigrationContext;
+
+static void
+setup_progress_dialog (MigrationContext *context)
+{
+ GtkWidget *vbox, *hbox;
+
+ context->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (context->window), _("Migrating..."));
+ gtk_window_set_modal (GTK_WINDOW (context->window), TRUE);
+ gtk_container_set_border_width (GTK_CONTAINER (context->window), 6);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_container_add (GTK_CONTAINER (context->window), vbox);
+
+ context->label = gtk_label_new ("");
+ gtk_label_set_line_wrap (GTK_LABEL (context->label), TRUE);
+ gtk_widget_show (context->label);
+ gtk_box_pack_start (GTK_BOX (vbox), context->label, TRUE, TRUE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+
+ context->folder_label = gtk_label_new ("");
+ gtk_widget_show (context->folder_label);
+ gtk_box_pack_start (GTK_BOX (hbox), context->folder_label, TRUE, TRUE, 0);
+
+ context->progress = gtk_progress_bar_new ();
+ gtk_widget_show (context->progress);
+ gtk_box_pack_start (GTK_BOX (hbox), context->progress, TRUE, TRUE, 0);
+
+ gtk_widget_show (context->window);
+}
+
+static void
+dialog_close (MigrationContext *context)
+{
+ gtk_widget_destroy (context->window);
+}
+
+static void
+dialog_set_label (MigrationContext *context, const char *str)
+{
+ gtk_label_set_text (GTK_LABEL (context->label), str);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+#ifdef SLOW_MIGRATION
+ sleep (1);
+#endif
+}
+
+static void
+dialog_set_folder_name (MigrationContext *context, const char *folder_name)
+{
+ char *text;
+
+ text = g_strdup_printf (_("Migrating '%s':"), folder_name);
+ gtk_label_set_text (GTK_LABEL (context->folder_label), text);
+ g_free (text);
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (context->progress), 0.0);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+#ifdef SLOW_MIGRATION
+ sleep (1);
+#endif
+}
+
+static void
+dialog_set_progress (MigrationContext *context, double percent)
+{
+ char text[5];
+
+ snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f));
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (context->progress), percent);
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (context->progress), text);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+#ifdef SLOW_MIGRATION
+ sleep (1);
+#endif
+}
+
+static gboolean
+check_for_conflict (ESourceGroup *group, char *name)
+{
+ GSList *sources;
+ GSList *s;
+
+ sources = e_source_group_peek_sources (group);
+
+ for (s = sources; s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+
+ if (!strcmp (e_source_peek_name (source), name))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static char *
+get_source_name (ESourceGroup *group, const char *path)
+{
+#ifndef G_OS_WIN32
+ char **p = g_strsplit (path, "/", 0);
+#else
+ char **p = g_strsplit_set (path, "\\/", 0);
+#endif
+ int i, j, starting_index;
+ int num_elements;
+ gboolean conflict;
+ GString *s = g_string_new ("");
+
+ for (i = 0; p[i]; i ++) ;
+
+ num_elements = i;
+ i--;
+
+ /* p[i] is now the last path element */
+
+ /* check if it conflicts */
+ starting_index = i;
+ do {
+ g_string_assign (s, "");
+ for (j = starting_index; j < num_elements; j += 2) {
+ if (j != starting_index)
+ g_string_append_c (s, '_');
+ g_string_append (s, p[j]);
+ }
+
+ conflict = check_for_conflict (group, s->str);
+
+
+ /* if there was a conflict back up 2 levels (skipping the /subfolder/ element) */
+ if (conflict)
+ starting_index -= 2;
+
+ /* we always break out if we can't go any further,
+ regardless of whether or not we conflict. */
+ if (starting_index < 0)
+ break;
+
+ } while (conflict);
+
+ g_strfreev (p);
+
+ return g_string_free (s, FALSE);
+}
+
+static void
+migrate_contacts (MigrationContext *context, EBook *old_book, EBook *new_book)
+{
+ EBookQuery *query = e_book_query_any_field_contains ("");
+ GList *l, *contacts;
+ int num_added = 0;
+ int num_contacts;
+
+ /* both books are loaded, start the actual migration */
+ e_book_get_contacts (old_book, query, &contacts, NULL);
+ e_book_query_unref (query);
+
+ num_contacts = g_list_length (contacts);
+ for (l = contacts; l; l = l->next) {
+ EContact *contact = l->data;
+ GError *e = NULL;
+ GList *attrs, *attr;
+
+ /* do some last minute massaging of the contact's attributes */
+
+ attrs = e_vcard_get_attributes (E_VCARD (contact));
+ for (attr = attrs; attr;) {
+ EVCardAttribute *a = attr->data;
+
+ /* evo 1.4 used the non-standard X-EVOLUTION-OFFICE attribute,
+ evo 1.5 uses the third element in the ORG list attribute. */
+ if (!strcmp ("X-EVOLUTION-OFFICE", e_vcard_attribute_get_name (a))) {
+ GList *v = e_vcard_attribute_get_values (a);
+ GList *next_attr;
+
+ if (v && v->data)
+ e_contact_set (contact, E_CONTACT_OFFICE, v->data);
+
+ next_attr = attr->next;
+ e_vcard_remove_attribute (E_VCARD (contact), a);
+ attr = next_attr;
+ }
+ /* evo 1.4 didn't put TYPE=VOICE in for phone numbers.
+ evo 1.5 does.
+
+ so we search through the attribute params for
+ either TYPE=VOICE or TYPE=FAX. If we find
+ either we do nothing. If we find neither, we
+ add TYPE=VOICE.
+ */
+ else if (!strcmp ("TEL", e_vcard_attribute_get_name (a))) {
+ GList *params, *param;
+ gboolean found = FALSE;
+
+ params = e_vcard_attribute_get_params (a);
+ for (param = params; param; param = param->next) {
+ EVCardAttributeParam *p = param->data;
+ if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) {
+ GList *v = e_vcard_attribute_param_get_values (p);
+ while (v && v->data) {
+ if (!strcmp ("VOICE", v->data)
+ || !strcmp ("FAX", v->data)) {
+ found = TRUE;
+ break;
+ }
+ v = v->next;
+ }
+ }
+ }
+
+ if (!found)
+ e_vcard_attribute_add_param_with_value (a,
+ e_vcard_attribute_param_new (EVC_TYPE),
+ "VOICE");
+ attr = attr->next;
+ }
+ /* Replace "POSTAL" (1.4) addresses with "OTHER" (1.5) */
+ else if (!strcmp ("ADR", e_vcard_attribute_get_name (a))) {
+ GList *params, *param;
+ gboolean found = FALSE;
+ EVCardAttributeParam *p;
+
+ params = e_vcard_attribute_get_params (a);
+ for (param = params; param; param = param->next) {
+ p = param->data;
+ if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) {
+ GList *v = e_vcard_attribute_param_get_values (p);
+ while (v && v->data ) {
+ if (!strcmp ("POSTAL", v->data)) {
+ found = TRUE;
+ break;
+ }
+ v = v->next;
+ }
+ if (found)
+ break;
+ }
+ }
+
+ if (found) {
+ e_vcard_attribute_param_remove_values (p);
+ e_vcard_attribute_param_add_value (p, "OTHER");
+ }
+
+ attr = attr->next;
+ }
+ /* this is kinda gross. The new vcard parser
+ needs ';'s to be escaped by \'s. but the
+ 1.4 vcard generator would put unescaped xml
+ (including entities like >) in the value
+ of attributes, so we need to go through and
+ escape those ';'s. */
+ else if (!strcmp ("EMAIL", e_vcard_attribute_get_name (a))) {
+ GList *params;
+ GList *v = e_vcard_attribute_get_values (a);
+
+ /* Add TYPE=OTHER if there is no type set */
+ params = e_vcard_attribute_get_params (a);
+ if (!params)
+ e_vcard_attribute_add_param_with_value (a,
+ e_vcard_attribute_param_new (EVC_TYPE),
+ "OTHER");
+
+ if (v && v->data) {
+ if (!strncmp ((char*)v->data, "<?xml", 5)) {
+ /* k, this is the nasty part. we glomb all the
+ value strings back together again (if there is
+ more than one), then work our magic */
+ GString *str = g_string_new ("");
+ while (v) {
+ g_string_append (str, v->data);
+ if (v->next)
+ g_string_append_c (str, ';');
+ v = v->next;
+ }
+
+ e_vcard_attribute_remove_values (a);
+ e_vcard_attribute_add_value (a, str->str);
+ g_string_free (str, TRUE);
+ }
+ }
+
+ attr = attr->next;
+ }
+ else {
+ attr = attr->next;
+ }
+ }
+
+ if (!e_book_add_contact (new_book,
+ contact,
+ &e))
+ g_warning ("contact add failed: `%s'", e->message);
+
+ num_added ++;
+
+ dialog_set_progress (context, (double)num_added / num_contacts);
+ }
+
+ g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
+ g_list_free (contacts);
+}
+
+static void
+migrate_contact_folder_to_source (MigrationContext *context, char *old_path, ESource *new_source)
+{
+ char *old_uri = g_filename_to_uri (old_path, NULL, NULL);
+ GError *e = NULL;
+
+ EBook *old_book = NULL, *new_book = NULL;
+ ESource *old_source;
+ ESourceGroup *group;
+
+ group = e_source_group_new ("", old_uri);
+ old_source = e_source_new ("", "");
+ e_source_group_add_source (group, old_source, -1);
+
+ dialog_set_folder_name (context, e_source_peek_name (new_source));
+
+ old_book = e_book_new (old_source, &e);
+ if (!old_book
+ || !e_book_open (old_book, TRUE, &e)) {
+ g_warning ("failed to load source book for migration: `%s'", e->message);
+ goto finish;
+ }
+
+ new_book = e_book_new (new_source, &e);
+ if (!new_book
+ || !e_book_open (new_book, FALSE, &e)) {
+ g_warning ("failed to load destination book for migration: `%s'", e->message);
+ goto finish;
+ }
+
+ migrate_contacts (context, old_book, new_book);
+
+ finish:
+ g_object_unref (old_source);
+ g_object_unref (group);
+ if (old_book)
+ g_object_unref (old_book);
+ if (new_book)
+ g_object_unref (new_book);
+ g_free (old_uri);
+}
+
+static void
+migrate_contact_folder (MigrationContext *context, char *old_path, ESourceGroup *dest_group, char *source_name)
+{
+ ESource *new_source;
+
+ new_source = e_source_new (source_name, source_name);
+ e_source_set_relative_uri (new_source, e_source_peek_uid (new_source));
+ e_source_group_add_source (dest_group, new_source, -1);
+
+ g_hash_table_insert (context->folder_uid_map, g_strdup (old_path), g_strdup (e_source_peek_uid (new_source)));
+
+ migrate_contact_folder_to_source (context, old_path, new_source);
+
+ g_object_unref (new_source);
+}
+
+#define LDAP_BASE_URI "ldap://"
+#define PERSONAL_RELATIVE_URI "system"
+
+static void
+create_groups (MigrationContext *context,
+ ESourceGroup **on_this_computer,
+ ESourceGroup **on_ldap_servers,
+ ESource **personal_source)
+{
+ GSList *groups;
+ ESourceGroup *group;
+ char *base_uri, *base_uri_proto;
+
+ *on_this_computer = NULL;
+ *on_ldap_servers = NULL;
+ *personal_source = NULL;
+
+ base_uri = g_build_filename (context->data_dir, "local", NULL);
+
+ base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL);
+
+ groups = e_source_list_peek_groups (context->source_list);
+ if (groups) {
+ /* groups are already there, we need to search for things... */
+ GSList *g;
+
+ for (g = groups; g; g = g->next) {
+
+ group = E_SOURCE_GROUP (g->data);
+
+ if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
+ *on_this_computer = g_object_ref (group);
+ else if (!*on_ldap_servers && !strcmp (LDAP_BASE_URI, e_source_group_peek_base_uri (group)))
+ *on_ldap_servers = g_object_ref (group);
+ }
+ }
+
+ if (*on_this_computer) {
+ /* make sure "Personal" shows up as a source under
+ this group */
+ GSList *sources = e_source_group_peek_sources (*on_this_computer);
+ GSList *s;
+ for (s = sources; s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (relative_uri == NULL)
+ continue;
+ if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) {
+ *personal_source = g_object_ref (source);
+ break;
+ }
+ }
+ }
+ else {
+ /* create the local source group */
+ group = e_source_group_new (_("On This Computer"), base_uri_proto);
+ e_source_list_add_group (context->source_list, group, -1);
+
+ *on_this_computer = group;
+ }
+
+ if (!*personal_source) {
+ /* Create the default Person addressbook */
+ ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
+ e_source_group_add_source (*on_this_computer, source, -1);
+
+ e_source_set_property (source, "completion", "true");
+
+ *personal_source = source;
+ }
+
+ if (!*on_ldap_servers) {
+ /* Create the LDAP source group */
+ group = e_source_group_new (_("On LDAP Servers"), LDAP_BASE_URI);
+ e_source_list_add_group (context->source_list, group, -1);
+
+ *on_ldap_servers = group;
+ }
+
+ g_free (base_uri_proto);
+ g_free (base_uri);
+}
+
+static gboolean
+migrate_local_folders (MigrationContext *context, ESourceGroup *on_this_computer, ESource *personal_source)
+{
+ char *old_path = NULL;
+ GSList *dirs, *l;
+ char *local_contact_folder = NULL;
+
+ old_path = g_strdup_printf ("%s/evolution/local", g_get_home_dir ());
+
+ dirs = e_folder_map_local_folders (old_path, "contacts");
+
+ /* migrate the local addressbook first, to local/system */
+ local_contact_folder = g_build_filename (g_get_home_dir (),
+ "evolution", "local", "Contacts",
+ NULL);
+
+ for (l = dirs; l; l = l->next) {
+ char *source_name;
+ /* we handle the system folder differently */
+ if (personal_source && !strcmp ((char*)l->data, local_contact_folder)) {
+ g_hash_table_insert (context->folder_uid_map, g_strdup (l->data), g_strdup (e_source_peek_uid (personal_source)));
+ migrate_contact_folder_to_source (context, local_contact_folder, personal_source);
+ continue;
+ }
+
+ source_name = get_source_name (on_this_computer, (char*)l->data);
+ migrate_contact_folder (context, l->data, on_this_computer, source_name);
+ g_free (source_name);
+ }
+
+ g_slist_foreach (dirs, (GFunc)g_free, NULL);
+ g_slist_free (dirs);
+ g_free (local_contact_folder);
+ g_free (old_path);
+
+ return TRUE;
+}
+
+static char *
+get_string_child (xmlNode *node,
+ const char *name)
+{
+ xmlNode *p;
+ xmlChar *xml_string;
+ char *retval;
+
+ p = e_xml_get_child_by_name (node, (xmlChar *) name);
+ if (p == NULL)
+ return NULL;
+
+ p = e_xml_get_child_by_name (p, (xmlChar *) "text");
+ if (p == NULL) /* there's no text between the tags, return the empty string */
+ return g_strdup("");
+
+ xml_string = xmlNodeListGetString (node->doc, p, 1);
+ retval = g_strdup ((char *) xml_string);
+ xmlFree (xml_string);
+
+ return retval;
+}
+
+static int
+get_integer_child (xmlNode *node,
+ const char *name,
+ int defval)
+{
+ xmlNode *p;
+ xmlChar *xml_string;
+ int retval;
+
+ p = e_xml_get_child_by_name (node, (xmlChar *) name);
+ if (p == NULL)
+ return defval;
+
+ p = e_xml_get_child_by_name (p, (xmlChar *) "text");
+ if (p == NULL) /* there's no text between the tags, return the default */
+ return defval;
+
+ xml_string = xmlNodeListGetString (node->doc, p, 1);
+ retval = atoi ((char *)xml_string);
+ xmlFree (xml_string);
+
+ return retval;
+}
+
+static gboolean
+migrate_ldap_servers (MigrationContext *context, ESourceGroup *on_ldap_servers)
+{
+ char *sources_xml = g_strdup_printf ("%s/evolution/addressbook-sources.xml",
+ g_get_home_dir ());
+
+ printf ("trying to migrate from %s\n", sources_xml);
+
+ if (g_file_test (sources_xml, G_FILE_TEST_EXISTS)) {
+ xmlDoc *doc = xmlParseFile (sources_xml);
+ xmlNode *root;
+ xmlNode *child;
+ int num_contactservers;
+ int servernum;
+
+ if (!doc)
+ return FALSE;
+
+ root = xmlDocGetRootElement (doc);
+ if (root == NULL || strcmp ((const char *)root->name, "addressbooks") != 0) {
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ /* count the number of servers, so we can give progress */
+ num_contactservers = 0;
+ for (child = root->children; child; child = child->next) {
+ if (!strcmp ((const char *)child->name, "contactserver")) {
+ num_contactservers++;
+ }
+ }
+ printf ("found %d contact servers to migrate\n", num_contactservers);
+
+ dialog_set_folder_name (context, _("LDAP Servers"));
+
+ servernum = 0;
+ for (child = root->children; child; child = child->next) {
+ if (!strcmp ((const char *)child->name, "contactserver")) {
+ char *port, *host, *rootdn, *scope, *authmethod, *ssl;
+ char *emailaddr, *binddn, *limitstr;
+ int limit;
+ char *name, *description;
+ GString *uri = g_string_new ("");
+ ESource *source;
+
+ name = get_string_child (child, "name");
+ description = get_string_child (child, "description");
+ port = get_string_child (child, "port");
+ host = get_string_child (child, "host");
+ rootdn = get_string_child (child, "rootdn");
+ scope = get_string_child (child, "scope");
+ authmethod = get_string_child (child, "authmethod");
+ ssl = get_string_child (child, "ssl");
+ emailaddr = get_string_child (child, "emailaddr");
+ binddn = get_string_child (child, "binddn");
+ limit = get_integer_child (child, "limit", 100);
+ limitstr = g_strdup_printf ("%d", limit);
+
+ g_string_append_printf (uri,
+ "%s:%s/%s?"/*trigraph prevention*/"?%s",
+ host, port, rootdn, scope);
+
+ source = e_source_new (name, uri->str);
+ e_source_set_property (source, "description", description);
+ e_source_set_property (source, "limit", limitstr);
+ e_source_set_property (source, "ssl", ssl);
+ e_source_set_property (source, "auth", authmethod);
+ if (emailaddr)
+ e_source_set_property (source, "email_addr", emailaddr);
+ if (binddn)
+ e_source_set_property (source, "binddn", binddn);
+
+ e_source_group_add_source (on_ldap_servers, source, -1);
+
+ g_string_free (uri, TRUE);
+ g_free (port);
+ g_free (host);
+ g_free (rootdn);
+ g_free (scope);
+ g_free (authmethod);
+ g_free (ssl);
+ g_free (emailaddr);
+ g_free (binddn);
+ g_free (limitstr);
+ g_free (name);
+ g_free (description);
+
+ servernum++;
+ dialog_set_progress (context, (double)servernum/num_contactservers);
+ }
+ }
+
+ xmlFreeDoc (doc);
+ }
+
+ g_free (sources_xml);
+
+ return TRUE;
+}
+
+static ESource*
+get_source_by_name (ESourceList *source_list, const char *name)
+{
+ GSList *groups;
+ GSList *g;
+
+ groups = e_source_list_peek_groups (source_list);
+ if (!groups)
+ return NULL;
+
+ for (g = groups; g; g = g->next) {
+ GSList *sources;
+ GSList *s;
+ ESourceGroup *group = E_SOURCE_GROUP (g->data);
+
+ sources = e_source_group_peek_sources (group);
+ if (!sources)
+ continue;
+
+ for (s = sources; s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+ const char *source_name = e_source_peek_name (source);
+
+ if (!strcmp (name, source_name))
+ return source;
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+migrate_completion_folders (MigrationContext *context)
+{
+ GConfClient *client;
+ const gchar *key;
+ gchar *uris_xml;
+
+ printf ("trying to migrate completion folders\n");
+
+ client = gconf_client_get_default ();
+ key = "/apps/evolution/addressbook/completion/uris";
+ uris_xml = gconf_client_get_string (client, key, NULL);
+ g_object_unref (client);
+
+ if (uris_xml) {
+ xmlDoc *doc = xmlParseMemory (uris_xml, strlen (uris_xml));
+ xmlNode *root;
+ xmlNode *child;
+
+ if (!doc)
+ return FALSE;
+
+ dialog_set_folder_name (context, _("Autocompletion Settings"));
+
+ root = xmlDocGetRootElement (doc);
+ if (root == NULL || strcmp ((const char *)root->name, "EvolutionFolderList") != 0) {
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ for (child = root->children; child; child = child->next) {
+ if (!strcmp ((const char *)child->name, "folder")) {
+ char *physical_uri = e_xml_get_string_prop_by_name (child, (const unsigned char *)"physical-uri");
+ ESource *source = NULL;
+
+ /* if the physical uri is file://...
+ we look it up in our folder_uid_map
+ hashtable. If it's a folder we
+ converted over, we should get back
+ a uid we can search for.
+
+ if the physical_uri is anything
+ else, we strip off the args
+ (anything after ;) before searching
+ for the uri. */
+
+ if (!strncmp (physical_uri, "file://", 7)) {
+ char *filename = g_filename_from_uri (physical_uri, NULL, NULL);
+ char *uid = NULL;
+
+ if (filename)
+ uid = g_hash_table_lookup (context->folder_uid_map,
+ filename);
+ g_free (filename);
+ if (uid)
+ source = e_source_list_peek_source_by_uid (context->source_list, uid);
+ }
+ else {
+ char *name = e_xml_get_string_prop_by_name (child, (const unsigned char *)"display-name");
+
+ source = get_source_by_name (context->source_list, name);
+
+ g_free (name);
+ }
+
+ if (source) {
+ e_source_set_property (source, "completion", "true");
+ }
+ else {
+ g_warning ("found completion folder with uri `%s' that "
+ "doesn't correspond to anything we migrated.", physical_uri);
+ }
+
+ g_free (physical_uri);
+ }
+ }
+
+ g_free (uris_xml);
+ }
+ else {
+ g_message ("no completion folder settings to migrate");
+ }
+
+ return TRUE;
+}
+
+static void
+migrate_contact_lists_for_local_folders (MigrationContext *context, ESourceGroup *on_this_computer)
+{
+ GSList *sources, *s;
+
+ sources = e_source_group_peek_sources (on_this_computer);
+ for (s = sources; s; s = s->next) {
+ ESource *source = s->data;
+ EBook *book;
+ EBookQuery *query;
+ GList *l, *contacts;
+ int num_contacts, num_converted;
+
+ dialog_set_folder_name (context, e_source_peek_name (source));
+
+ book = e_book_new (source, NULL);
+ if (!book
+ || !e_book_open (book, TRUE, NULL)) {
+ char *uri = e_source_get_uri (source);
+ g_warning ("failed to migrate contact lists for source %s", uri);
+ g_free (uri);
+ continue;
+ }
+
+ query = e_book_query_any_field_contains ("");
+ e_book_get_contacts (book, query, &contacts, NULL);
+ e_book_query_unref (query);
+
+ num_converted = 0;
+ num_contacts = g_list_length (contacts);
+ for (l = contacts; l; l = l->next) {
+ EContact *contact = l->data;
+ GError *e = NULL;
+ GList *attrs, *attr;
+ gboolean converted = FALSE;
+
+ attrs = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
+ for (attr = attrs; attr; attr = attr->next) {
+ EVCardAttribute *a = attr->data;
+ GList *v = e_vcard_attribute_get_values (a);
+
+ if (v && v->data) {
+ if (!strncmp ((char*)v->data, "<?xml", 5)) {
+ EDestination *dest = e_destination_import ((char*)v->data);
+
+ e_destination_export_to_vcard_attribute (dest, a);
+
+ g_object_unref (dest);
+
+ converted = TRUE;
+ }
+ }
+ }
+
+ if (converted) {
+ e_contact_set_attributes (contact, E_CONTACT_EMAIL, attrs);
+
+ if (!e_book_commit_contact (book,
+ contact,
+ &e))
+ g_warning ("contact commit failed: `%s'", e->message);
+ }
+
+ num_converted ++;
+
+ dialog_set_progress (context, (double)num_converted / num_contacts);
+ }
+
+ g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
+ g_list_free (contacts);
+
+ g_object_unref (book);
+ }
+}
+
+static void
+migrate_company_phone_for_local_folders (MigrationContext *context, ESourceGroup *on_this_computer)
+{
+ GSList *sources, *s;
+
+ sources = e_source_group_peek_sources (on_this_computer);
+ for (s = sources; s; s = s->next) {
+ ESource *source = s->data;
+ EBook *book;
+ EBookQuery *query;
+ GList *l, *contacts;
+ int num_contacts, num_converted;
+
+ dialog_set_folder_name (context, e_source_peek_name (source));
+
+ book = e_book_new (source, NULL);
+ if (!book
+ || !e_book_open (book, TRUE, NULL)) {
+ char *uri = e_source_get_uri (source);
+ g_warning ("failed to migrate company phone numbers for source %s", uri);
+ g_free (uri);
+ continue;
+ }
+
+ query = e_book_query_any_field_contains ("");
+ e_book_get_contacts (book, query, &contacts, NULL);
+ e_book_query_unref (query);
+
+ num_converted = 0;
+ num_contacts = g_list_length (contacts);
+ for (l = contacts; l; l = l->next) {
+ EContact *contact = l->data;
+ GError *e = NULL;
+ GList *attrs, *attr;
+ gboolean converted = FALSE;
+ int num_work_voice = 0;
+
+ attrs = e_vcard_get_attributes (E_VCARD (contact));
+ for (attr = attrs; attr;) {
+ EVCardAttribute *a = attr->data;
+ GList *next_attr = attr->next;
+
+ if (!strcmp ("TEL", e_vcard_attribute_get_name (a))) {
+ GList *params, *param;
+ gboolean found_voice = FALSE;
+ gboolean found_work = FALSE;
+
+ params = e_vcard_attribute_get_params (a);
+ for (param = params; param; param = param->next) {
+ EVCardAttributeParam *p = param->data;
+ if (!strcmp (EVC_TYPE, e_vcard_attribute_param_get_name (p))) {
+ GList *v = e_vcard_attribute_param_get_values (p);
+ while (v && v->data) {
+ if (!strcmp ("VOICE", v->data))
+ found_voice = TRUE;
+ else if (!strcmp ("WORK", v->data))
+ found_work = TRUE;
+ v = v->next;
+ }
+ }
+
+ if (found_work && found_voice)
+ num_work_voice++;
+
+ if (num_work_voice == 3) {
+ GList *v = e_vcard_attribute_get_values (a);
+
+ if (v && v->data)
+ e_contact_set (contact, E_CONTACT_PHONE_COMPANY, v->data);
+
+ e_vcard_remove_attribute (E_VCARD (contact), a);
+
+ converted = TRUE;
+ break;
+ }
+ }
+ }
+
+ attr = next_attr;
+
+ if (converted)
+ break;
+ }
+
+ if (converted) {
+ if (!e_book_commit_contact (book,
+ contact,
+ &e))
+ g_warning ("contact commit failed: `%s'", e->message);
+ }
+
+ num_converted ++;
+
+ dialog_set_progress (context, (double)num_converted / num_contacts);
+ }
+
+ g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
+ g_list_free (contacts);
+
+ g_object_unref (book);
+ }
+}
+
+static void
+migrate_pilot_data (const char *old_path, const char *new_path)
+{
+ const char *dent;
+ const char *ext;
+ char *filename;
+ GDir *dir;
+
+ if (!(dir = g_dir_open (old_path, 0, NULL)))
+ return;
+
+ while ((dent = g_dir_read_name (dir))) {
+ if ((!strncmp (dent, "pilot-map-", 10) &&
+ ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) ||
+ (!strncmp (dent, "pilot-sync-evolution-addressbook-", 33) &&
+ ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db")))) {
+ /* src and dest file formats are identical for both map and changelog files */
+ unsigned char inbuf[4096];
+ size_t nread, nwritten;
+ int fd0, fd1;
+ ssize_t n;
+
+ filename = g_build_filename (old_path, dent, NULL);
+ if ((fd0 = g_open (filename, O_RDONLY | O_BINARY, 0)) == -1) {
+ g_free (filename);
+ continue;
+ }
+
+ g_free (filename);
+ filename = g_build_filename (new_path, dent, NULL);
+ if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) {
+ g_free (filename);
+ close (fd0);
+ continue;
+ }
+
+ do {
+ do {
+ n = read (fd0, inbuf, sizeof (inbuf));
+ } while (n == -1 && errno == EINTR);
+
+ if (n < 1)
+ break;
+
+ nread = n;
+ nwritten = 0;
+ do {
+ do {
+ n = write (fd1, inbuf + nwritten, nread - nwritten);
+ } while (n == -1 && errno == EINTR);
+
+ if (n > 0)
+ nwritten += n;
+ } while (nwritten < nread && n != -1);
+
+ if (n == -1)
+ break;
+ } while (1);
+
+ if (n != -1)
+ n = fsync (fd1);
+
+ if (n == -1) {
+ g_warning ("Failed to migrate %s: %s", dent, g_strerror (errno));
+ g_unlink (filename);
+ }
+
+ close (fd0);
+ close (fd1);
+ g_free (filename);
+ }
+ }
+
+ g_dir_close (dir);
+}
+
+static MigrationContext *
+migration_context_new (const gchar *data_dir)
+{
+ MigrationContext *context = g_new (MigrationContext, 1);
+
+ /* set up the mapping from old uris to new uids */
+ context->folder_uid_map = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ e_book_get_addressbooks (&context->source_list, NULL);
+
+ context->data_dir = data_dir;
+
+ return context;
+}
+
+static void
+migration_context_free (MigrationContext *context)
+{
+ e_source_list_sync (context->source_list, NULL);
+
+ g_hash_table_destroy (context->folder_uid_map);
+
+ g_object_unref (context->source_list);
+
+ g_free (context);
+}
+
+gboolean
+e_book_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ ESourceGroup *on_this_computer;
+ ESourceGroup *on_ldap_servers;
+ ESource *personal_source;
+ MigrationContext *context;
+ gboolean need_dialog = FALSE;
+ const gchar *data_dir;
+
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE);
+
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ context = migration_context_new (data_dir);
+
+ /* we call this unconditionally now - create_groups either
+ creates the groups/sources or it finds the necessary
+ groups/sources. */
+ create_groups (context, &on_this_computer, &on_ldap_servers, &personal_source);
+
+ /* figure out if we need the dialog displayed */
+ if (major == 1
+ /* we only need the most recent upgrade point here.
+ further decomposition will happen below. */
+ && (minor < 5 || (minor == 5 && micro <= 10)))
+ need_dialog = TRUE;
+
+ if (need_dialog)
+ setup_progress_dialog (context);
+
+ if (major == 1) {
+
+ if (minor < 5 || (minor == 5 && micro <= 2)) {
+ /* initialize our dialog */
+ dialog_set_label (context,
+ _("The location and hierarchy of the Evolution contact "
+ "folders has changed since Evolution 1.x.\n\nPlease be "
+ "patient while Evolution migrates your folders..."));
+
+ if (on_this_computer)
+ migrate_local_folders (context, on_this_computer, personal_source);
+ if (on_ldap_servers)
+ migrate_ldap_servers (context, on_ldap_servers);
+
+ migrate_completion_folders (context);
+ }
+
+ if (minor < 5 || (minor == 5 && micro <= 7)) {
+ dialog_set_label (context,
+ _("The format of mailing list contacts has changed.\n\n"
+ "Please be patient while Evolution migrates your "
+ "folders..."));
+
+ migrate_contact_lists_for_local_folders (context, on_this_computer);
+ }
+
+ if (minor < 5 || (minor == 5 && micro <= 8)) {
+ dialog_set_label (context,
+ _("The way Evolution stores some phone numbers has changed.\n\n"
+ "Please be patient while Evolution migrates your "
+ "folders..."));
+
+ migrate_company_phone_for_local_folders (context, on_this_computer);
+ }
+
+ if (minor < 5 || (minor == 5 && micro <= 10)) {
+ char *old_path, *new_path;
+
+ dialog_set_label (context, _("Evolution's Palm Sync changelog and map files have changed.\n\n"
+ "Please be patient while Evolution migrates your Pilot Sync data..."));
+
+ old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Contacts", NULL);
+ new_path = g_build_filename (data_dir, "local", "system", NULL);
+ migrate_pilot_data (old_path, new_path);
+ g_free (new_path);
+ g_free (old_path);
+ }
+
+ /* we only need to do this next step if people ran
+ older versions of 1.5. We need to clear out the
+ absolute URI's that were assigned to ESources
+ during one phase of development, as they take
+ precedent over relative uris (but aren't updated
+ when editing an ESource). */
+ if (minor == 5 && micro <= 11) {
+ GSList *g;
+ for (g = e_source_list_peek_groups (context->source_list); g; g = g->next) {
+ ESourceGroup *group = g->data;
+ GSList *s;
+
+ for (s = e_source_group_peek_sources (group); s; s = s->next) {
+ ESource *source = s->data;
+ e_source_set_absolute_uri (source, NULL);
+ }
+ }
+ }
+ }
+
+ if (need_dialog)
+ dialog_close (context);
+
+ if (on_this_computer)
+ g_object_unref (on_this_computer);
+ if (on_ldap_servers)
+ g_object_unref (on_ldap_servers);
+ if (personal_source)
+ g_object_unref (personal_source);
+
+
+ migration_context_free (context);
+
+ return TRUE;
+}
diff --cc addressbook/gui/component/e-book-shell-migrate.h
index f631ef6,0000000..cb61289
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-migrate.h
+++ b/addressbook/gui/component/e-book-shell-migrate.h
@@@ -1,41 -1,0 +1,41 @@@
+/*
+ * e-book-shell-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Toshok (toshok ximian com)
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_BOOK_SHELL_MIGRATE_H
+#define E_BOOK_SHELL_MIGRATE_H
+
+#include <glib.h>
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_book_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_BOOK_SHELL_MIGRATE_H */
diff --cc addressbook/gui/component/e-book-shell-sidebar.c
index 2a784e3,0000000..fc283e2
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-sidebar.c
+++ b/addressbook/gui/component/e-book-shell-sidebar.c
@@@ -1,232 -1,0 +1,232 @@@
+/*
+ * e-book-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-book-shell-sidebar.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-book-shell-view.h"
+#include "e-book-shell-backend.h"
+#include "e-addressbook-selector.h"
+
+#define E_BOOK_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarPrivate))
+
+struct _EBookShellSidebarPrivate {
+ GtkWidget *selector;
+};
+
+enum {
+ PROP_0,
+ PROP_SELECTOR
+};
+
+static gpointer parent_class;
+static GType book_shell_sidebar_type;
+
+static void
+book_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SELECTOR:
+ g_value_set_object (
+ value, e_book_shell_sidebar_get_selector (
+ E_BOOK_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+book_shell_sidebar_dispose (GObject *object)
+{
+ EBookShellSidebarPrivate *priv;
+
+ priv = E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->selector != NULL) {
+ g_object_unref (priv->selector);
+ priv->selector = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+book_shell_sidebar_constructed (GObject *object)
+{
+ EBookShellSidebarPrivate *priv;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellSidebar *shell_sidebar;
+ ESourceList *source_list;
+ GtkContainer *container;
+ GtkWidget *widget;
+
+ priv = E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ source_list = e_book_shell_backend_get_source_list (
+ E_BOOK_SHELL_BACKEND (shell_backend));
+
+ container = GTK_CONTAINER (shell_sidebar);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (container, widget);
+ gtk_widget_show (widget);
+
+ container = GTK_CONTAINER (widget);
+
+ widget = e_addressbook_selector_new (source_list);
+ e_source_selector_show_selection (E_SOURCE_SELECTOR (widget), FALSE);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->selector = g_object_ref (widget);
+ gtk_widget_show (widget);
+}
+
+static guint32
+book_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ EBookShellSidebar *book_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *source;
+ gboolean is_system = FALSE;
+ guint32 state = 0;
+
+ book_shell_sidebar = E_BOOK_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_book_shell_sidebar_get_selector (book_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+
+ if (source != NULL) {
+ const gchar *uri;
+
+ uri = e_source_peek_relative_uri (source);
+ is_system = (uri == NULL || strcmp (uri, "system") == 0);
+ }
+
+ if (source != NULL)
+ state |= E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
+ if (is_system)
+ state |= E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM;
+
+ return state;
+}
+
+static void
+book_shell_sidebar_class_init (EBookShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EBookShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = book_shell_sidebar_get_property;
+ object_class->dispose = book_shell_sidebar_dispose;
+ object_class->constructed = book_shell_sidebar_constructed;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = book_shell_sidebar_check_state;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTOR,
+ g_param_spec_object (
+ "selector",
+ _("Source Selector Widget"),
+ _("This widget displays groups of address books"),
+ E_TYPE_SOURCE_SELECTOR,
+ G_PARAM_READABLE));
+}
+
+static void
+book_shell_sidebar_init (EBookShellSidebar *book_shell_sidebar)
+{
+ book_shell_sidebar->priv =
+ E_BOOK_SHELL_SIDEBAR_GET_PRIVATE (book_shell_sidebar);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_book_shell_sidebar_get_type (void)
+{
+ return book_shell_sidebar_type;
+}
+
+void
+e_book_shell_sidebar_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EBookShellSidebarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) book_shell_sidebar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EBookShellSidebar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) book_shell_sidebar_init,
+ NULL /* value_table */
+ };
+
+ book_shell_sidebar_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_SIDEBAR,
+ "EBookShellSidebar", &type_info, 0);
+}
+
+GtkWidget *
+e_book_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_BOOK_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+ESourceSelector *
+e_book_shell_sidebar_get_selector (EBookShellSidebar *book_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_BOOK_SHELL_SIDEBAR (book_shell_sidebar), NULL);
+
+ return E_SOURCE_SELECTOR (book_shell_sidebar->priv->selector);
+}
diff --cc addressbook/gui/component/e-book-shell-sidebar.h
index e2523f5,0000000..716523f
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-sidebar.h
+++ b/addressbook/gui/component/e-book-shell-sidebar.h
@@@ -1,79 -1,0 +1,79 @@@
+/*
+ * e-book-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_BOOK_SHELL_SIDEBAR_H
+#define E_BOOK_SHELL_SIDEBAR_H
+
+#include <libedataserverui/e-source-selector.h>
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_BOOK_SHELL_SIDEBAR \
+ (e_book_shell_sidebar_get_type ())
+#define E_BOOK_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebar))
+#define E_BOOK_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarClass))
+#define E_IS_BOOK_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_BOOK_SHELL_SIDEBAR))
+#define E_IS_BOOK_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_BOOK_SHELL_SIDEBAR))
+#define E_BOOK_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_BOOK_SHELL_SIDEBAR, EBookShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EBookShellSidebar EBookShellSidebar;
+typedef struct _EBookShellSidebarClass EBookShellSidebarClass;
+typedef struct _EBookShellSidebarPrivate EBookShellSidebarPrivate;
+
+enum {
+ E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
+ E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM = 1 << 1
+};
+
+struct _EBookShellSidebar {
+ EShellSidebar parent;
+ EBookShellSidebarPrivate *priv;
+};
+
+struct _EBookShellSidebarClass {
+ EShellSidebarClass parent_class;
+};
+
+GType e_book_shell_sidebar_get_type (void);
+void e_book_shell_sidebar_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_book_shell_sidebar_new(EShellView *shell_view);
+ESourceSelector *
+ e_book_shell_sidebar_get_selector
+ (EBookShellSidebar *book_shell_sidebar);
+
+G_END_DECLS
+
+#endif /* E_BOOK_SHELL_SIDEBAR_H */
diff --cc addressbook/gui/component/e-book-shell-view-actions.c
index 918ff57,0000000..35d0e8f
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view-actions.c
+++ b/addressbook/gui/component/e-book-shell-view-actions.c
@@@ -1,982 -1,0 +1,982 @@@
+/*
+ * e-book-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-book-shell-view-private.h"
+
+#include <e-util/e-error.h>
+#include <e-util/e-util.h>
+#include <filter/filter-rule.h>
+
+#include <addressbook-config.h>
+
+static void
+action_address_book_copy_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_copy_to_folder (view, TRUE);
+}
+
+static void
+action_address_book_delete_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EBookShellBackend *book_shell_backend;
+ EBookShellSidebar *book_shell_sidebar;
+ ESource *source;
+ ESourceSelector *selector;
+ ESourceGroup *source_group;
+ ESourceList *source_list;
+ EBook *book;
+ gint response;
+ GError *error = NULL;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ book_shell_backend = book_shell_view->priv->book_shell_backend;
+ source_list = e_book_shell_backend_get_source_list (book_shell_backend);
+
+ book_shell_sidebar = book_shell_view->priv->book_shell_sidebar;
+ selector = e_book_shell_sidebar_get_selector (book_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ response = e_error_run (
+ GTK_WINDOW (shell_window),
+ "addressbook:ask-delete-addressbook",
+ e_source_peek_name (source));
+
+ if (response != GTK_RESPONSE_YES)
+ return;
+
+ book = e_book_new (source, &error);
+ if (error != NULL) {
+ g_warning ("Error removing addressbook: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (!e_book_remove (book, NULL)) {
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "addressbook:remove-addressbook", NULL);
+ g_object_unref (book);
+ return;
+ }
+
+ if (e_source_selector_source_is_selected (selector, source))
+ e_source_selector_unselect_source (selector, source);
+
+ source_group = e_source_peek_group (source);
+ e_source_group_remove_source (source_group, source);
+
+ e_source_list_sync (source_list, NULL);
+
+ g_object_unref (book);
+}
+
+static void
+action_address_book_move_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_move_to_folder (view, TRUE);
+}
+
+static void
+action_address_book_new_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ addressbook_config_create_new_source (GTK_WIDGET (shell_window));
+}
+
+static void
+action_address_book_properties_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EBookShellSidebar *book_shell_sidebar;
+ ESource *source;
+ ESourceSelector *selector;
+ EditorUidClosure *closure;
+ GHashTable *uid_to_editor;
+ const gchar *uid;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ book_shell_sidebar = book_shell_view->priv->book_shell_sidebar;
+ selector = e_book_shell_sidebar_get_selector (book_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (source != NULL);
+
+ uid = e_source_peek_uid (source);
+ uid_to_editor = book_shell_view->priv->uid_to_editor;
+
+ closure = g_hash_table_lookup (uid_to_editor, uid);
+ if (closure == NULL) {
+ GtkWidget *editor;
+
+ editor = addressbook_config_edit_source (
+ GTK_WIDGET (shell_window), source);
+
+ closure = g_new (EditorUidClosure, 1);
+ closure->editor = editor;
+ closure->uid = g_strdup (uid);
+ closure->view = book_shell_view;
+
+ g_hash_table_insert (uid_to_editor, closure->uid, closure);
+
+ g_object_weak_ref (
+ G_OBJECT (closure->editor), (GWeakNotify)
+ e_book_shell_view_editor_weak_notify, closure);
+ }
+
+ gtk_window_present (GTK_WINDOW (closure->editor));
+}
+
+static void
+action_address_book_rename_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellSidebar *book_shell_sidebar;
+ ESourceSelector *selector;
+
+ book_shell_sidebar = book_shell_view->priv->book_shell_sidebar;
+ selector = e_book_shell_sidebar_get_selector (book_shell_sidebar);
+
+ e_source_selector_edit_primary_selection (selector);
+}
+
+static void
+action_address_book_save_as_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_save_as (view, TRUE);
+}
+
+static void
+action_address_book_stop_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_stop (view);
+}
+
+static void
+action_contact_clipboard_copy_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ e_book_shell_content_clipboard_copy (book_shell_content);
+}
+
+static void
+action_contact_clipboard_cut_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_cut (view);
+}
+
+static void
+action_contact_clipboard_paste_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_paste (view);
+}
+
+static void
+action_contact_copy_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_copy_to_folder (view, FALSE);
+}
+
+static void
+action_contact_delete_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_delete_selection (view, TRUE);
+}
+
+static void
+action_contact_forward_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ GList *list, *iter;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ list = e_addressbook_view_get_selected (view);
+ g_return_if_fail (list != NULL);
+
+ /* Convert the list of contacts to a list of destinations. */
+ for (iter = list; iter != NULL; iter = iter->next) {
+ EContact *contact = iter->data;
+ EDestination *destination;
+
+ destination = e_destination_new ();
+ e_destination_set_contact (destination, contact, 0);
+ g_object_unref (contact);
+
+ iter->data = destination;
+ }
+
+ eab_send_as_attachment (list);
+ g_list_foreach (list, (GFunc) g_object_unref, NULL);
+ g_list_free (list);
+}
+
+static void
+action_contact_move_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_move_to_folder (view, FALSE);
+}
+
+static void
+action_contact_new_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ EAddressbookModel *model;
+ EContact *contact;
+ GtkWidget *editor;
+ EBook *book;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ model = e_addressbook_view_get_model (view);
+ book = e_addressbook_model_get_book (model);
+ g_return_if_fail (book != NULL);
+
+ contact = e_contact_new ();
+ editor = e_contact_editor_new (book, contact, TRUE, TRUE);
+ eab_editor_show (EAB_EDITOR (editor));
+ g_object_unref (contact);
+}
+
+static void
+action_contact_new_list_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ EAddressbookModel *model;
+ EContact *contact;
+ GtkWidget *editor;
+ EBook *book;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ model = e_addressbook_view_get_model (view);
+ book = e_addressbook_model_get_book (model);
+ g_return_if_fail (book != NULL);
+
+ contact = e_contact_new ();
+ editor = e_contact_list_editor_new (book, contact, TRUE, TRUE);
+ eab_editor_show (EAB_EDITOR (editor));
+ g_object_unref (contact);
+}
+
+static void
+action_contact_open_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_view (view);
+}
+
+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_print_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ GtkPrintOperationAction print_action;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ e_addressbook_view_print (view, print_action);
+}
+
+static void
+action_contact_print_preview_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ GtkPrintOperationAction print_action;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
+ e_addressbook_view_print (view, print_action);
+}
+
+static void
+action_contact_save_as_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_save_as (view, FALSE);
+}
+
+static void
+action_contact_select_all_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ e_addressbook_view_select_all (view);
+}
+
+static void
+action_contact_send_message_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ GList *list, *iter;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ g_return_if_fail (view != NULL);
+
+ list = e_addressbook_view_get_selected (view);
+ g_return_if_fail (list != NULL);
+
+ /* Convert the list of contacts to a list of destinations. */
+ for (iter = list; iter != NULL; iter = iter->next) {
+ EContact *contact = iter->data;
+ EDestination *destination;
+
+ destination = e_destination_new ();
+ e_destination_set_contact (destination, contact, 0);
+ g_object_unref (contact);
+
+ iter->data = destination;
+ }
+
+ eab_send_as_to (list);
+ g_list_foreach (list, (GFunc) g_object_unref, NULL);
+ g_list_free (list);
+}
+
+static void
+action_gal_save_custom_view_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EShellView *shell_view;
+ EAddressbookView *address_view;
+ GalViewInstance *view_instance;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with saving the custom view. */
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ 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);
+ gal_view_instance_save_as (view_instance);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+ EBookShellView *book_shell_view)
+{
+ EShellView *shell_view;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with executing the search. */
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ e_book_shell_view_execute_search (book_shell_view);
+}
+
+static void
+action_search_filter_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EBookShellView *book_shell_view)
+{
+ e_book_shell_view_execute_search (book_shell_view);
+}
+
+static GtkActionEntry contact_entries[] = {
+
+ { "address-book-copy",
+ GTK_STOCK_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",
+ GTK_STOCK_DELETE,
+ N_("Del_ete Address Book"),
+ NULL,
+ N_("Delete the selected address book"),
+ G_CALLBACK (action_address_book_delete_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",
+ GTK_STOCK_PROPERTIES,
+ N_("Address _Book Properties"),
+ NULL,
+ N_("Show properties of the selected address book"),
+ G_CALLBACK (action_address_book_properties_cb) },
+
+ { "address-book-rename",
+ NULL,
+ N_("_Rename..."),
+ "F2",
+ N_("Rename the selected address book"),
+ G_CALLBACK (action_address_book_rename_cb) },
+
+ { "address-book-save-as",
+ GTK_STOCK_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) },
+
+ { "address-book-stop",
+ GTK_STOCK_STOP,
+ NULL,
+ NULL,
+ N_("Stop loading"),
+ G_CALLBACK (action_address_book_stop_cb) },
+
+ { "contact-clipboard-copy",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy the selection"),
+ G_CALLBACK (action_contact_clipboard_copy_cb) },
+
+ { "contact-clipboard-cut",
+ GTK_STOCK_CUT,
+ NULL,
+ NULL,
+ N_("Cut the selection"),
+ G_CALLBACK (action_contact_clipboard_cut_cb) },
+
+ { "contact-clipboard-paste",
+ GTK_STOCK_PASTE,
+ NULL,
+ NULL,
+ N_("Paste the clipboard"),
+ G_CALLBACK (action_contact_clipboard_paste_cb) },
+
+ { "contact-copy",
+ NULL,
+ N_("_Copy Contact To..."),
+ "<Control><Shift>y",
+ N_("Copy selected contacts to another address book"),
+ G_CALLBACK (action_contact_copy_cb) },
+
+ { "contact-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete Contact"),
+ "<Control>d",
+ N_("Delete selected contacts"),
+ G_CALLBACK (action_contact_delete_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..."),
+ "<Control><Shift>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"),
+ "<Control>o",
+ N_("View the current contact"),
+ G_CALLBACK (action_contact_open_cb) },
+
+ { "contact-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("Save as vCard..."),
+ NULL,
+ N_("Save selected contacts as a vCard"),
+ G_CALLBACK (action_contact_save_as_cb) },
+
+ { "contact-select-all",
+ GTK_STOCK_SELECT_ALL,
+ NULL,
+ NULL,
+ N_("Select all contacts"),
+ G_CALLBACK (action_contact_select_all_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 ***/
+
+ { "actions-menu",
+ NULL,
+ N_("_Actions"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry contact_popup_entries[] = {
+
+ { "address-book-popup-delete",
+ N_("_Delete"),
+ "address-book-delete" },
+
+ { "address-book-popup-properties",
+ N_("_Properties"),
+ "address-book-properties" },
+
+ { "address-book-popup-rename",
+ NULL,
+ "address-book-rename" },
+
+ { "address-book-popup-save-as",
+ N_("_Save as vCard..."),
+ "address-book-save-as" },
+
+ { "contact-popup-clipboard-copy",
+ NULL,
+ "contact-clipboard-copy" },
+
+ { "contact-popup-clipboard-cut",
+ NULL,
+ "contact-clipboard-cut" },
+
+ { "contact-popup-clipboard-paste",
+ NULL,
+ "contact-clipboard-paste" },
+
+ { "contact-popup-copy",
+ NULL,
+ "contact-copy" },
+
+ { "contact-popup-delete",
+ NULL,
+ "contact-delete" },
+
+ { "contact-popup-forward",
+ NULL,
+ "contact-forward" },
+
+ { "contact-popup-move",
+ NULL,
+ "contact-move" },
+
+ { "contact-popup-open",
+ NULL,
+ "contact-open" },
+
+ { "contact-popup-save-as",
+ NULL,
+ "contact-save-as" },
+
+ { "contact-popup-send-message",
+ NULL,
+ "contact-send-message" },
+};
+
+static GtkToggleActionEntry contact_toggle_entries[] = {
+
+ { "contact-preview",
+ NULL,
+ N_("Contact _Preview"),
+ "<Control>m",
+ N_("Show contact preview window"),
+ G_CALLBACK (action_contact_preview_cb),
+ TRUE }
+};
+
+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-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-name-contains",
+ NULL,
+ N_("Name contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CONTACT_SEARCH_NAME_CONTAINS }
+};
+
+static GtkActionEntry lockdown_printing_entries[] = {
+
+ { "contact-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print selected contacts"),
+ G_CALLBACK (action_contact_print_cb) },
+
+ { "contact-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ NULL,
+ N_("Preview the contacts to be printed"),
+ G_CALLBACK (action_contact_print_preview_cb) }
+};
+
+static EPopupActionEntry lockdown_printing_popup_entries[] = {
+
+ { "contact-popup-print",
+ NULL,
+ "contact-print" }
+};
+
+void
+e_book_shell_view_actions_init (EBookShellView *book_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+ GConfBridge *bridge;
+ GtkAction *action;
+ GObject *object;
+ const gchar *key;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ shell_window = e_shell_view_get_shell_window (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_search_entries,
+ G_N_ELEMENTS (contact_search_entries),
+ CONTACT_SEARCH_NAME_CONTAINS,
+ NULL, NULL);
+
+ /* 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));
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (ACTION (CONTACT_PREVIEW));
+ key = "/apps/evolution/addressbook/display/show_preview";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ /* Fine tuning. */
+
+ action = ACTION (CONTACT_DELETE);
+ g_object_set (action, "short-label", _("Delete"), NULL);
+
+ g_signal_connect (
+ ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
+ G_CALLBACK (action_gal_save_custom_view_cb), book_shell_view);
+
+ g_signal_connect (
+ ACTION (SEARCH_EXECUTE), "activate",
+ G_CALLBACK (action_search_execute_cb), book_shell_view);
+}
+
+void
+e_book_shell_view_update_search_filter (EBookShellView *book_shell_view)
+{
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GList *list, *iter;
+ GSList *group;
+ gint ii;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ shell_content = e_shell_view_get_shell_content (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);
+
+ /* Add the standard filter actions. */
+ gtk_action_group_add_radio_actions (
+ action_group, contact_filter_entries,
+ G_N_ELEMENTS (contact_filter_entries),
+ CONTACT_FILTER_ANY_CATEGORY,
+ G_CALLBACK (action_search_filter_cb),
+ book_shell_view);
+
+ /* 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);
+
+ /* Build the category actions. */
+
+ list = e_categories_get_list ();
+ for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+ const gchar *category_name = iter->data;
+ const gchar *filename;
+ GtkAction *action;
+ gchar *action_name;
+
+ 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);
+
+ /* Convert the category icon file to a themed icon name. */
+ filename = e_categories_get_icon_file_for (category_name);
+ if (filename != NULL && *filename != '\0') {
+ gchar *basename;
+ gchar *cp;
+
+ basename = g_path_get_basename (filename);
+
+ /* Lose the file extension. */
+ if ((cp = strrchr (basename, '.')) != NULL)
+ *cp = '\0';
+
+ g_object_set (
+ radio_action, "icon-name", basename, NULL);
+
+ g_free (basename);
+ }
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_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_list_free (list);
+
+ /* Use any action in the group; doesn't matter which. */
+ e_shell_content_set_filter_action (shell_content, radio_action);
+
+ ii = CONTACT_FILTER_UNMATCHED;
+ e_shell_content_add_filter_separator_after (shell_content, ii);
+}
diff --cc addressbook/gui/component/e-book-shell-view-actions.h
index 503855d,0000000..8e3d31f
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view-actions.h
+++ b/addressbook/gui/component/e-book-shell-view-actions.h
@@@ -1,91 -1,0 +1,91 @@@
+/*
+ * e-book-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_BOOK_SHELL_VIEW_ACTIONS_H
+#define E_BOOK_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* 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_PROPERTIES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "address-book-properties")
+#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")
+
+/* Contact Actions */
+#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-copy")
+#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_CUT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-cut")
+#define E_SHELL_WINDOW_ACTION_CONTACT_CLIPBOARD_PASTE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-clipboard-paste")
+#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_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_PRINT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-print")
+#define E_SHELL_WINDOW_ACTION_CONTACT_PRINT_PREVIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-print-preview")
+#define E_SHELL_WINDOW_ACTION_CONTACT_SAVE_AS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-save-as")
+#define E_SHELL_WINDOW_ACTION_CONTACT_SELECT_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-select-all")
+#define E_SHELL_WINDOW_ACTION_CONTACT_SEND_MESSAGE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-send-message")
+
+/* Search Actions */
+#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_NAME_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contact-search-name-contains")
+
+/* 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")
+
+#endif /* E_BOOK_SHELL_VIEW_ACTIONS_H */
diff --cc addressbook/gui/component/e-book-shell-view-private.c
index cdb8c8f,0000000..ec3562e
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view-private.c
+++ b/addressbook/gui/component/e-book-shell-view-private.c
@@@ -1,621 -1,0 +1,621 @@@
+/*
+ * e-book-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-book-shell-view-private.h"
+
+#include "widgets/menus/gal-view-factory-etable.h"
+#include "addressbook/gui/widgets/gal-view-factory-minicard.h"
+
+#include "addressbook.h"
+
+static void
+open_contact (EBookShellView *book_shell_view,
+ EContact *contact,
+ gboolean is_new_contact,
+ EAddressbookView *view)
+{
+ EAddressbookModel *model;
+ GtkWidget *editor;
+ EBook *book;
+ gboolean editable;
+
+ model = e_addressbook_view_get_model (view);
+ book = e_addressbook_model_get_book (model);
+ editable = e_addressbook_model_get_editable (model);
+
+ if (e_contact_get (contact, E_CONTACT_IS_LIST))
+ editor = e_contact_list_editor_new (
+ book, contact, is_new_contact, editable);
+ else
+ editor = e_contact_editor_new (
+ book, contact, is_new_contact, editable);
+
+ eab_editor_show (EAB_EDITOR (editor));
+}
+
+static void
+popup_event (EBookShellView *book_shell_view,
+ GdkEventButton *event)
+{
+ EShellView *shell_view;
+ const gchar *widget_path;
+
+ widget_path = "/contact-popup";
+ shell_view = E_SHELL_VIEW (book_shell_view);
+
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+}
+
+static void
+book_shell_view_selection_change_foreach (gint row,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ EAddressbookModel *model;
+ EContact *contact;
+
+ /* XXX A "foreach" function is kind of a silly way to retrieve
+ * the one and only selected contact, but this is the only
+ * means that ESelectionModel provides. */
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ model = e_addressbook_view_get_model (view);
+ contact = e_addressbook_model_get_contact (model, row);
+
+ e_book_shell_content_set_preview_contact (book_shell_content, contact);
+}
+
+static void
+selection_change (EBookShellView *book_shell_view,
+ EAddressbookView *view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *current_view;
+ ESelectionModel *selection_model;
+ EShellView *shell_view;
+ gint n_selected;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ current_view = e_book_shell_content_get_current_view (book_shell_content);
+
+ if (view != current_view)
+ return;
+
+ e_shell_view_update_actions (shell_view);
+
+ selection_model = e_addressbook_view_get_selection_model (view);
+
+ n_selected = (selection_model != NULL) ?
+ e_selection_model_selected_count (selection_model) : 0;
+
+ if (n_selected == 1)
+ e_selection_model_foreach (
+ selection_model, (EForeachFunc)
+ book_shell_view_selection_change_foreach,
+ book_shell_view);
+ else
+ e_book_shell_content_set_preview_contact (
+ book_shell_content, NULL);
+}
+
+static void
+contact_changed (EBookShellView *book_shell_view,
+ EContact *contact)
+{
+ EBookShellContent *book_shell_content;
+ EContact *preview_contact;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+
+ preview_contact =
+ e_book_shell_content_get_preview_contact (book_shell_content);
+
+ if (contact != preview_contact)
+ return;
+
+ /* Re-render the same contact. */
+ e_book_shell_content_set_preview_contact (book_shell_content, contact);
+}
+
+static void
+contacts_removed (EBookShellView *book_shell_view,
+ GArray *removed_indices,
+ EAddressbookModel *model)
+{
+ EBookShellContent *book_shell_content;
+ EContact *preview_contact;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+
+ preview_contact =
+ e_book_shell_content_get_preview_contact (book_shell_content);
+
+ if (preview_contact == NULL)
+ return;
+
+ /* Is the displayed contact still in the model? */
+ if (e_addressbook_model_find (model, preview_contact) < 0)
+ return;
+
+ /* If not, clear the contact display. */
+ e_book_shell_content_set_preview_contact (book_shell_content, NULL);
+}
+
+static void
+book_open_cb (EBook *book,
+ EBookStatus status,
+ gpointer user_data)
+{
+ EAddressbookView *view = user_data;
+ EAddressbookModel *model;
+ ESource *source;
+
+ source = e_book_get_source (book);
+ model = e_addressbook_view_get_model (view);
+
+ if (status == E_BOOK_ERROR_OK) {
+ e_addressbook_model_set_book (model, book);
+ e_addressbook_model_force_folder_bar_message (model);
+ } else if (status != E_BOOK_ERROR_CANCELLED)
+ eab_load_error_dialog (NULL /* XXX */, source, status);
+}
+
+static void
+book_shell_view_activate_selected_source (EBookShellView *book_shell_view,
+ ESourceSelector *selector)
+{
+ EShellView *shell_view;
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ EAddressbookModel *model;
+ ESource *source;
+ GalViewInstance *view_instance;
+ GHashTable *hash_table;
+ GtkWidget *widget;
+ const gchar *uid;
+ gchar *view_id;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ source = e_source_selector_peek_primary_selection (selector);
+
+ if (source == NULL)
+ return;
+
+ uid = e_source_peek_uid (source);
+ hash_table = book_shell_view->priv->uid_to_view;
+ widget = g_hash_table_lookup (hash_table, uid);
+
+ if (widget != NULL) {
+ EBook *book;
+
+ /* There is a view for this UID. Make sure the view
+ * actually contains an EBook. The absence of an EBook
+ * suggests a previous load failed, so try again. */
+ view = E_ADDRESSBOOK_VIEW (widget);
+ model = e_addressbook_view_get_model (view);
+ source = e_addressbook_view_get_source (view);
+
+ if (e_addressbook_model_get_book (model) == NULL) {
+ book = e_book_new (source, NULL);
+
+ if (book != NULL)
+ addressbook_load (book, book_open_cb, view);
+ }
+
+ } else {
+ EBook *book;
+
+ /* Create a view for this UID. */
+ widget = e_addressbook_view_new (shell_view, source);
+ gtk_widget_show (widget);
+
+ e_book_shell_content_insert_view (
+ book_shell_content,
+ E_ADDRESSBOOK_VIEW (widget));
+
+ g_hash_table_insert (
+ hash_table, g_strdup (uid),
+ g_object_ref (widget));
+
+ g_signal_connect_swapped (
+ widget, "open-contact",
+ G_CALLBACK (open_contact), book_shell_view);
+
+ g_signal_connect_swapped (
+ widget, "popup-event",
+ G_CALLBACK (popup_event), book_shell_view);
+
+ g_signal_connect_swapped (
+ widget, "command-state-change",
+ G_CALLBACK (e_shell_view_update_actions),
+ book_shell_view);
+
+ g_signal_connect_swapped (
+ widget, "selection-change",
+ G_CALLBACK (selection_change), book_shell_view);
+
+ book = e_book_new (source, NULL);
+ view = E_ADDRESSBOOK_VIEW (widget);
+
+ if (book != NULL)
+ addressbook_load (book, book_open_cb, view);
+
+ model = e_addressbook_view_get_model (view);
+
+ g_signal_connect_swapped (
+ model, "contact-changed",
+ G_CALLBACK (contact_changed), book_shell_view);
+
+ g_signal_connect_swapped (
+ model, "contacts-removed",
+ G_CALLBACK (contacts_removed), book_shell_view);
+ }
+
+ e_book_shell_content_set_current_view (
+ book_shell_content, E_ADDRESSBOOK_VIEW (widget));
+
+ /* XXX We have to keep the addressbook selector informed of the
+ * current view so it can move contacts via drag-and-drop. */
+ e_addressbook_selector_set_current_view (
+ E_ADDRESSBOOK_SELECTOR (selector),
+ E_ADDRESSBOOK_VIEW (widget));
+
+ view_instance = e_addressbook_view_get_view_instance (view);
+ view_id = gal_view_instance_get_current_view_id (view_instance);
+ e_shell_view_set_view_id (shell_view, view_id);
+ g_free (view_id);
+
+ e_addressbook_model_force_folder_bar_message (model);
+ selection_change (book_shell_view, view);
+}
+
+static gboolean
+book_shell_view_show_popup_menu (GdkEventButton *event,
+ EShellView *shell_view)
+{
+ const gchar *widget_path;
+
+ widget_path = "/address-book-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+
+ return TRUE;
+}
+
+static gboolean
+book_shell_view_selector_button_press_event_cb (EShellView *shell_view,
+ GdkEventButton *event)
+{
+ /* XXX Use ESourceSelector's "popup-event" signal instead. */
+
+ if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+ return book_shell_view_show_popup_menu (event, shell_view);
+
+ return FALSE;
+}
+
+static gboolean
+book_shell_view_selector_popup_menu_cb (EShellView *shell_view)
+{
+ /* XXX Use ESourceSelector's "popup-event" signal instead. */
+
+ return book_shell_view_show_popup_menu (NULL, shell_view);
+}
+
+static gboolean
+book_shell_view_selector_key_press_event_cb (EShellView *shell_view,
+ GdkEventKey *event)
+{
+ EShellWindow *shell_window;
+
+ /* Needed for the ACTION() macro. */
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (event->keyval == GDK_Delete) {
+ gtk_action_activate (ACTION (ADDRESS_BOOK_DELETE));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+book_shell_view_load_view_collection (EShellViewClass *shell_view_class)
+{
+ GalViewCollection *collection;
+ GalViewFactory *factory;
+ ETableSpecification *spec;
+ const gchar *base_dir;
+ gchar *filename;
+
+ collection = shell_view_class->view_collection;
+
+ base_dir = EVOLUTION_ETSPECDIR;
+ spec = e_table_specification_new ();
+ filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
+ if (!e_table_specification_load_from_file (spec, filename))
+ g_critical ("Unable to load ETable specification file "
+ "for address book");
+ g_free (filename);
+
+ factory = gal_view_factory_etable_new (spec);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+ g_object_unref (spec);
+
+ factory = gal_view_factory_minicard_new ();
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+
+ gal_view_collection_load (collection);
+}
+
+static void
+book_shell_view_notify_view_id_cb (EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *address_view;
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ 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);
+ view_id = e_shell_view_get_view_id (E_SHELL_VIEW (book_shell_view));
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_book_shell_view_private_init (EBookShellView *book_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+ GHashTable *uid_to_view;
+ GHashTable *uid_to_editor;
+
+ uid_to_view = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ uid_to_editor = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ priv->uid_to_view = uid_to_view;
+ priv->uid_to_editor = uid_to_editor;
+
+ if (!gal_view_collection_loaded (shell_view_class->view_collection))
+ book_shell_view_load_view_collection (shell_view_class);
+
+ g_signal_connect (
+ book_shell_view, "notify::view-id",
+ G_CALLBACK (book_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_book_shell_view_private_constructed (EBookShellView *book_shell_view)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceSelector *selector;
+
+ shell_view = E_SHELL_VIEW (book_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);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ e_shell_window_add_action_group (shell_window, "contacts");
+ e_shell_window_add_action_group (shell_window, "contacts-filter");
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->book_shell_backend = g_object_ref (shell_backend);
+ priv->book_shell_content = g_object_ref (shell_content);
+ priv->book_shell_sidebar = g_object_ref (shell_sidebar);
+
+ selector = e_book_shell_sidebar_get_selector (
+ E_BOOK_SHELL_SIDEBAR (shell_sidebar));
+
+ g_signal_connect_swapped (
+ selector, "button-press-event",
+ G_CALLBACK (book_shell_view_selector_button_press_event_cb),
+ book_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "key-press-event",
+ G_CALLBACK (book_shell_view_selector_key_press_event_cb),
+ book_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "popup-menu",
+ G_CALLBACK (book_shell_view_selector_popup_menu_cb),
+ book_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "primary-selection-changed",
+ G_CALLBACK (book_shell_view_activate_selected_source),
+ book_shell_view);
+
+ e_categories_register_change_listener (
+ G_CALLBACK (e_book_shell_view_update_search_filter),
+ book_shell_view);
+
+ e_book_shell_view_actions_init (book_shell_view);
+ book_shell_view_activate_selected_source (book_shell_view, selector);
+ e_book_shell_view_update_search_filter (book_shell_view);
+}
+
+void
+e_book_shell_view_private_dispose (EBookShellView *book_shell_view)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+
+ DISPOSE (priv->book_shell_backend);
+ DISPOSE (priv->book_shell_content);
+ DISPOSE (priv->book_shell_sidebar);
+
+ g_hash_table_remove_all (priv->uid_to_view);
+ g_hash_table_remove_all (priv->uid_to_editor);
+}
+
+void
+e_book_shell_view_private_finalize (EBookShellView *book_shell_view)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+
+ g_hash_table_destroy (priv->uid_to_view);
+ g_hash_table_destroy (priv->uid_to_editor);
+}
+
+void
+e_book_shell_view_execute_search (EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ GtkAction *action;
+ GString *string;
+ EAddressbookView *view;
+ EAddressbookModel *model;
+ FilterRule *rule;
+ const gchar *format;
+ const gchar *text;
+ gchar *query;
+ gchar *temp;
+ gint value;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ text = e_shell_content_get_search_text (shell_content);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ action = ACTION (CONTACT_SEARCH_ANY_FIELD_CONTAINS);
+ value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+
+ if (text == NULL || *text == '\0') {
+ text = "";
+ value = CONTACT_SEARCH_ANY_FIELD_CONTAINS;
+ }
+
+ switch (value) {
+ case CONTACT_SEARCH_NAME_CONTAINS:
+ format = "(contains \"full_name\" %s)";
+ break;
+
+ case CONTACT_SEARCH_EMAIL_BEGINS_WITH:
+ format = "(beginswith \"email\" %s)";
+ break;
+
+ default:
+ text = "";
+ /* fall through */
+
+ case CONTACT_SEARCH_ANY_FIELD_CONTAINS:
+ format = "(contains \"x-evolution-any-field\" %s)";
+ break;
+ }
+
+ /* Build the query. */
+ string = g_string_new ("");
+ e_sexp_encode_string (string, text);
+ query = g_strdup_printf (format, string->str);
+ g_string_free (string, TRUE);
+
+ /* Apply selected filter. */
+ value = e_shell_content_get_filter_value (shell_content);
+ switch (value) {
+ case CONTACT_FILTER_ANY_CATEGORY:
+ break;
+
+ case CONTACT_FILTER_UNMATCHED:
+ temp = g_strdup_printf (
+ "(and (not (and (exists \"CATEGORIES\") "
+ "(not (is \"CATEGORIES\" \"\")))) %s)",
+ query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ {
+ GList *categories;
+ const gchar *category_name;
+
+ categories = e_categories_get_list ();
+ category_name = g_list_nth_data (categories, value);
+ g_list_free (categories);
+
+ temp = g_strdup_printf (
+ "(and (is \"category_list\" \"%s\") %s)",
+ category_name, query);
+ g_free (query);
+ query = temp;
+ }
+ }
+
+ /* XXX This is wrong. We need to programmatically construct a
+ * FilterRule, tell it to build code, and pass the resulting
+ * expression string to EAddressbookModel. */
+ rule = filter_rule_new ();
+ e_shell_content_set_search_rule (shell_content, rule);
+ g_object_unref (rule);
+
+ /* Submit the query. */
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ model = e_addressbook_view_get_model (view);
+ e_addressbook_model_set_query (model, query);
+ g_free (query);
+
+ e_book_shell_content_set_preview_contact (book_shell_content, NULL);
+}
+
+void
+e_book_shell_view_editor_weak_notify (EditorUidClosure *closure,
+ GObject *where_the_object_was)
+{
+ GHashTable *hash_table;
+
+ hash_table = closure->view->priv->uid_to_editor;
+ g_hash_table_remove (hash_table, closure->uid);
+}
diff --cc addressbook/gui/component/e-book-shell-view-private.h
index 628c1c2,0000000..b4701ae
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view-private.h
+++ b/addressbook/gui/component/e-book-shell-view-private.h
@@@ -1,129 -1,0 +1,129 @@@
+/*
+ * e-book-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_BOOK_SHELL_VIEW_PRIVATE_H
+#define E_BOOK_SHELL_VIEW_PRIVATE_H
+
+#include "e-book-shell-view.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <libebook/e-book.h>
+#include <libedataserver/e-categories.h>
+#include <libedataserver/e-sexp.h>
+#include <libedataserverui/e-source-selector.h>
+
+#include "e-util/gconf-bridge.h"
+#include "shell/e-shell-content.h"
+#include "shell/e-shell-sidebar.h"
+#include "misc/e-popup-action.h"
+
+#include "addressbook/gui/contact-editor/e-contact-editor.h"
+#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
+#include "addressbook/gui/widgets/eab-gui-util.h"
+#include "addressbook/gui/widgets/e-addressbook-view.h"
+#include "addressbook/gui/widgets/e-addressbook-selector.h"
+
+#include "e-book-shell-backend.h"
+#include "e-book-shell-content.h"
+#include "e-book-shell-sidebar.h"
+#include "e-book-shell-view-actions.h"
+
+#define E_BOOK_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* For use in dispose() methods. */
+#define DISPOSE(obj) \
+ G_STMT_START { \
+ if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
+ } G_STMT_END
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "e-addressbook-view.etspec"
+
+G_BEGIN_DECLS
+
+typedef struct _EditorUidClosure EditorUidClosure;
+
+struct _EditorUidClosure {
+ GtkWidget *editor;
+ gchar *uid;
+ EBookShellView *view;
+};
+
+/* List these in the order to be displayed.
+ * Positive values are reserved for categories. */
+enum {
+ CONTACT_FILTER_ANY_CATEGORY = -2,
+ CONTACT_FILTER_UNMATCHED = -1
+};
+
+/* List these in the order to be displayed. */
+enum {
+ CONTACT_SEARCH_NAME_CONTAINS,
+ CONTACT_SEARCH_EMAIL_BEGINS_WITH,
+ CONTACT_SEARCH_ANY_FIELD_CONTAINS
+};
+
+struct _EBookShellViewPrivate {
+
+ /* These are just for convenience. */
+ EBookShellBackend *book_shell_backend;
+ EBookShellContent *book_shell_content;
+ EBookShellSidebar *book_shell_sidebar;
+
+ GHashTable *uid_to_view;
+ GHashTable *uid_to_editor;
+};
+
+void e_book_shell_view_private_init
+ (EBookShellView *book_shell_view,
+ EShellViewClass *shell_view_class);
+void e_book_shell_view_private_constructed
+ (EBookShellView *book_shell_view);
+void e_book_shell_view_private_dispose
+ (EBookShellView *book_shell_view);
+void e_book_shell_view_private_finalize
+ (EBookShellView *book_shell_view);
+
+/* Private Utilities */
+
+void e_book_shell_view_actions_init
+ (EBookShellView *book_shell_view);
+void e_book_shell_view_execute_search
+ (EBookShellView *book_shell_view);
+void e_book_shell_view_editor_weak_notify
+ (EditorUidClosure *closure,
+ GObject *where_the_object_was);
+void e_book_shell_view_update_search_filter
+ (EBookShellView *book_shell_view);
+
+G_END_DECLS
+
+#endif /* E_BOOK_SHELL_VIEW_PRIVATE_H */
diff --cc addressbook/gui/component/e-book-shell-view.c
index 44c06be,0000000..ea48bb5
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view.c
+++ b/addressbook/gui/component/e-book-shell-view.c
@@@ -1,318 -1,0 +1,318 @@@
+/*
+ * e-book-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-book-shell-view-private.h"
+
+static gpointer parent_class;
+static GType book_shell_view_type;
+
+static void
+book_shell_view_source_list_changed_cb (EBookShellView *book_shell_view,
+ ESourceList *source_list)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+ EBookShellContent *book_shell_content;
+ EShellView *shell_view;
+ GList *keys, *iter;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ book_shell_content = book_shell_view->priv->book_shell_content;
+
+ keys = g_hash_table_get_keys (priv->uid_to_view);
+ for (iter = keys; iter != NULL; iter = iter->next) {
+ gchar *uid = iter->data;
+ EAddressbookView *view;
+
+ /* If the source still exists, move on. */
+ if (e_source_list_peek_source_by_uid (source_list, uid))
+ continue;
+
+ /* Remove the view for the deleted source. */
+ view = g_hash_table_lookup (priv->uid_to_view, uid);
+ e_book_shell_content_remove_view (book_shell_content, view);
+ g_hash_table_remove (priv->uid_to_view, uid);
+ }
+ g_list_free (keys);
+
+ keys = g_hash_table_get_keys (priv->uid_to_editor);
+ for (iter = keys; iter != NULL; iter = iter->next) {
+ gchar *uid = iter->data;
+ EditorUidClosure *closure;
+
+ /* If the source still exists, move on. */
+ if (e_source_list_peek_source_by_uid (source_list, uid))
+ continue;
+
+ /* Remove the editor for the deleted source. */
+ closure = g_hash_table_lookup (priv->uid_to_editor, uid);
+ g_object_weak_unref (
+ G_OBJECT (closure->editor), (GWeakNotify)
+ e_book_shell_view_editor_weak_notify, closure);
+ gtk_widget_destroy (closure->editor);
+ g_hash_table_remove (priv->uid_to_editor, uid);
+ }
+ g_list_free (keys);
+
+ e_shell_view_update_actions (shell_view);
+}
+
+static void
+book_shell_view_dispose (GObject *object)
+{
+ EBookShellView *book_shell_view;
+
+ book_shell_view = E_BOOK_SHELL_VIEW (object);
+ e_book_shell_view_private_dispose (book_shell_view);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+book_shell_view_finalize (GObject *object)
+{
+ EBookShellView *book_shell_view;
+
+ book_shell_view = E_BOOK_SHELL_VIEW (object);
+ e_book_shell_view_private_finalize (book_shell_view);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+book_shell_view_constructed (GObject *object)
+{
+ EBookShellView *book_shell_view;
+ EBookShellBackend *book_shell_backend;
+ ESourceList *source_list;
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ book_shell_view = E_BOOK_SHELL_VIEW (object);
+ e_book_shell_view_private_constructed (book_shell_view);
+
+ book_shell_backend = book_shell_view->priv->book_shell_backend;
+ source_list = e_book_shell_backend_get_source_list (book_shell_backend);
+
+ g_signal_connect_swapped (
+ source_list, "changed",
+ G_CALLBACK (book_shell_view_source_list_changed_cb),
+ book_shell_view);
+}
+
+static void
+book_shell_view_update_actions (EShellView *shell_view)
+{
+ EBookShellViewPrivate *priv;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ const gchar *label;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean any_contacts_selected;
+ gboolean has_primary_source;
+ gboolean multiple_contacts_selected;
+ gboolean primary_source_is_system;
+ gboolean single_contact_selected;
+ gboolean selection_is_contact_list;
+ gboolean selection_has_email;
+ gboolean source_is_busy;
+ gboolean source_is_editable;
+ gboolean source_is_empty;
+
+ priv = E_BOOK_SHELL_VIEW_GET_PRIVATE (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);
+
+ single_contact_selected =
+ (state & E_BOOK_SHELL_CONTENT_SELECTION_SINGLE);
+ multiple_contacts_selected =
+ (state & E_BOOK_SHELL_CONTENT_SELECTION_MULTIPLE);
+ selection_has_email =
+ (state & E_BOOK_SHELL_CONTENT_SELECTION_HAS_EMAIL);
+ selection_is_contact_list =
+ (state & E_BOOK_SHELL_CONTENT_SELECTION_IS_CONTACT_LIST);
+ source_is_busy =
+ (state & E_BOOK_SHELL_CONTENT_SOURCE_IS_BUSY);
+ source_is_editable =
+ (state & E_BOOK_SHELL_CONTENT_SOURCE_IS_EDITABLE);
+ source_is_empty =
+ (state & E_BOOK_SHELL_CONTENT_SOURCE_IS_EMPTY);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ state = e_shell_sidebar_check_state (shell_sidebar);
+
+ has_primary_source =
+ (state & E_BOOK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+ primary_source_is_system =
+ (state & E_BOOK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM);
+
+ any_contacts_selected =
+ (single_contact_selected || multiple_contacts_selected);
+
+ action = ACTION (ADDRESS_BOOK_DELETE);
+ sensitive = has_primary_source && !primary_source_is_system;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (ADDRESS_BOOK_RENAME);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (ADDRESS_BOOK_STOP);
+ sensitive = source_is_busy;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_CLIPBOARD_COPY);
+ sensitive = any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_CLIPBOARD_CUT);
+ sensitive = source_is_editable && any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_CLIPBOARD_PASTE);
+ sensitive = source_is_editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_COPY);
+ sensitive = any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_DELETE);
+ sensitive = source_is_editable && any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_FORWARD);
+ sensitive = any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+ if (multiple_contacts_selected)
+ label = _("_Forward Contacts");
+ else
+ label = _("_Forward Contact");
+ g_object_set (action, "label", label, NULL);
+
+ action = ACTION (CONTACT_MOVE);
+ sensitive = source_is_editable && any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_OPEN);
+ sensitive = any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_PRINT);
+ sensitive = any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_PRINT_PREVIEW);
+ sensitive = any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_SAVE_AS);
+ sensitive = any_contacts_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_SELECT_ALL);
+ sensitive = !(source_is_empty);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CONTACT_SEND_MESSAGE);
+ sensitive = any_contacts_selected && selection_has_email;
+ gtk_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");
+ g_object_set (action, "label", label, NULL);
+}
+
+static void
+book_shell_view_class_init (EBookShellViewClass *class)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EBookShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = book_shell_view_dispose;
+ object_class->finalize = book_shell_view_finalize;
+ object_class->constructed = book_shell_view_constructed;
+
+ 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_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->update_actions = book_shell_view_update_actions;
+}
+
+static void
+book_shell_view_init (EBookShellView *book_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ book_shell_view->priv =
+ E_BOOK_SHELL_VIEW_GET_PRIVATE (book_shell_view);
+
+ e_book_shell_view_private_init (book_shell_view, shell_view_class);
+}
+
+GType
+e_book_shell_view_get_type (void)
+{
+ return book_shell_view_type;
+}
+
+void
+e_book_shell_view_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EBookShellViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) book_shell_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EBookShellView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) book_shell_view_init,
+ NULL /* value_table */
+ };
+
+ book_shell_view_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_VIEW,
+ "EBookShellView", &type_info, 0);
+}
diff --cc addressbook/gui/component/e-book-shell-view.h
index 3cefba8,0000000..33a0c8a
mode 100644,000000..100644
--- a/addressbook/gui/component/e-book-shell-view.h
+++ b/addressbook/gui/component/e-book-shell-view.h
@@@ -1,66 -1,0 +1,66 @@@
+/*
+ * e-book-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_BOOK_SHELL_VIEW_H
+#define E_BOOK_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_BOOK_SHELL_VIEW \
+ (e_book_shell_view_get_type ())
+#define E_BOOK_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellView))
+#define E_BOOK_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewClass))
+#define E_IS_BOOK_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_BOOK_SHELL_VIEW))
+#define E_IS_BOOK_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_BOOK_SHELL_VIEW))
+#define E_BOOK_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_BOOK_SHELL_VIEW, EBookShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EBookShellView EBookShellView;
+typedef struct _EBookShellViewClass EBookShellViewClass;
+typedef struct _EBookShellViewPrivate EBookShellViewPrivate;
+
+struct _EBookShellView {
+ EShellView parent;
+ EBookShellViewPrivate *priv;
+};
+
+struct _EBookShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_book_shell_view_get_type (void);
+void e_book_shell_view_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_BOOK_SHELL_VIEW_H */
diff --cc addressbook/gui/component/eab-composer-util.c
index 943225b,0000000..46d28b0
mode 100644,000000..100644
--- a/addressbook/gui/component/eab-composer-util.c
+++ b/addressbook/gui/component/eab-composer-util.c
@@@ -1,197 -1,0 +1,197 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "eab-composer-util.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libebook/e-contact.h>
+#include <libebook/e-destination.h>
+
+#include "composer/e-msg-composer.h"
+#include "addressbook/util/eab-book-util.h"
+#include "addressbook/gui/widgets/eab-gui-util.h"
+
+void
+eab_send_as_to (GList *destinations)
+{
+ EMsgComposer *composer;
+ EComposerHeaderTable *table;
+ GPtrArray *to_array;
+ GPtrArray *bcc_array;
+
+ union {
+ gpointer *pdata;
+ EDestination **destinations;
+ } convert;
+
+ if (destinations == NULL)
+ return;
+
+ composer = e_msg_composer_new ();
+ table = e_msg_composer_get_header_table (composer);
+
+ to_array = g_ptr_array_new ();
+ bcc_array = g_ptr_array_new ();
+
+ /* Sort contacts into "To" and "Bcc" destinations. */
+ while (destinations != NULL) {
+ EDestination *destination = destinations->data;
+
+ if (e_destination_is_evolution_list (destination)) {
+ if (e_destination_list_show_addresses (destination))
+ g_ptr_array_add (to_array, destination);
+ else
+ g_ptr_array_add (bcc_array, destination);
+ } else
+ g_ptr_array_add (to_array, destination);
+
+ destinations = g_list_next (destinations);
+ }
+
+ /* Add sentinels to each array. */
+ g_ptr_array_add (to_array, NULL);
+ g_ptr_array_add (bcc_array, NULL);
+
+ /* XXX Acrobatics like this make me question whether NULL-terminated
+ * arrays are really the best argument type for passing a list of
+ * destinations to the header table. */
+
+ /* Add "To" destinations. */
+ convert.pdata = to_array->pdata;
+ e_composer_header_table_set_destinations_to (
+ table, convert.destinations);
+ g_ptr_array_free (to_array, FALSE);
+ e_destination_freev (convert.destinations);
+
+ /* Add "Bcc" destinations. */
+ convert.pdata = bcc_array->pdata;
+ e_composer_header_table_set_destinations_bcc (
+ table, convert.destinations);
+ g_ptr_array_free (bcc_array, FALSE);
+ e_destination_freev (convert.destinations);
+
+ gtk_widget_show (GTK_WIDGET (composer));
+}
+
+static const char *
+get_email (EContact *contact, EContactField field_id, gchar **to_free)
+{
+ char *name = NULL, *mail = NULL;
+ const char *value = e_contact_get_const (contact, field_id);
+
+ *to_free = NULL;
+
+ if (eab_parse_qp_email (value, &name, &mail)) {
+ *to_free = g_strdup_printf ("%s <%s>", name, mail);
+ value = *to_free;
+ }
+
+ g_free (name);
+ g_free (mail);
+
+ return value;
+}
+
+void
+eab_send_as_attachment (GList *destinations)
+{
+ EMsgComposer *composer;
+ EComposerHeaderTable *table;
+ CamelMimePart *attachment;
+ GList *contacts, *iter;
+ gchar *data;
+
+ if (destinations == NULL)
+ return;
+
+ composer = e_msg_composer_new ();
+ table = e_msg_composer_get_header_table (composer);
+
+ attachment = camel_mime_part_new ();
+
+ contacts = g_list_copy (destinations);
+ for (iter = contacts; iter != NULL; iter = iter->next)
+ iter->data = e_destination_get_contact (iter->data);
+ data = eab_contact_list_to_string (contacts);
+ g_list_free (contacts);
+
+ camel_mime_part_set_content (
+ attachment, data, strlen (data), "text/x-vcard");
+
+ if (destinations->next != NULL)
+ camel_mime_part_set_description (
+ attachment, _("Multiple vCards"));
+ else {
+ EContact *contact;
+ const gchar *file_as;
+ gchar *description;
+
+ contact = e_destination_get_contact (destinations->data);
+ file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+ description = g_strdup_printf (_("vCard for %s"), file_as);
+ camel_mime_part_set_description (attachment, description);
+ g_free (description);
+ }
+
+ camel_mime_part_set_disposition (attachment, "attachment");
+
+ e_msg_composer_attach (composer, attachment);
+ camel_object_unref (attachment);
+
+ if (destinations->next != NULL)
+ e_composer_header_table_set_subject (
+ table, _("Contact information"));
+ else {
+ EContact *contact;
+ gchar *tempstr;
+ const gchar *tempstr2;
+ gchar *tempfree = NULL;
+
+ contact = e_destination_get_contact (destinations->data);
+ tempstr2 = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+ if (!tempstr2 || !*tempstr2)
+ tempstr2 = e_contact_get_const (contact, E_CONTACT_FULL_NAME);
+ if (!tempstr2 || !*tempstr2)
+ tempstr2 = e_contact_get_const (contact, E_CONTACT_ORG);
+ if (!tempstr2 || !*tempstr2) {
+ g_free (tempfree);
+ tempstr2 = get_email (contact, E_CONTACT_EMAIL_1, &tempfree);
+ }
+ if (!tempstr2 || !*tempstr2) {
+ g_free (tempfree);
+ tempstr2 = get_email (contact, E_CONTACT_EMAIL_2, &tempfree);
+ }
+ if (!tempstr2 || !*tempstr2) {
+ g_free (tempfree);
+ tempstr2 = get_email (contact, E_CONTACT_EMAIL_3, &tempfree);
+ }
+
+ if (!tempstr2 || !*tempstr2)
+ tempstr = g_strdup_printf (_("Contact information"));
+ else
+ tempstr = g_strdup_printf (_("Contact information for %s"), tempstr2);
+
+ e_composer_header_table_set_subject (table, tempstr);
+
+ g_free (tempstr);
+ g_free (tempfree);
+ }
+
+ gtk_widget_show (GTK_WIDGET (composer));
+}
diff --cc addressbook/gui/component/eab-composer-util.h
index ffee76b,0000000..4aec230
mode 100644,000000..100644
--- a/addressbook/gui/component/eab-composer-util.h
+++ b/addressbook/gui/component/eab-composer-util.h
@@@ -1,31 -1,0 +1,31 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EAB_COMPOSER_UTIL_H
+#define EAB_COMPOSER_UTIL_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void eab_send_as_to (GList *destinations);
+void eab_send_as_attachment (GList *destinations);
+
+G_END_DECLS
+
+#endif /* EAB_COMPOSER_UTIL_H */
diff --cc addressbook/gui/component/evolution-module-addressbook.c
index 2d3e18e,0000000..3089133
mode 100644,000000..100644
--- a/addressbook/gui/component/evolution-module-addressbook.c
+++ b/addressbook/gui/component/evolution-module-addressbook.c
@@@ -1,45 -1,0 +1,45 @@@
+/*
+ * evolution-module-addressbook.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-book-shell-backend.h"
+#include "e-book-shell-content.h"
+#include "e-book-shell-sidebar.h"
+#include "e-book-shell-view.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ /* Register dynamically loaded types. */
+
+ e_book_shell_backend_register_type (type_module);
+ e_book_shell_content_register_type (type_module);
+ e_book_shell_sidebar_register_type (type_module);
+ e_book_shell_view_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --cc addressbook/gui/widgets/a11y/ea-addressbook-view.c
index eff7eb4,0000000..4150e10
mode 100644,000000..100644
--- a/addressbook/gui/widgets/a11y/ea-addressbook-view.c
+++ b/addressbook/gui/widgets/a11y/ea-addressbook-view.c
@@@ -1,123 -1,0 +1,123 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Leon Zhang <leon zhang sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+#include "ea-addressbook-view.h"
+
+static G_CONST_RETURN gchar* ea_ab_view_get_name (AtkObject *accessible);
+static G_CONST_RETURN gchar* ea_ab_view_get_description (AtkObject *accessible);
+
+static void ea_ab_view_class_init (EAddressbookViewClass *class);
+
+static gpointer parent_class = NULL;
+
+GType
+ea_ab_view_get_type (void)
+{
+ static GType type = 0;
+ AtkObjectFactory *factory;
+ GTypeQuery query;
+ GType derived_atk_type;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (EAddressbookViewClass),
+ (GBaseInitFunc) NULL, /* base_init */
+ (GBaseFinalizeFunc) NULL, /* base_finalize */
+ (GClassInitFunc) ea_ab_view_class_init,
+ (GClassFinalizeFunc) NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EAddressbookView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ /*
+ * Figure out the size of the class and instance
+ * we are run-time deriving from (GailWidget, in this case) */
+
+ factory = atk_registry_get_factory (atk_get_default_registry (),
+ GTK_TYPE_EVENT_BOX);
+ derived_atk_type = atk_object_factory_get_accessible_type (factory);
+ g_type_query (derived_atk_type, &query);
+
+ tinfo.class_size = query.class_size;
+ tinfo.instance_size = query.instance_size;
+
+ type = g_type_register_static (derived_atk_type,
+ "EaABView", &tinfo, 0);
+ }
+
+ return type;
+}
+
+static void
+ea_ab_view_class_init (EAddressbookViewClass *class)
+{
+ AtkObjectClass *atk_object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ atk_object_class = ATK_OBJECT_CLASS (class);
+ atk_object_class->get_name = ea_ab_view_get_name;
+ atk_object_class->get_description = ea_ab_view_get_description;
+}
+
+static G_CONST_RETURN gchar*
+ea_ab_view_get_name (AtkObject *accessible)
+{
+ g_return_val_if_fail (EA_IS_AB_VIEW(accessible), NULL);
+ if (accessible->name)
+ return accessible->name;
+
+ return _("evolution address book");
+}
+
+static G_CONST_RETURN gchar*
+ea_ab_view_get_description (AtkObject *accessible)
+{
+ if (accessible->description)
+ return accessible->description;
+
+ return _("evolution address book");
+}
+
+AtkObject*
+ea_ab_view_new (GObject *obj)
+{
+ GObject *object;
+ AtkObject *accessible;
+
+ g_return_val_if_fail(obj != NULL, NULL);
+ g_return_val_if_fail (E_IS_ADDRESSBOOK_VIEW(obj), NULL);
+
+ object = g_object_new (EA_TYPE_AB_VIEW, NULL);
+
+ accessible = ATK_OBJECT (object);
+ atk_object_initialize (accessible, obj);
+ accessible->role = ATK_ROLE_CANVAS;
+
+ return accessible;
+}
diff --cc addressbook/gui/widgets/a11y/ea-addressbook.c
index 087c33a,0000000..14fc4c1
mode 100644,000000..100644
--- a/addressbook/gui/widgets/a11y/ea-addressbook.c
+++ b/addressbook/gui/widgets/a11y/ea-addressbook.c
@@@ -1,84 -1,0 +1,84 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Leon Zhang <leon zhang sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <text/e-text.h>
+#include "a11y/ea-factory.h"
+#include "ea-addressbook.h"
+#include "ea-minicard.h"
+#include "ea-minicard-view.h"
+#include "ea-addressbook-view.h"
+
+EA_FACTORY_GOBJECT (EA_TYPE_MINICARD, ea_minicard, ea_minicard_new)
+EA_FACTORY_GOBJECT (EA_TYPE_MINICARD_VIEW, ea_minicard_view, ea_minicard_view_new)
+EA_FACTORY_GOBJECT (EA_TYPE_AB_VIEW, ea_ab_view, ea_ab_view_new)
+
+static gboolean ea_addressbook_focus_watcher (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data);
+
+void e_minicard_a11y_init (void)
+{
+ EA_SET_FACTORY (e_minicard_get_type (), ea_minicard);
+}
+
+void e_minicard_view_a11y_init (void)
+{
+ EA_SET_FACTORY (e_minicard_view_get_type (), ea_minicard_view);
+
+ if (atk_get_root ()) {
+ g_signal_add_emission_hook (g_signal_lookup ("event",
+ e_minicard_get_type()),
+ 0, ea_addressbook_focus_watcher,
+ NULL, (GDestroyNotify) NULL);
+ }
+}
+
+void eab_view_a11y_init (void)
+{
+ EA_SET_FACTORY (E_TYPE_ADDRESSBOOK_VIEW, ea_ab_view);
+}
+
+static gboolean
+ea_addressbook_focus_watcher (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ GObject *object;
+ GdkEvent *event;
+ AtkObject *ea_event = NULL;
+
+ object = g_value_get_object (param_values + 0);
+ event = g_value_get_boxed (param_values + 1);
+
+ if (E_IS_MINICARD (object)) {
+ GnomeCanvasItem *item = GNOME_CANVAS_ITEM (object);
+ ea_event = atk_gobject_accessible_for_object (object);
+ if (event->type == GDK_FOCUS_CHANGE) {
+ if ((event->focus_change.in) && (E_IS_MINICARD (item->canvas->focused_item)))
+ atk_focus_tracker_notify (ea_event);
+ }
+ }
+
+ return TRUE;
+}
diff --cc addressbook/gui/widgets/a11y/ea-minicard-view.c
index aed11ed,0000000..052db4d
mode 100644,000000..100644
--- a/addressbook/gui/widgets/a11y/ea-minicard-view.c
+++ b/addressbook/gui/widgets/a11y/ea-minicard-view.c
@@@ -1,413 -1,0 +1,413 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Leon Zhang < leon zhang sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include "ea-minicard.h"
+#include "ea-minicard-view.h"
+#include "eab-gui-util.h"
+#include "e-addressbook-view.h"
+
+static const char * action_name[] = {
+ N_("New Contact"),
+ N_("New Contact List")
+};
+
+
+static G_CONST_RETURN gchar* ea_minicard_view_get_name (AtkObject *accessible);
+static G_CONST_RETURN gchar* ea_minicard_view_get_description (AtkObject *accessible);
+
+static void ea_minicard_view_class_init (EaMinicardViewClass *klass);
+
+static gint ea_minicard_view_get_n_children (AtkObject *obj);
+static AtkObject *ea_minicard_view_ref_child (AtkObject *obj, gint i);
+
+static AtkStateSet *ea_minicard_view_ref_state_set(AtkObject *obj);
+
+static void atk_selection_interface_init (AtkSelectionIface *iface);
+static gboolean selection_interface_add_selection (AtkSelection *selection,
+ gint i);
+static gboolean selection_interface_clear_selection (AtkSelection *selection);
+static AtkObject* selection_interface_ref_selection (AtkSelection *selection,
+ gint i);
+static gint selection_interface_get_selection_count (AtkSelection *selection);
+static gboolean selection_interface_is_child_selected (AtkSelection *selection,
+ gint i);
+
+static void atk_action_interface_init (AtkActionIface *iface);
+static gboolean atk_action_interface_do_action (AtkAction *iface, gint i);
+static gint atk_action_interface_get_n_action (AtkAction *iface);
+static G_CONST_RETURN gchar* atk_action_interface_get_description (AtkAction *iface, gint i);
+static G_CONST_RETURN gchar* atk_action_interface_get_name (AtkAction *iface, gint i);
+
+static gpointer parent_class = NULL;
+
+GType
+ea_minicard_view_get_type (void)
+{
+ static GType type = 0;
+ AtkObjectFactory *factory;
+ GTypeQuery query;
+ GType derived_atk_type;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (EaMinicardViewClass),
+ (GBaseInitFunc) NULL, /* base_init */
+ (GBaseFinalizeFunc) NULL, /* base_finalize */
+ (GClassInitFunc) ea_minicard_view_class_init,
+ (GClassFinalizeFunc) NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (EaMinicardView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ static const GInterfaceInfo atk_selection_info = {
+ (GInterfaceInitFunc) atk_selection_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo atk_action_info = {
+ (GInterfaceInitFunc) atk_action_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ /*
+ * Figure out the size of the class and instance
+ * we are run-time deriving from (GailWidget, in this case) */
+
+ factory = atk_registry_get_factory (atk_get_default_registry (),
+ GNOME_TYPE_CANVAS_GROUP);
+ derived_atk_type = atk_object_factory_get_accessible_type (factory);
+ g_type_query (derived_atk_type, &query);
+
+ tinfo.class_size = query.class_size;
+ tinfo.instance_size = query.instance_size;
+
+ type = g_type_register_static (derived_atk_type,
+ "EaMinicardView", &tinfo, 0);
+ g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+ &atk_selection_info);
+ g_type_add_interface_static (type, ATK_TYPE_ACTION,
+ &atk_action_info);
+
+ }
+
+ return type;
+}
+
+static void
+ea_minicard_view_class_init (EaMinicardViewClass *klass)
+{
+ AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ class->get_name = ea_minicard_view_get_name;
+ class->get_description = ea_minicard_view_get_description;
+ class->ref_state_set = ea_minicard_view_ref_state_set;
+ class->get_n_children = ea_minicard_view_get_n_children;
+ class->ref_child = ea_minicard_view_ref_child;
+}
+
+static G_CONST_RETURN gchar*
+ea_minicard_view_get_name (AtkObject *accessible)
+{
+ EReflow *reflow;
+ gchar *string;
+ EMinicardView *card_view;
+ EBook *book = NULL;
+ const gchar *source_name;
+
+ g_return_val_if_fail (EA_IS_MINICARD_VIEW (accessible), NULL);
+
+ reflow = E_REFLOW(atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
+
+ if (!reflow)
+ return NULL;
+
+ /* Get the current name of minicard view*/
+ card_view = E_MINICARD_VIEW (reflow);
+ g_object_get (card_view->adapter, "book", &book, NULL);
+ g_return_val_if_fail (E_IS_BOOK (book), NULL);
+ source_name = e_source_peek_name (e_book_get_source (book));
+ if (!source_name)
+ source_name="";
+
+ string = g_strdup_printf (ngettext ("current address book folder %s has %d card",
+ "current address book folder %s has %d cards",
+ reflow->count), source_name, reflow->count);
+
+ ATK_OBJECT_CLASS (parent_class)->set_name (accessible, string);
+ g_free (string);
+ g_object_unref(book);
+ return accessible->name;
+}
+
+static G_CONST_RETURN gchar*
+ea_minicard_view_get_description (AtkObject *accessible)
+{
+ g_return_val_if_fail (EA_IS_MINICARD_VIEW(accessible), NULL);
+ if (accessible->description)
+ return accessible->description;
+
+ return _("evolution address book");
+}
+
+AtkObject*
+ea_minicard_view_new (GObject *obj)
+{
+ GObject *object;
+ AtkObject *accessible;
+
+ g_return_val_if_fail (E_IS_MINICARD_VIEW(obj), NULL);
+ object = g_object_new (EA_TYPE_MINICARD_VIEW, NULL);
+ accessible = ATK_OBJECT (object);
+ atk_object_initialize (accessible, obj);
+ accessible->role = ATK_ROLE_PANEL;
+ return accessible;
+}
+
+static gint
+ea_minicard_view_get_n_children (AtkObject *accessible)
+{
+ EReflow *reflow;
+
+ gint child_num = 0;
+
+ g_return_val_if_fail (EA_IS_MINICARD_VIEW (accessible), -1);
+
+ reflow = E_REFLOW (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible)));
+
+ if (!reflow)
+ return -1;
+
+ child_num = reflow->count;
+
+ return child_num;
+}
+
+static AtkStateSet *ea_minicard_view_ref_state_set (AtkObject *obj)
+{
+ AtkStateSet *state_set = NULL;
+ GObject *gobj = NULL;
+
+ state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+ if( !state_set )
+ state_set = atk_state_set_new ();
+
+ gobj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (obj));
+ if( !gobj )
+ return state_set;
+
+ atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
+ atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
+ atk_state_set_add_state (state_set, ATK_STATE_SHOWING);
+
+ return state_set;
+}
+
+static AtkObject *
+ea_minicard_view_ref_child (AtkObject *accessible, gint index)
+{
+ EReflow *reflow;
+ gint child_num;
+ AtkObject *atk_object = NULL;
+ EMinicard *card = NULL;
+
+ g_return_val_if_fail (EA_IS_MINICARD_VIEW (accessible), NULL);
+
+ child_num = atk_object_get_n_accessible_children (accessible);
+ if (child_num <= 0 || index < 0 || index >= child_num)
+ return NULL;
+
+ reflow = E_REFLOW (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible)));
+ if (!reflow)
+ return NULL;
+ if (!reflow->items )
+ return NULL;
+ /* a minicard */
+ if (index < child_num) {
+ card = E_MINICARD (reflow->items[index]);
+ atk_object = atk_gobject_accessible_for_object (G_OBJECT (card));
+ } else {
+ return NULL;
+ }
+
+ g_object_ref (atk_object);
+ return atk_object;
+}
+
+/* atkselection interface */
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->add_selection = selection_interface_add_selection;
+ iface->clear_selection = selection_interface_clear_selection;
+ iface->ref_selection = selection_interface_ref_selection;
+ iface->get_selection_count = selection_interface_get_selection_count;
+ iface->is_child_selected = selection_interface_is_child_selected;
+}
+
+static gboolean
+selection_interface_add_selection (AtkSelection *selection, gint i)
+{
+ AtkGObjectAccessible *atk_gobj= NULL;
+ EReflow *reflow = NULL;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (selection);
+ reflow = E_REFLOW (atk_gobject_accessible_get_object (atk_gobj));
+
+ if (!reflow)
+ return FALSE;
+
+ selection_interface_clear_selection (selection);
+ e_selection_model_select_single_row (reflow->selection, i);
+
+ return TRUE;
+}
+
+static gboolean
+selection_interface_clear_selection (AtkSelection *selection)
+{
+ AtkGObjectAccessible *atk_gobj = NULL;
+ EReflow *reflow = NULL;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (selection);
+ reflow = E_REFLOW(atk_gobject_accessible_get_object (atk_gobj));
+
+ if( !reflow )
+ return FALSE;
+
+ e_selection_model_clear (reflow->selection);
+
+ return TRUE;
+}
+
+static AtkObject*
+selection_interface_ref_selection (AtkSelection *selection, gint i)
+{
+ return ea_minicard_view_ref_child (ATK_OBJECT (selection), i);
+}
+
+static gint
+selection_interface_get_selection_count (AtkSelection *selection)
+{
+ AtkGObjectAccessible *atk_gobj = NULL;
+ EReflow *reflow = NULL;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (selection);
+ reflow = E_REFLOW (atk_gobject_accessible_get_object (atk_gobj));
+
+ if (!reflow )
+ return FALSE;
+
+ return e_selection_model_selected_count (reflow->selection);
+}
+
+static gboolean
+selection_interface_is_child_selected (AtkSelection *selection, gint i)
+{
+ AtkGObjectAccessible *atk_gobj = NULL;
+ EReflow *reflow = NULL;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (selection);
+ reflow = E_REFLOW(atk_gobject_accessible_get_object (atk_gobj));
+
+ if( !reflow )
+ return FALSE;
+
+ return e_selection_model_is_row_selected (reflow->selection, i);
+}
+
+static void atk_action_interface_init (AtkActionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->do_action = atk_action_interface_do_action;
+ iface->get_n_actions = atk_action_interface_get_n_action;
+ iface->get_description = atk_action_interface_get_description;
+ iface->get_name = atk_action_interface_get_name;
+}
+
+static gboolean atk_action_interface_do_action (AtkAction *action, gint i)
+{
+ gboolean return_value = TRUE;
+ EMinicardView *card_view;
+
+ AtkGObjectAccessible *atk_gobj= NULL;
+ EReflow *reflow = NULL;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (action);
+ reflow = E_REFLOW (atk_gobject_accessible_get_object (atk_gobj));
+
+ if (reflow == NULL)
+ return FALSE;
+
+ card_view = E_MINICARD_VIEW (reflow);
+
+ switch (i) {
+ case 0:
+ /* New Contact */
+ e_minicard_view_create_contact (card_view);
+ break;
+ case 1:
+ /* New Contact List */
+ e_minicard_view_create_contact_list (card_view);
+ break;
+ default:
+ return_value = FALSE;
+ break;
+ }
+
+ return return_value;
+}
+
+static gint atk_action_interface_get_n_action (AtkAction *iface)
+{
+ return G_N_ELEMENTS (action_name);
+}
+
+static G_CONST_RETURN gchar*
+atk_action_interface_get_description (AtkAction *iface, gint i)
+{
+ return atk_action_interface_get_name (iface, i);
+}
+
+static G_CONST_RETURN gchar*
+atk_action_interface_get_name (AtkAction *iface, gint i)
+{
+ if( i >= G_N_ELEMENTS (action_name) || i < 0)
+ return NULL;
+
+ return action_name[i];
+}
+
diff --cc addressbook/gui/widgets/e-addressbook-selector.c
index e7bec99,0000000..21347e2
mode 100644,000000..100644
--- a/addressbook/gui/widgets/e-addressbook-selector.c
+++ b/addressbook/gui/widgets/e-addressbook-selector.c
@@@ -1,443 -1,0 +1,443 @@@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-addressbook-selector.c
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU 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 General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "e-addressbook-selector.h"
+
+#include <eab-book-util.h>
+#include <eab-contact-merging.h>
+
+#define E_ADDRESSBOOK_SELECTOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ADDRESSBOOK_SELECTOR, EAddressbookSelectorPrivate))
+
+#define PRIMARY_ADDRESSBOOK_KEY \
+ "/apps/evolution/addressbook/display/primary_addressbook"
+
+typedef struct _MergeContext MergeContext;
+
+struct _EAddressbookSelectorPrivate {
+ EAddressbookView *current_view;
+};
+
+struct _MergeContext {
+ EBook *source_book;
+ EBook *target_book;
+
+ EContact *current_contact;
+ GList *remaining_contacts;
+ guint pending_removals;
+
+ gint remove_from_source : 1;
+ gint copy_done : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_CURRENT_VIEW
+};
+
+enum {
+ DND_TARGET_TYPE_VCARD,
+ DND_TARGET_TYPE_SOURCE_VCARD
+};
+
+static GtkTargetEntry drag_types[] = {
- { "text/x-vcard", 0, DND_TARGET_TYPE_VCARD },
- { "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD }
++ { (gchar *) "text/x-vcard", 0, DND_TARGET_TYPE_VCARD },
++ { (gchar *) "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD }
+};
+
+static gpointer parent_class;
+
+static void
+merge_context_next (MergeContext *merge_context)
+{
+ GList *list;
+
+ list = merge_context->remaining_contacts;
+ merge_context->current_contact = list->data;
+ list = g_list_delete_link (list, list);
+ merge_context->remaining_contacts = list;
+}
+
+static MergeContext *
+merge_context_new (EBook *source_book,
+ EBook *target_book,
+ GList *contact_list)
+{
+ MergeContext *merge_context;
+
+ merge_context = g_slice_new0 (MergeContext);
+ merge_context->source_book = source_book;
+ merge_context->target_book = target_book;
+ merge_context->remaining_contacts = contact_list;
+ merge_context_next (merge_context);
+
+ return merge_context;
+}
+
+static void
+merge_context_free (MergeContext *merge_context)
+{
+ if (merge_context->source_book != NULL)
+ g_object_unref (merge_context->source_book);
+
+ if (merge_context->target_book != NULL)
+ g_object_unref (merge_context->target_book);
+
+ g_slice_free (MergeContext, merge_context);
+}
+
+static void
+addressbook_selector_removed_cb (EBook *book,
+ EBookStatus status,
+ MergeContext *merge_context)
+{
+ merge_context->pending_removals--;
+
+ if (merge_context->remaining_contacts != NULL)
+ return;
+
+ if (merge_context->pending_removals > 0)
+ return;
+
+ merge_context_free (merge_context);
+}
+
+static void
+addressbook_selector_merge_next_cb (EBook *book,
+ EBookStatus status,
+ const gchar *id,
+ MergeContext *merge_context)
+{
+ if (merge_context->remove_from_source && status == E_BOOK_ERROR_OK) {
+ /* Remove previous contact from source. */
+ e_book_async_remove_contact (
+ merge_context->source_book,
+ merge_context->current_contact,
+ (EBookCallback) addressbook_selector_removed_cb,
+ merge_context);
+ merge_context->pending_removals++;
+ }
+
+ g_object_unref (merge_context->current_contact);
+
+ if (merge_context->remaining_contacts != NULL) {
+ merge_context_next (merge_context);
+ eab_merging_book_add_contact (
+ merge_context->target_book,
+ merge_context->current_contact,
+ (EBookIdCallback) addressbook_selector_merge_next_cb,
+ merge_context);
+
+ } else if (merge_context->pending_removals == 0)
+ merge_context_free (merge_context);
+}
+
+static void
+addressbook_selector_load_primary_source (ESourceSelector *selector)
+{
+ GConfClient *client;
+ ESourceList *source_list;
+ ESource *source = NULL;
+ const gchar *key;
+ gchar *uid;
+
+ /* XXX If ESourceSelector had a "primary-uid" property,
+ * we could just bind the GConf key to it. */
+
+ source_list = e_source_selector_get_source_list (selector);
+
+ client = gconf_client_get_default ();
+ key = PRIMARY_ADDRESSBOOK_KEY;
+ uid = gconf_client_get_string (client, key, NULL);
+ g_object_unref (client);
+
+ if (uid != NULL) {
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ g_free (uid);
+ } else {
+ GSList *groups;
+
+ /* Dig up the first source in the source list.
+ * XXX libedataserver should provide API for this. */
+ groups = e_source_list_peek_groups (source_list);
+ while (groups != NULL) {
+ ESourceGroup *source_group = groups->data;
+ GSList *sources;
+
+ sources = e_source_group_peek_sources (source_group);
+ if (sources != NULL) {
+ source = sources->data;
+ break;
+ }
+
+ groups = g_slist_next (groups);
+ }
+ }
+
+ if (source != NULL)
+ e_source_selector_set_primary_selection (selector, source);
+}
+
+static void
+addressbook_selector_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_VIEW:
+ e_addressbook_selector_set_current_view (
+ E_ADDRESSBOOK_SELECTOR (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+addressbook_selector_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CURRENT_VIEW:
+ g_value_set_object (
+ value,
+ e_addressbook_selector_get_current_view (
+ E_ADDRESSBOOK_SELECTOR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+addressbook_selector_dispose (GObject *object)
+{
+ EAddressbookSelectorPrivate *priv;
+
+ priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (object);
+
+ if (priv->current_view != NULL) {
+ g_object_unref (priv->current_view);
+ priv->current_view = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+addressbook_selector_constructed (GObject *object)
+{
+ ESourceSelector *selector;
+
+ selector = E_SOURCE_SELECTOR (object);
+ addressbook_selector_load_primary_source (selector);
+}
+
+static void
+addressbook_selector_primary_selection_changed (ESourceSelector *selector)
+{
+ ESource *source;
+ GConfClient *client;
+ const gchar *key;
+ const gchar *string;
+
+ /* XXX If ESourceSelector had a "primary-uid" property,
+ * we could just bind the GConf key to it. */
+
+ source = e_source_selector_peek_primary_selection (selector);
+ if (source == NULL)
+ return;
+
+ client = gconf_client_get_default ();
+ key = PRIMARY_ADDRESSBOOK_KEY;
+ string = e_source_peek_uid (source);
+ gconf_client_set_string (client, key, string, NULL);
+ g_object_unref (client);
+}
+
+static gboolean
+addressbook_selector_data_dropped (ESourceSelector *selector,
+ GtkSelectionData *selection_data,
+ ESource *destination,
+ GdkDragAction action,
+ guint info)
+{
+ EAddressbookSelectorPrivate *priv;
+ MergeContext *merge_context;
+ EAddressbookModel *model;
+ EBook *source_book;
+ EBook *target_book;
+ GList *list;
+ const gchar *string;
+ gboolean remove_from_source;
+
+ priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (selector);
+ g_return_val_if_fail (priv->current_view != NULL, FALSE);
+
+ string = (const gchar *) selection_data->data;
+ remove_from_source = (action == GDK_ACTION_MOVE);
+
+ target_book = e_book_new (destination, NULL);
+ if (target_book == NULL)
+ return FALSE;
+
+ e_book_open (target_book, FALSE, NULL);
+
+ /* XXX Function assumes both out arguments are provided. All we
+ * care about is the contact list; source_book will be NULL. */
+ eab_book_and_contact_list_from_string (string, &source_book, &list);
+ if (list == NULL)
+ return FALSE;
+
+ model = e_addressbook_view_get_model (priv->current_view);
+ source_book = e_addressbook_model_get_book (model);
+ g_return_val_if_fail (E_IS_BOOK (source_book), FALSE);
+
+ merge_context = merge_context_new (source_book, target_book, list);
+ merge_context->remove_from_source = remove_from_source;
+
+ eab_merging_book_add_contact (
+ target_book, merge_context->current_contact,
+ (EBookIdCallback) addressbook_selector_merge_next_cb,
+ merge_context);
+
+ return TRUE;
+}
+
+static void
+addressbook_selector_class_init (EAddressbookSelectorClass *class)
+{
+ GObjectClass *object_class;
+ ESourceSelectorClass *selector_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAddressbookSelectorPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = addressbook_selector_set_property;
+ object_class->get_property = addressbook_selector_get_property;
+ object_class->dispose = addressbook_selector_dispose;
+ object_class->constructed = addressbook_selector_constructed;
+
+ selector_class = E_SOURCE_SELECTOR_CLASS (class);
+ selector_class->primary_selection_changed =
+ addressbook_selector_primary_selection_changed;
+ selector_class->data_dropped = addressbook_selector_data_dropped;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CURRENT_VIEW,
+ g_param_spec_object (
+ "current-view",
+ NULL,
+ NULL,
+ E_TYPE_ADDRESSBOOK_VIEW,
+ G_PARAM_READWRITE));
+}
+
+static void
+addressbook_selector_init (EAddressbookSelector *selector)
+{
+ selector->priv = E_ADDRESSBOOK_SELECTOR_GET_PRIVATE (selector);
+
+ gtk_drag_dest_set (
+ GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL,
+ drag_types, G_N_ELEMENTS (drag_types),
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+}
+
+GType
+e_addressbook_selector_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (EAddressbookSelectorClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) addressbook_selector_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAddressbookSelector),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) addressbook_selector_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_SOURCE_SELECTOR, "EAddressbookSelector",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_addressbook_selector_new (ESourceList *source_list)
+{
+ g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
+
+ return g_object_new (
+ E_TYPE_ADDRESSBOOK_SELECTOR,
+ "source-list", source_list, NULL);
+}
+
+EAddressbookView *
+e_addressbook_selector_get_current_view (EAddressbookSelector *selector)
+{
+ g_return_val_if_fail (E_IS_ADDRESSBOOK_SELECTOR (selector), NULL);
+
+ return selector->priv->current_view;
+}
+
+void
+e_addressbook_selector_set_current_view (EAddressbookSelector *selector,
+ EAddressbookView *current_view)
+{
+ /* XXX This is only needed for moving contacts via drag-and-drop.
+ * The selection data doesn't include the source of the data
+ * (the model for the currently selected address book view),
+ * so we have to rely on it being provided to us. I would
+ * be happy to see this function go away. */
+
+ g_return_if_fail (E_IS_ADDRESSBOOK_SELECTOR (selector));
+
+ if (current_view != NULL)
+ g_return_if_fail (E_IS_ADDRESSBOOK_VIEW (current_view));
+
+ if (selector->priv->current_view != NULL) {
+ g_object_unref (selector->priv->current_view);
+ selector->priv->current_view = NULL;
+ }
+
+ if (current_view != NULL)
+ g_object_ref (current_view);
+
+ selector->priv->current_view = current_view;
+
+ g_object_notify (G_OBJECT (selector), "current-view");
+}
diff --cc addressbook/gui/widgets/e-addressbook-view.c
index 8ee3c14,4cd151f..e889d9b
--- a/addressbook/gui/widgets/e-addressbook-view.c
+++ b/addressbook/gui/widgets/e-addressbook-view.c
@@@ -107,22 -126,71 +107,22 @@@ enum
DND_TARGET_TYPE_SOURCE_VCARD,
DND_TARGET_TYPE_VCARD
};
-#define VCARD_TYPE "text/x-vcard"
-#define SOURCE_VCARD_TYPE "text/x-source-vcard"
-
-typedef struct EABSearchBarItem {
- ESearchBarItem search;
- char *image;
-}EABSearchBarItem;
static GtkTargetEntry drag_types[] = {
- { "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD },
- { "text/x-vcard", 0, DND_TARGET_TYPE_VCARD }
- { (gchar *) SOURCE_VCARD_TYPE, 0, DND_TARGET_TYPE_SOURCE_VCARD },
- { (gchar *) VCARD_TYPE, 0, DND_TARGET_TYPE_VCARD }
++ { (gchar *) "text/x-source-vcard", 0, DND_TARGET_TYPE_SOURCE_VCARD },
++ { (gchar *) "text/x-vcard", 0, DND_TARGET_TYPE_VCARD }
};
-static const int num_drag_types = sizeof (drag_types) / sizeof (drag_types[0]);
-
-static guint eab_view_signals [LAST_SIGNAL] = {0, };
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
static GdkAtom clipboard_atom = GDK_NONE;
-static GalViewCollection *collection = NULL;
-
-enum {
- ESB_FULL_NAME,
- ESB_EMAIL,
- ESB_ANY
-};
-
-#if 0
-static ESearchBarItem addressbook_search_option_items[] = {
- { N_("Name begins with"), ESB_FULL_NAME, ESB_ITEMTYPE_RADIO },
- { N_("Email begins with"), ESB_EMAIL, ESB_ITEMTYPE_RADIO },
- { N_("Any field contains"), ESB_ANY, ESB_ITEMTYPE_RADIO },
- { NULL, -1, 0 }
-};
-#endif
-
-static ESearchBarItem addressbook_search_items[] = {
- E_FILTERBAR_ADVANCED,
- {NULL, 0, 0},
- E_FILTERBAR_SAVE,
- E_FILTERBAR_EDIT,
- {NULL, -1, 0}
-};
-
-GType
-eab_view_get_type (void)
+static void
+addressbook_view_emit_open_contact (EAddressbookView *view,
+ EContact *contact,
+ gboolean is_new_contact)
{
- static GType type = 0;
-
- if (!type) {
- static const GTypeInfo info = {
- sizeof (EABViewClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) eab_view_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (EABView),
- 0, /* n_preallocs */
- (GInstanceInitFunc) eab_view_init,
- };
-
- type = g_type_register_static (GTK_TYPE_VBOX, "EABView", &info, 0);
- }
-
- return type;
+ g_signal_emit (view, signals[OPEN_CONTACT], 0, contact, is_new_contact);
}
static void
diff --cc addressbook/util/addressbook.h
index 2e25448,0000000..7bc92ee
mode 100644,000000..100644
--- a/addressbook/util/addressbook.h
+++ b/addressbook/util/addressbook.h
@@@ -1,31 -1,0 +1,31 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __ADDRESSBOOK_H__
+#define __ADDRESSBOOK_H__
+
+#include <libebook/e-book.h>
+
+guint addressbook_load (EBook *book, EBookCallback cb, gpointer closure);
+void addressbook_load_cancel (guint id);
+void addressbook_load_default_book (EBookCallback open_response, gpointer closure);
+
+#endif /* __ADDRESSBOOK_H__ */
diff --cc calendar/gui/a11y/ea-calendar.c
index 3cf41f3,0000000..2662f42
mode 100644,000000..100644
--- a/calendar/gui/a11y/ea-calendar.c
+++ b/calendar/gui/a11y/ea-calendar.c
@@@ -1,204 -1,0 +1,204 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Bolian Yin <bolian yin sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <text/e-text.h>
+#include <libgnomecanvas/gnome-canvas-pixbuf.h>
+#include "ea-calendar-helpers.h"
+#include "a11y/ea-factory.h"
+#include "ea-calendar.h"
+
+#include "calendar/ea-cal-view.h"
+#include "calendar/ea-cal-view-event.h"
+#include "calendar/ea-day-view.h"
+#include "calendar/ea-day-view-main-item.h"
+#include "calendar/ea-week-view.h"
+#include "calendar/ea-week-view-main-item.h"
+#include "calendar/ea-gnome-calendar.h"
+
+
+EA_FACTORY (EA_TYPE_CAL_VIEW, ea_cal_view, ea_cal_view_new)
+EA_FACTORY (EA_TYPE_DAY_VIEW, ea_day_view, ea_day_view_new)
+EA_FACTORY_GOBJECT (EA_TYPE_DAY_VIEW_MAIN_ITEM, ea_day_view_main_item, ea_day_view_main_item_new)
+EA_FACTORY (EA_TYPE_WEEK_VIEW, ea_week_view, ea_week_view_new)
+EA_FACTORY_GOBJECT (EA_TYPE_WEEK_VIEW_MAIN_ITEM, ea_week_view_main_item, ea_week_view_main_item_new)
+EA_FACTORY (EA_TYPE_GNOME_CALENDAR, ea_gnome_calendar, ea_gnome_calendar_new)
+
+static gboolean ea_calendar_focus_watcher (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data);
+
+static gpointer e_text_type, pixbuf_type, e_day_view_type, e_week_view_type;
+static gpointer e_day_view_main_item_type, e_week_view_main_item_type;
+
+void
+gnome_calendar_a11y_init (void)
+{
+ /* we only add focus watcher when accessibility is enabled
+ */
+ if (atk_get_root ()) {
+ EA_SET_FACTORY (gnome_calendar_get_type(), ea_gnome_calendar);
+
+ /* force loading some types */
+ e_text_type = g_type_class_ref (E_TYPE_TEXT);
+ pixbuf_type = g_type_class_ref (GNOME_TYPE_CANVAS_PIXBUF);
+ e_day_view_type = g_type_class_ref (e_day_view_get_type ());
+ e_week_view_type = g_type_class_ref (e_week_view_get_type ());
+ e_day_view_main_item_type = g_type_class_ref (e_day_view_main_item_get_type ());
+ e_week_view_main_item_type = g_type_class_ref (e_week_view_main_item_get_type ());
+
+ g_signal_add_emission_hook (g_signal_lookup ("event", E_TYPE_TEXT),
+ 0, ea_calendar_focus_watcher,
+ NULL, (GDestroyNotify) NULL);
+ g_signal_add_emission_hook (g_signal_lookup ("event", GNOME_TYPE_CANVAS_PIXBUF),
+ 0, ea_calendar_focus_watcher,
+ NULL, (GDestroyNotify) NULL);
+ g_signal_add_emission_hook (g_signal_lookup ("event-after",
+ e_day_view_get_type()),
+ 0, ea_calendar_focus_watcher,
+ NULL, (GDestroyNotify) NULL);
+ g_signal_add_emission_hook (g_signal_lookup ("event",
+ e_day_view_main_item_get_type()),
+ 0, ea_calendar_focus_watcher,
+ NULL, (GDestroyNotify) NULL);
+ g_signal_add_emission_hook (g_signal_lookup ("event-after",
+ e_week_view_get_type()),
+ 0, ea_calendar_focus_watcher,
+ NULL, (GDestroyNotify) NULL);
+ g_signal_add_emission_hook (g_signal_lookup ("event",
+ e_week_view_main_item_get_type()),
+ 0, ea_calendar_focus_watcher,
+ NULL, (GDestroyNotify) NULL);
+
+ }
+}
+
+void
+e_cal_view_a11y_init (void)
+{
+ EA_SET_FACTORY (e_calendar_view_get_type(), ea_cal_view);
+}
+
+void
+e_day_view_a11y_init (void)
+{
+ EA_SET_FACTORY (e_day_view_get_type(), ea_day_view);
+}
+
+void
+e_day_view_main_item_a11y_init (void)
+{
+ EA_SET_FACTORY (e_day_view_main_item_get_type (), ea_day_view_main_item);
+}
+
+void
+e_week_view_a11y_init (void)
+{
+ EA_SET_FACTORY (e_week_view_get_type(), ea_week_view);
+}
+
+void
+e_week_view_main_item_a11y_init (void)
+{
+ EA_SET_FACTORY (e_week_view_main_item_get_type (), ea_week_view_main_item);
+}
+
+static gboolean
+ea_calendar_focus_watcher (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ GObject *object;
+ GdkEvent *event;
+ AtkObject *ea_event = NULL;
+
+ object = g_value_get_object (param_values + 0);
+ event = g_value_get_boxed (param_values + 1);
+
+ if ((E_IS_TEXT (object)) || (GNOME_IS_CANVAS_PIXBUF (object))) {
+ /* "event" signal on canvas item
+ */
+ GnomeCanvasItem *canvas_item;
+
+ canvas_item = GNOME_CANVAS_ITEM (object);
+ if (event->type == GDK_FOCUS_CHANGE) {
+ if (event->focus_change.in) {
+ ea_event =
+ ea_calendar_helpers_get_accessible_for (canvas_item);
+ if (!ea_event)
+ /* not canvas item we want */
+ return TRUE;
+
+ }
+ atk_focus_tracker_notify (ea_event);
+ }
+ }
+ else if (E_IS_DAY_VIEW (object)) {
+ EDayView *day_view = E_DAY_VIEW (object);
+ if (event->type == GDK_FOCUS_CHANGE) {
+ if (event->focus_change.in) {
+ /* give main item chance to emit focus */
+ gnome_canvas_item_grab_focus (day_view->main_canvas_item);
+ }
+ }
+ }
+ else if (E_IS_DAY_VIEW_MAIN_ITEM (object)) {
+ if (event->type == GDK_FOCUS_CHANGE) {
+ if (event->focus_change.in) {
+ /* we should emit focus on main item */
+ ea_event = atk_gobject_accessible_for_object (object);
+ }
+ else
+ /* focus out */
+ ea_event = NULL;
+#ifdef ACC_DEBUG
+ printf ("EvoAcc: focus notify on day main item %p\n", (void *)object);
+#endif
+ atk_focus_tracker_notify (ea_event);
+ }
+ } else if (E_IS_WEEK_VIEW (object)) {
+ EWeekView *week_view = E_WEEK_VIEW (object);
+ if (event->type == GDK_FOCUS_CHANGE) {
+ if (event->focus_change.in) {
+ /* give main item chance to emit focus */
+ gnome_canvas_item_grab_focus (week_view->main_canvas_item);
+ }
+ }
+ }
+ else if (E_IS_WEEK_VIEW_MAIN_ITEM (object)) {
+ if (event->type == GDK_FOCUS_CHANGE) {
+ if (event->focus_change.in) {
+ /* we should emit focus on main item */
+ ea_event = atk_gobject_accessible_for_object (object);
+ }
+ else
+ /* focus out */
+ ea_event = NULL;
+#ifdef ACC_DEBUG
+ printf ("EvoAcc: focus notify on week main item %p\n", (void *)object);
+#endif
+ atk_focus_tracker_notify (ea_event);
+ }
+ }
+ return TRUE;
+}
diff --cc calendar/gui/a11y/ea-day-view-cell.c
index 4698a3d,0000000..3555723
mode 100644,000000..100644
--- a/calendar/gui/a11y/ea-day-view-cell.c
+++ b/calendar/gui/a11y/ea-day-view-cell.c
@@@ -1,396 -1,0 +1,396 @@@
+/*
+ *
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Bolian Yin <bolian yin sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "ea-day-view-cell.h"
+#include "ea-day-view-main-item.h"
+#include "ea-day-view.h"
+#include "a11y/ea-factory.h"
+
+/* EDayViewCell */
+
+static void e_day_view_cell_class_init (EDayViewCellClass *class);
+
+EA_FACTORY_GOBJECT (EA_TYPE_DAY_VIEW_CELL, ea_day_view_cell, ea_day_view_cell_new)
+
+GType
+e_day_view_cell_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (EDayViewCellClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) e_day_view_cell_class_init, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (EDayViewCell), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "EDayViewCell", &tinfo, 0);
+ }
+
+ return type;
+}
+
+static void
+e_day_view_cell_class_init (EDayViewCellClass *class)
+{
+ EA_SET_FACTORY (e_day_view_cell_get_type (), ea_day_view_cell);
+}
+
+EDayViewCell *
+e_day_view_cell_new (EDayView *day_view, gint row, gint column)
+{
+ GObject *object;
+ EDayViewCell *cell;
+
+ g_return_val_if_fail (E_IS_DAY_VIEW (day_view), NULL);
+
+ object = g_object_new (E_TYPE_DAY_VIEW_CELL, NULL);
+ cell = E_DAY_VIEW_CELL (object);
+ cell->day_view = day_view;
+ cell->row = row;
+ cell->column = column;
+
+#ifdef ACC_DEBUG
+ printf ("EvoAcc: e_day_view_cell created %p\n", (void *)cell);
+#endif
+
+ return cell;
+}
+
+/* EaDayViewCell */
+
+static void ea_day_view_cell_class_init (EaDayViewCellClass *klass);
+
+static G_CONST_RETURN gchar* ea_day_view_cell_get_name (AtkObject *accessible);
+static G_CONST_RETURN gchar* ea_day_view_cell_get_description (AtkObject *accessible);
+static AtkStateSet* ea_day_view_cell_ref_state_set (AtkObject *obj);
+static AtkObject * ea_day_view_cell_get_parent (AtkObject *accessible);
+static gint ea_day_view_cell_get_index_in_parent (AtkObject *accessible);
+
+/* component interface */
+static void atk_component_interface_init (AtkComponentIface *iface);
+static void component_interface_get_extents (AtkComponent *component,
+ gint *x, gint *y,
+ gint *width, gint *height,
+ AtkCoordType coord_type);
+static gboolean component_interface_grab_focus (AtkComponent *component);
+
+static gpointer parent_class = NULL;
+
+#ifdef ACC_DEBUG
+static gint n_ea_day_view_cell_created = 0, n_ea_day_view_cell_destroyed = 0;
+static void ea_day_view_cell_finalize (GObject *object);
+#endif
+
+GType
+ea_day_view_cell_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (EaDayViewCellClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) ea_day_view_cell_class_init, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (EaDayViewCell), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ static const GInterfaceInfo atk_component_info = {
+ (GInterfaceInitFunc) atk_component_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE,
+ "EaDayViewCell", &tinfo, 0);
+ g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+ &atk_component_info);
+ }
+
+ return type;
+}
+
+static void
+ea_day_view_cell_class_init (EaDayViewCellClass *klass)
+{
+ AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+#ifdef ACC_DEBUG
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = ea_day_view_cell_finalize;
+#endif
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ class->get_name = ea_day_view_cell_get_name;
+ class->get_description = ea_day_view_cell_get_description;
+ class->ref_state_set = ea_day_view_cell_ref_state_set;
+
+ class->get_parent = ea_day_view_cell_get_parent;
+ class->get_index_in_parent = ea_day_view_cell_get_index_in_parent;
+}
+
+AtkObject*
+ea_day_view_cell_new (GObject *obj)
+{
+ gpointer object;
+ AtkObject *atk_object;
+
+ g_return_val_if_fail (E_IS_DAY_VIEW_CELL (obj), NULL);
+
+ object = g_object_new (EA_TYPE_DAY_VIEW_CELL, NULL);
+ atk_object = ATK_OBJECT (object);
+ atk_object_initialize (atk_object, obj);
+ atk_object->role = ATK_ROLE_UNKNOWN;
+
+#ifdef ACC_DEBUG
+ ++n_ea_day_view_cell_created;
+ printf ("ACC_DEBUG: n_ea_day_view_cell_created = %d\n",
+ n_ea_day_view_cell_created);
+#endif
+ return atk_object;
+}
+
+#ifdef ACC_DEBUG
+static void ea_day_view_cell_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+ ++n_ea_day_view_cell_destroyed;
+ printf ("ACC_DEBUG: n_ea_day_view_cell_destroyed = %d\n",
+ n_ea_day_view_cell_destroyed);
+}
+#endif
+
+static G_CONST_RETURN gchar*
+ea_day_view_cell_get_name (AtkObject *accessible)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EDayViewCell *cell;
+
+ g_return_val_if_fail (EA_IS_DAY_VIEW_CELL (accessible), NULL);
+
+ if (!accessible->name) {
+ AtkObject *ea_main_item;
+ GnomeCanvasItem *main_item;
+ gchar *new_name = g_strdup ("");
+ const gchar *row_label, *column_label;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return NULL;
+
+ cell = E_DAY_VIEW_CELL (g_obj);
+ main_item = cell->day_view->main_canvas_item;
+ ea_main_item = atk_gobject_accessible_for_object (G_OBJECT (main_item));
+ column_label = atk_table_get_column_description (ATK_TABLE (ea_main_item),
+ cell->column);
+ row_label = atk_table_get_row_description (ATK_TABLE (ea_main_item),
+ cell->row);
+ new_name = g_strconcat (column_label, " ", row_label, NULL);
+ ATK_OBJECT_CLASS (parent_class)->set_name (accessible, new_name);
+ g_free (new_name);
+ }
+ return accessible->name;
+}
+
+static G_CONST_RETURN gchar*
+ea_day_view_cell_get_description (AtkObject *accessible)
+{
+ return ea_day_view_cell_get_name (accessible);
+}
+
+static AtkStateSet*
+ea_day_view_cell_ref_state_set (AtkObject *obj)
+{
+ AtkStateSet *state_set;
+ GObject *g_obj;
+ AtkObject *parent;
+ gint x, y, width, height;
+ gint parent_x, parent_y, parent_width, parent_height;
+
+ state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(obj));
+ if (!g_obj)
+ return state_set;
+
+ atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
+
+ parent = atk_object_get_parent (obj);
+ atk_component_get_extents (ATK_COMPONENT (obj), &x, &y,
+ &width, &height, ATK_XY_WINDOW);
+ atk_component_get_extents (ATK_COMPONENT (parent), &parent_x, &parent_y,
+ &parent_width, &parent_height, ATK_XY_WINDOW);
+
+
+ if (x + width < parent_x || x > parent_x + parent_width ||
+ y + height < parent_y || y > parent_y + parent_height)
+ /* the cell is out of the main canvas */
+ ;
+ else
+ atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
+
+ return state_set;
+}
+
+static AtkObject *
+ea_day_view_cell_get_parent (AtkObject *accessible)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EDayViewCell *cell;
+
+ g_return_val_if_fail (EA_IS_DAY_VIEW_CELL (accessible), NULL);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return NULL;
+
+ cell = E_DAY_VIEW_CELL (g_obj);
+ return atk_gobject_accessible_for_object (G_OBJECT (cell->day_view->main_canvas_item));
+}
+
+static gint
+ea_day_view_cell_get_index_in_parent (AtkObject *accessible)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EDayViewCell *cell;
+ AtkObject *parent;
+
+ g_return_val_if_fail (EA_IS_DAY_VIEW_CELL (accessible), -1);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return -1;
+
+ cell = E_DAY_VIEW_CELL (g_obj);
+ parent = atk_object_get_parent (accessible);
+ return atk_table_get_index_at (ATK_TABLE (parent),
+ cell->row, cell->column);
+}
+
+/* Atk Component Interface */
+
+static void
+atk_component_interface_init (AtkComponentIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_extents = component_interface_get_extents;
+ iface->grab_focus = component_interface_grab_focus;
+}
+
+static void
+component_interface_get_extents (AtkComponent *component,
+ gint *x, gint *y, gint *width, gint *height,
+ AtkCoordType coord_type)
+{
+ GObject *g_obj;
+ AtkObject *atk_obj;
+ EDayViewCell *cell;
+ EDayView *day_view;
+ GtkWidget *main_canvas;
+ gint day_view_width, day_view_height;
+ gint scroll_x, scroll_y;
+
+ *x = *y = *width = *height = 0;
+
+ g_return_if_fail (EA_IS_DAY_VIEW_CELL (component));
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(component));
+ if (!g_obj)
+ /* defunct object*/
+ return;
+
+ cell = E_DAY_VIEW_CELL (g_obj);
+ day_view = cell->day_view;
+ main_canvas = cell->day_view->main_canvas;
+
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT (main_canvas));
+ atk_component_get_extents (ATK_COMPONENT (atk_obj),
+ x, y,
+ &day_view_width, &day_view_height,
+ coord_type);
+ gnome_canvas_get_scroll_offsets (GNOME_CANVAS (day_view->main_canvas),
+ &scroll_x, &scroll_y);
+ *x += day_view->day_offsets[cell->column] - scroll_x;
+ *y += day_view->row_height * cell->row
+ - scroll_y;
+ *width = day_view->day_widths[cell->column];
+ *height = day_view->row_height;
+}
+
+static gboolean
+component_interface_grab_focus (AtkComponent *comp)
+{
+ GObject *g_obj;
+ EDayViewCell *cell;
+ EDayView *day_view;
+ GtkWidget *toplevel;
+
+ g_return_val_if_fail (EA_IS_DAY_VIEW_CELL (comp), FALSE);
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (comp));
+ if (!g_obj)
+ return FALSE;
+
+ cell = E_DAY_VIEW_CELL (g_obj);
+ day_view = cell->day_view;
+
+ day_view->selection_start_day = cell->column;
+ day_view->selection_end_day = cell->column;
+ day_view->selection_start_row = cell->row;
+ day_view->selection_end_row = cell->row;
+
+ e_day_view_ensure_rows_visible (day_view,
+ day_view->selection_start_row,
+ day_view->selection_end_row);
+ e_day_view_update_calendar_selection_time (day_view);
+ gtk_widget_queue_draw (day_view->main_canvas);
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (day_view));
+ if (GTK_WIDGET_TOPLEVEL (toplevel))
+ gtk_window_present (GTK_WINDOW (toplevel));
+
+ return TRUE;
+}
+
diff --cc calendar/gui/a11y/ea-week-view-cell.c
index 3ec553b,0000000..b45cf66
mode 100644,000000..100644
--- a/calendar/gui/a11y/ea-week-view-cell.c
+++ b/calendar/gui/a11y/ea-week-view-cell.c
@@@ -1,478 -1,0 +1,478 @@@
+/*
+ *
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Bolian Yin <bolian yin sun com>
+ * Yang Wu <Yang Wu sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "ea-week-view-cell.h"
+#include "ea-week-view-main-item.h"
+#include "a11y/ea-factory.h"
+
+/* EWeekViewCell */
+
+static void e_week_view_cell_class_init (EWeekViewCellClass *class);
+
+EA_FACTORY_GOBJECT (EA_TYPE_WEEK_VIEW_CELL, ea_week_view_cell, ea_week_view_cell_new)
+
+GType
+e_week_view_cell_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (EWeekViewCellClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) e_week_view_cell_class_init, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (EWeekViewCell), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "EWeekViewCell", &tinfo, 0);
+ }
+
+ return type;
+}
+
+static void
+e_week_view_cell_class_init (EWeekViewCellClass *class)
+{
+ EA_SET_FACTORY (e_week_view_cell_get_type (), ea_week_view_cell);
+}
+
+EWeekViewCell *
+e_week_view_cell_new (EWeekView *week_view, gint row, gint column)
+{
+ GObject *object;
+ EWeekViewCell *cell;
+
+ g_return_val_if_fail (E_IS_WEEK_VIEW (week_view), NULL);
+
+ object = g_object_new (E_TYPE_WEEK_VIEW_CELL, NULL);
+ cell = E_WEEK_VIEW_CELL (object);
+ cell->week_view = week_view;
+ cell->row = row;
+ cell->column = column;
+
+#ifdef ACC_DEBUG
+ printf ("EvoAcc: e_week_view_cell created %p\n", (void *)cell);
+#endif
+
+ return cell;
+}
+
+/* EaWeekViewCell */
+
+static void ea_week_view_cell_class_init (EaWeekViewCellClass *klass);
+
+static G_CONST_RETURN gchar* ea_week_view_cell_get_name (AtkObject *accessible);
+static G_CONST_RETURN gchar* ea_week_view_cell_get_description (AtkObject *accessible);
+static AtkStateSet* ea_week_view_cell_ref_state_set (AtkObject *obj);
+static AtkObject * ea_week_view_cell_get_parent (AtkObject *accessible);
+static gint ea_week_view_cell_get_index_in_parent (AtkObject *accessible);
+
+/* component interface */
+static void atk_component_interface_init (AtkComponentIface *iface);
+static void component_interface_get_extents (AtkComponent *component,
+ gint *x, gint *y,
+ gint *width, gint *height,
+ AtkCoordType coord_type);
+static gboolean component_interface_grab_focus (AtkComponent *component);
+
+static gpointer parent_class = NULL;
+
+#ifdef ACC_DEBUG
+static gint n_ea_week_view_cell_created = 0, n_ea_week_view_cell_destroyed = 0;
+static void ea_week_view_cell_finalize (GObject *object);
+#endif
+
+GType
+ea_week_view_cell_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (EaWeekViewCellClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) ea_week_view_cell_class_init, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (EaWeekViewCell), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ static const GInterfaceInfo atk_component_info = {
+ (GInterfaceInitFunc) atk_component_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE,
+ "EaWeekViewCell", &tinfo, 0);
+ g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+ &atk_component_info);
+
+ }
+
+ return type;
+}
+
+static void
+ea_week_view_cell_class_init (EaWeekViewCellClass *klass)
+{
+ AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+#ifdef ACC_DEBUG
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = ea_week_view_cell_finalize;
+#endif
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ class->get_name = ea_week_view_cell_get_name;
+ class->get_description = ea_week_view_cell_get_description;
+ class->ref_state_set = ea_week_view_cell_ref_state_set;
+
+ class->get_parent = ea_week_view_cell_get_parent;
+ class->get_index_in_parent = ea_week_view_cell_get_index_in_parent;
+
+}
+
+AtkObject*
+ea_week_view_cell_new (GObject *obj)
+{
+ gpointer object;
+ AtkObject *atk_object;
+
+ g_return_val_if_fail (E_IS_WEEK_VIEW_CELL (obj), NULL);
+ object = g_object_new (EA_TYPE_WEEK_VIEW_CELL, NULL);
+ atk_object = ATK_OBJECT (object);
+ atk_object_initialize (atk_object, obj);
+ atk_object->role = ATK_ROLE_UNKNOWN;
+
+#ifdef ACC_DEBUG
+ ++n_ea_week_view_cell_created;
+ printf ("ACC_DEBUG: n_ea_week_view_cell_created = %d\n",
+ n_ea_week_view_cell_created);
+#endif
+ return atk_object;
+}
+
+#ifdef ACC_DEBUG
+static void ea_week_view_cell_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+ ++n_ea_week_view_cell_destroyed;
+ printf ("ACC_DEBUG: n_ea_week_view_cell_destroyed = %d\n",
+ n_ea_week_view_cell_destroyed);
+}
+#endif
+
+static G_CONST_RETURN gchar*
+ea_week_view_cell_get_name (AtkObject *accessible)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EWeekViewCell *cell;
+
+ g_return_val_if_fail (EA_IS_WEEK_VIEW_CELL (accessible), NULL);
+
+ if (!accessible->name) {
+ AtkObject *ea_main_item;
+ GnomeCanvasItem *main_item;
+ gchar *new_name = g_strdup ("");
+ const gchar *row_label, *column_label;
+ gint new_column, new_row;
+ gint start_day;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return NULL;
+
+ cell = E_WEEK_VIEW_CELL (g_obj);
+ main_item = cell->week_view->main_canvas_item;
+ ea_main_item = atk_gobject_accessible_for_object (G_OBJECT (main_item));
+
+ start_day = cell->week_view->display_start_day;
+ if (cell->column + start_day >= 7) {
+ new_column = cell->column + start_day - 7;
+ new_row = cell->row + 1;
+ } else {
+ new_column = cell->column + start_day;
+ new_row = cell->row;
+ }
+
+ column_label = atk_table_get_column_description (ATK_TABLE (ea_main_item),
+ new_column);
+ row_label = atk_table_get_row_description (ATK_TABLE (ea_main_item),
+ new_row);
+ new_name = g_strconcat (column_label, " ", row_label, NULL);
+ ATK_OBJECT_CLASS (parent_class)->set_name (accessible, new_name);
+ g_free (new_name);
+ }
+ return accessible->name;
+}
+
+static G_CONST_RETURN gchar*
+ea_week_view_cell_get_description (AtkObject *accessible)
+{
+ return ea_week_view_cell_get_name (accessible);
+}
+
+static AtkStateSet*
+ea_week_view_cell_ref_state_set (AtkObject *obj)
+{
+ AtkStateSet *state_set;
+ GObject *g_obj;
+ AtkObject *parent;
+ gint x, y, width, height;
+ gint parent_x, parent_y, parent_width, parent_height;
+
+ state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (obj);
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(obj));
+ if (!g_obj)
+ return state_set;
+
+ atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
+
+ parent = atk_object_get_parent (obj);
+ atk_component_get_extents (ATK_COMPONENT (obj), &x, &y,
+ &width, &height, ATK_XY_WINDOW);
+ atk_component_get_extents (ATK_COMPONENT (parent), &parent_x, &parent_y,
+ &parent_width, &parent_height, ATK_XY_WINDOW);
+
+
+ if (x + width < parent_x || x > parent_x + parent_width ||
+ y + height < parent_y || y > parent_y + parent_height)
+ /* the cell is out of the main canvas */
+ ;
+ else
+ atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
+
+ return state_set;
+}
+
+static AtkObject *
+ea_week_view_cell_get_parent (AtkObject *accessible)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EWeekViewCell *cell;
+
+ g_return_val_if_fail (EA_IS_WEEK_VIEW_CELL (accessible), NULL);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return NULL;
+
+ cell = E_WEEK_VIEW_CELL (g_obj);
+ return atk_gobject_accessible_for_object (G_OBJECT (cell->week_view->main_canvas_item));
+}
+
+static gint
+ea_week_view_cell_get_index_in_parent (AtkObject *accessible)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EWeekViewCell *cell;
+ AtkObject *parent;
+
+ g_return_val_if_fail (EA_IS_WEEK_VIEW_CELL (accessible), -1);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return -1;
+
+ cell = E_WEEK_VIEW_CELL (g_obj);
+ parent = atk_object_get_parent (accessible);
+ return atk_table_get_index_at (ATK_TABLE (parent),
+ cell->row, cell->column);
+}
+
+/* Atk Component Interface */
+
+static void
+atk_component_interface_init (AtkComponentIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_extents = component_interface_get_extents;
+ iface->grab_focus = component_interface_grab_focus;
+}
+
+static void
+component_interface_get_extents (AtkComponent *component,
+ gint *x, gint *y, gint *width, gint *height,
+ AtkCoordType coord_type)
+{
+ GObject *g_obj;
+ AtkObject *atk_obj;
+ EWeekViewCell *cell;
+ EWeekView *week_view;
+ GtkWidget *main_canvas;
+ gint week_view_width, week_view_height;
+ gint scroll_x, scroll_y;
+ gint start_day;
+
+ *x = *y = *width = *height = 0;
+
+ g_return_if_fail (EA_IS_WEEK_VIEW_CELL (component));
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(component));
+ if (!g_obj)
+ /* defunct object*/
+ return;
+
+ cell = E_WEEK_VIEW_CELL (g_obj);
+ week_view = cell->week_view;
+ main_canvas = cell->week_view->main_canvas;
+
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT (main_canvas));
+ atk_component_get_extents (ATK_COMPONENT (atk_obj),
+ x, y,
+ &week_view_width, &week_view_height,
+ coord_type);
+ gnome_canvas_get_scroll_offsets (GNOME_CANVAS (week_view->main_canvas),
+ &scroll_x, &scroll_y);
+ start_day = week_view->display_start_day;
+ if (week_view->multi_week_view) {
+ if (week_view->compress_weekend && (cell->column == (5 - start_day))) {
+ *height = week_view->row_heights[cell->row*2];
+ *width = week_view->col_widths[cell->column];
+ *x += week_view->col_offsets[cell->column] - scroll_x;
+ *y += week_view->row_offsets[cell->row*2]- scroll_y;
+ } else if (week_view->compress_weekend && (cell->column == (6 - start_day))) {
+ *height = week_view->row_heights[cell->row*2];
+ *width = week_view->col_widths[cell->column - 1];
+ *x += week_view->col_offsets[cell->column - 1]- scroll_x;
+ *y += week_view->row_offsets[cell->row*2 + 1]- scroll_y;
+ } else if (week_view->compress_weekend && (cell->column > (6 - start_day))){
+ *height = week_view->row_heights[cell->row*2]*2;
+ *width = week_view->col_widths[cell->column - 1];
+ *x += week_view->col_offsets[cell->column - 1] - scroll_x;
+ *y += week_view->row_offsets[cell->row*2]- scroll_y;
+ } else {
+ *height = week_view->row_heights[cell->row*2]*2;
+ *width = week_view->col_widths[cell->column];
+ *x += week_view->col_offsets[cell->column] - scroll_x;
+ *y += week_view->row_offsets[cell->row*2]- scroll_y;
+ }
+ } else {
+ if (start_day < 3) {
+ if (cell->column < 3) {
+ *height = week_view->row_heights[cell->column*2]*2;
+ *width = week_view->col_widths[0];
+ *x += week_view->col_offsets[0] - scroll_x;
+ *y += week_view->row_offsets[cell->column*2]- scroll_y;
+ } else {
+ if (cell->column == 5 - start_day) {
+ *height = week_view->row_heights[(cell->column - 3)*2];
+ *width = week_view->col_widths[1];
+ *x += week_view->col_offsets[1] - scroll_x;
+ *y += week_view->row_offsets[(cell->column - 3)*2]- scroll_y;
+ } else if (cell->column == 6 - start_day) {
+ *height = week_view->row_heights[(cell->column - 4)*2];
+ *width = week_view->col_widths[1];
+ *x += week_view->col_offsets[1] - scroll_x;
+ *y += week_view->row_offsets[(cell->column - 3)*2 - 1]- scroll_y;
+ } else if (cell->column > 6 - start_day) {
+ *height = week_view->row_heights[(cell->column - 4)*2]*2;
+ *width = week_view->col_widths[1];
+ *x += week_view->col_offsets[1] - scroll_x;
+ *y += week_view->row_offsets[(cell->column - 4)*2]- scroll_y;
+ } else {
+ *height = week_view->row_heights[(cell->column - 3)*2]*2;
+ *width = week_view->col_widths[1];
+ *x += week_view->col_offsets[1] - scroll_x;
+ *y += week_view->row_offsets[(cell->column - 3)*2]- scroll_y;
+ }
+ }
+ } else if (cell->column < 4) {
+ if (cell->column == 5 - start_day) {
+ *height = week_view->row_heights[cell->column*2];
+ *width = week_view->col_widths[0];
+ *x += week_view->col_offsets[0] - scroll_x;
+ *y += week_view->row_offsets[cell->column*2]- scroll_y;
+ } else if (cell->column == 6 - start_day) {
+ *height = week_view->row_heights[(cell->column - 1)*2];
+ *width = week_view->col_widths[0];
+ *x += week_view->col_offsets[0] - scroll_x;
+ *y += week_view->row_offsets[cell->column*2 - 1]- scroll_y;
+ } else if (cell->column > 6 - start_day) {
+ *height = week_view->row_heights[(cell->column - 1)*2]*2;
+ *width = week_view->col_widths[0];
+ *x += week_view->col_offsets[0] - scroll_x;
+ *y += week_view->row_offsets[(cell->column - 1)*2]- scroll_y;
+ } else {
+ *height = week_view->row_heights[(cell->column)*2]*2;
+ *width = week_view->col_widths[0];
+ *x += week_view->col_offsets[0] - scroll_x;
+ *y += week_view->row_offsets[cell->column*2]- scroll_y;
+ }
+ } else {
+ *height = week_view->row_heights[(cell->column - 4)*2]*2;
+ *width = week_view->col_widths[1];
+ *x += week_view->col_offsets[1] - scroll_x;
+ *y += week_view->row_offsets[(cell->column - 4)*2]- scroll_y;
+ }
+ }
+}
+
+static gboolean
+component_interface_grab_focus (AtkComponent *comp)
+{
+ GObject *g_obj;
+ EWeekViewCell *cell;
+ EWeekView *week_view;
+ GtkWidget *toplevel;
+
+ g_return_val_if_fail (EA_IS_WEEK_VIEW_CELL (comp), FALSE);
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (comp));
+ if (!g_obj)
+ return FALSE;
+
+ cell = E_WEEK_VIEW_CELL (g_obj);
+ week_view = cell->week_view;
+
+ week_view->selection_start_day = cell->row * 7 + cell->column;
+ week_view->selection_end_day = cell->row * 7 + cell->column;
+ gtk_widget_queue_draw (week_view->main_canvas);
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (week_view));
+ if (GTK_WIDGET_TOPLEVEL (toplevel))
+ gtk_window_present (GTK_WINDOW (toplevel));
+
+ return TRUE;
+}
diff --cc calendar/gui/calendar-component.c
index 2aaaaf2,bca0832..eef60cf
--- a/calendar/gui/calendar-component.c
+++ b/calendar/gui/calendar-component.c
@@@ -65,9 -65,26 +65,9 @@@
#define CREATE_MEETING_ID "meeting"
#define CREATE_ALLDAY_EVENT_ID "allday-event"
#define CREATE_CALENDAR_ID "calendar"
-#define WEB_BASE_URI "webcal://"
-#define CONTACTS_BASE_URI "contacts://"
-#define WEATHER_BASE_URI "weather://"
-#define PERSONAL_RELATIVE_URI "system"
#define CALENDAR_ERROR_LEVEL_KEY "/apps/evolution/calendar/display/error_level"
- #define CALENDAR_ERROR_TIME_OUT_KEY "/apps/evolution/calendar/display/error_timeout"
+ #define CALENDAR_ERROR_TIME_OUT_KEY "/apps/evolution/calendar/display/error_timeout"
-enum DndTargetType {
- DND_TARGET_TYPE_CALENDAR_LIST
-};
-#define CALENDAR_TYPE "text/calendar"
-#define XCALENDAR_TYPE "text/x-calendar"
-static GtkTargetEntry drag_types[] = {
- { (gchar *) CALENDAR_TYPE, 0, DND_TARGET_TYPE_CALENDAR_LIST },
- { (gchar *) XCALENDAR_TYPE, 0, DND_TARGET_TYPE_CALENDAR_LIST }
-};
-static gint num_drag_types = sizeof(drag_types) / sizeof(drag_types[0]);
-#define CALENDAR_COMPONENT_DEFAULT(cc) if (cc == NULL) cc = calendar_component_peek()
-#define PARENT_TYPE bonobo_object_get_type ()
-
static BonoboObjectClass *parent_class = NULL;
typedef struct
@@@ -708,9 -1608,68 +709,7 @@@ calendar_component_init (CalendarCompon
e_activity_handler_set_error_flush_time (priv->activity_handler,eni_config_get_error_timeout (CALENDAR_ERROR_TIME_OUT_KEY)*1000);
component->priv = priv;
- ensure_sources (component);
- if (!e_cal_get_sources (&priv->task_source_list, E_CAL_SOURCE_TYPE_TODO, NULL))
- ;
- if (!e_cal_get_sources (&priv->memo_source_list, E_CAL_SOURCE_TYPE_JOURNAL, NULL))
- ;
+ e_cal_get_sources (&priv->task_source_list, E_CAL_SOURCE_TYPE_TODO, NULL);
+ e_cal_get_sources (&priv->memo_source_list, E_CAL_SOURCE_TYPE_JOURNAL, NULL);
}
-
-
-/* Public API. */
-
-CalendarComponent *
-calendar_component_peek (void)
-{
- static CalendarComponent *component = NULL;
-
- if (component == NULL) {
- component = g_object_new (calendar_component_get_type (), NULL);
-
- if (g_mkdir_with_parents (calendar_component_peek_config_directory (component), 0777) != 0) {
- g_warning (G_STRLOC ": Cannot create directory %s: %s",
- calendar_component_peek_config_directory (component),
- g_strerror (errno));
- g_object_unref (component);
- component = NULL;
- }
- }
-
- return component;
-}
-
-const char *
-calendar_component_peek_base_directory (CalendarComponent *component)
-{
- return component->priv->base_directory;
-}
-
-const char *
-calendar_component_peek_config_directory (CalendarComponent *component)
-{
- return component->priv->config_directory;
-}
-
-ESourceList *
-calendar_component_peek_source_list (CalendarComponent *component)
-{
- return component->priv->source_list;
-}
-
-EActivityHandler *
-calendar_component_peek_activity_handler (CalendarComponent *component)
-{
- CALENDAR_COMPONENT_DEFAULT(component);
-
- return component->priv->activity_handler;
-}
-
-void
-calendar_component_show_logger (gpointer top)
-{
- CalendarComponent *cc = calendar_component_peek ();
- ELogger *logger = cc->priv->logger;
-
- eni_show_logger(logger, top, CALENDAR_ERROR_TIME_OUT_KEY, CALENDAR_ERROR_LEVEL_KEY);
-}
-
-BONOBO_TYPE_FUNC_FULL (CalendarComponent, GNOME_Evolution_Component, PARENT_TYPE, calendar_component)
diff --cc calendar/gui/e-calendar-view.c
index cc51599,91f9ede..975052b
--- a/calendar/gui/e-calendar-view.c
+++ b/calendar/gui/e-calendar-view.c
@@@ -1775,34 -1808,97 +1775,34 @@@ static EPopupItem ecv_main_items [] =
};
static EPopupItem ecv_child_items [] = {
- { E_POPUP_ITEM, "00.open", N_("_Open"), on_edit_appointment, NULL, GTK_STOCK_OPEN, 0, E_CAL_POPUP_SELECT_NOTEDITING },
- { E_POPUP_ITEM, "10.saveas", N_("_Save As..."), on_save_as, NULL, GTK_STOCK_SAVE_AS, 0, E_CAL_POPUP_SELECT_NOTEDITING },
- { E_POPUP_ITEM, "20.print", N_("Pri_nt..."), on_print_event, NULL, GTK_STOCK_PRINT, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ { E_POPUP_ITEM, (gchar *) "00.open", (gchar *) N_("_Open"), on_edit_appointment, NULL, (gchar *) GTK_STOCK_OPEN, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ { E_POPUP_ITEM, (gchar *) "10.saveas", (gchar *) N_("_Save As..."), on_save_as, NULL, (gchar *) GTK_STOCK_SAVE_AS, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ { E_POPUP_ITEM, (gchar *) "20.print", (gchar *) N_("Pri_nt..."), on_print_event, NULL, (gchar *) GTK_STOCK_PRINT, 0, E_CAL_POPUP_SELECT_NOTEDITING },
- { E_POPUP_BAR, "30." },
+ { E_POPUP_BAR, (gchar *) "30." },
- { E_POPUP_ITEM, "31.cut", N_("C_ut"), on_cut, NULL, GTK_STOCK_CUT, 0, E_CAL_POPUP_SELECT_NOTEDITING|E_CAL_POPUP_SELECT_EDITABLE|E_CAL_POPUP_SELECT_ORGANIZER },
- { E_POPUP_ITEM, "32.copy", N_("_Copy"), on_copy, NULL, GTK_STOCK_COPY, 0, E_CAL_POPUP_SELECT_NOTEDITING|E_CAL_POPUP_SELECT_ORGANIZER },
- { E_POPUP_ITEM, "33.paste", N_("_Paste"), on_paste, NULL, GTK_STOCK_PASTE, 0, E_CAL_POPUP_SELECT_EDITABLE },
+ { E_POPUP_ITEM, (gchar *) "31.cut", (gchar *) N_("C_ut"), on_cut, NULL, (gchar *) GTK_STOCK_CUT, 0, E_CAL_POPUP_SELECT_NOTEDITING|E_CAL_POPUP_SELECT_EDITABLE|E_CAL_POPUP_SELECT_ORGANIZER },
+ { E_POPUP_ITEM, (gchar *) "32.copy", (gchar *) N_("_Copy"), on_copy, NULL, (gchar *) GTK_STOCK_COPY, 0, E_CAL_POPUP_SELECT_NOTEDITING|E_CAL_POPUP_SELECT_ORGANIZER },
+ { E_POPUP_ITEM, (gchar *) "33.paste", (gchar *) N_("_Paste"), on_paste, NULL, (gchar *) GTK_STOCK_PASTE, 0, E_CAL_POPUP_SELECT_EDITABLE },
- { E_POPUP_BAR, "40." },
+ { E_POPUP_BAR, (gchar *) "40." },
- { E_POPUP_ITEM, "43.copyto", N_("Cop_y to Calendar..."), on_copy_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING },
- { E_POPUP_ITEM, "44.moveto", N_("Mo_ve to Calendar..."), on_move_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "45.delegate", N_("_Delegate Meeting..."), on_delegate, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_DELEGATABLE | E_CAL_POPUP_SELECT_MEETING},
- { E_POPUP_ITEM, "46.schedule", N_("_Schedule Meeting..."), on_meeting, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_NOTMEETING },
- { E_POPUP_ITEM, "47.forward", N_("_Forward as iCalendar..."), on_forward, NULL, "mail-forward", 0, E_CAL_POPUP_SELECT_NOTEDITING },
- { E_POPUP_ITEM, "48.reply", N_("_Reply"), on_reply, NULL, "mail-reply-sender", E_CAL_POPUP_SELECT_MEETING | E_CAL_POPUP_SELECT_NOSAVESCHEDULES, E_CAL_POPUP_SELECT_NOTEDITING },
- { E_POPUP_ITEM, "49.reply-all", N_("Reply to _All"), on_reply_all, NULL, "mail-reply-all", E_CAL_POPUP_SELECT_MEETING | E_CAL_POPUP_SELECT_NOSAVESCHEDULES, E_CAL_POPUP_SELECT_NOTEDITING },
+ { E_POPUP_ITEM, (gchar *) "43.copyto", (gchar *) N_("Cop_y to Calendar..."), on_copy_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ { E_POPUP_ITEM, (gchar *) "44.moveto", (gchar *) N_("Mo_ve to Calendar..."), on_move_to, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ { E_POPUP_ITEM, (gchar *) "45.delegate", (gchar *) N_("_Delegate Meeting..."), on_delegate, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_DELEGATABLE | E_CAL_POPUP_SELECT_MEETING},
+ { E_POPUP_ITEM, (gchar *) "46.schedule", (gchar *) N_("_Schedule Meeting..."), on_meeting, NULL, NULL, 0, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE | E_CAL_POPUP_SELECT_NOTMEETING },
+ { E_POPUP_ITEM, (gchar *) "47.forward", (gchar *) N_("_Forward as iCalendar..."), on_forward, NULL, (gchar *) "mail-forward", 0, E_CAL_POPUP_SELECT_NOTEDITING },
+ { E_POPUP_ITEM, (gchar *) "48.reply", (gchar *) N_("_Reply"), on_reply, NULL, (gchar *) "mail-reply-sender", E_CAL_POPUP_SELECT_MEETING | E_CAL_POPUP_SELECT_NOSAVESCHEDULES, E_CAL_POPUP_SELECT_NOTEDITING },
+ { E_POPUP_ITEM, (gchar *) "49.reply-all", (gchar *) N_("Reply to _All"), on_reply_all, NULL, (gchar *) "mail-reply-all", E_CAL_POPUP_SELECT_MEETING | E_CAL_POPUP_SELECT_NOSAVESCHEDULES, E_CAL_POPUP_SELECT_NOTEDITING },
- { E_POPUP_BAR, "50." },
+ { E_POPUP_BAR, (gchar *) "50." },
- { E_POPUP_ITEM, "51.delete", N_("_Delete"), on_delete_appointment, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_NONRECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "52.move", N_("Make this Occurrence _Movable"), on_unrecur_appointment, NULL, NULL, E_CAL_POPUP_SELECT_RECURRING | E_CAL_POPUP_SELECT_INSTANCE, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "53.delete", N_("Delete this _Occurrence"), on_delete_occurrence, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_RECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
- { E_POPUP_ITEM, "54.delete", N_("Delete _All Occurrences"), on_delete_appointment, NULL, GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_RECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ { E_POPUP_ITEM, (gchar *) "51.delete", (gchar *) N_("_Delete"), on_delete_appointment, NULL, (gchar *) GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_NONRECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ { E_POPUP_ITEM, (gchar *) "52.move", (gchar *) N_("Make this Occurrence _Movable"), on_unrecur_appointment, NULL, NULL, E_CAL_POPUP_SELECT_RECURRING | E_CAL_POPUP_SELECT_INSTANCE, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ { E_POPUP_ITEM, (gchar *) "53.delete", (gchar *) N_("Delete this _Occurrence"), on_delete_occurrence, NULL, (gchar *) GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_RECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
+ { E_POPUP_ITEM, (gchar *) "54.delete", (gchar *) N_("Delete _All Occurrences"), on_delete_appointment, NULL, (gchar *) GTK_STOCK_DELETE, E_CAL_POPUP_SELECT_RECURRING, E_CAL_POPUP_SELECT_NOTEDITING | E_CAL_POPUP_SELECT_EDITABLE },
};
-static void
-ecv_popup_free (EPopup *ep, GSList *list, void *data)
-{
- g_slist_free(list);
-}
-
-GtkMenu *
-e_calendar_view_create_popup_menu (ECalendarView *cal_view)
-{
- ECalPopup *ep;
- GSList *menus = NULL;
- GList *selected, *l;
- int i;
- ECalPopupTargetSelect *t;
- ECalModel *model;
- GPtrArray *events;
-
- g_return_val_if_fail (E_IS_CALENDAR_VIEW (cal_view), NULL);
-
- /* We could do this using a factory on the ECalPopup class,
- * that way we would get called implicitly whenever a popup
- * menu was created rather than everyone having to call us.
- * We could also have a different menu id for each view */
-
- /** @HookPoint-ECalPopup: Calendar Main View Context Menu
- * @Id: org.gnome.evolution.calendar.view.popup
- * @Class: org.gnome.evolution.calendar.popup:1.0
- * @Target: ECalPopupTargetSelect
- *
- * The context menu on the main calendar view. This menu
- * applies to all view types.
- */
- ep = e_cal_popup_new("org.gnome.evolution.calendar.view.popup");
-
- model = e_calendar_view_get_model(cal_view);
- events = g_ptr_array_new();
- selected = e_calendar_view_get_selected_events(cal_view);
- for (l=selected;l;l=g_list_next(l)) {
- ECalendarViewEvent *event = l->data;
-
- if (event)
- g_ptr_array_add(events, e_cal_model_copy_component_data(event->comp_data));
- }
- g_list_free(selected);
-
- t = e_cal_popup_target_new_select(ep, model, events);
- t->target.widget = (GtkWidget *)cal_view;
-
- if (t->events->len == 0) {
- for (i=0;i<sizeof(ecv_main_items)/sizeof(ecv_main_items[0]);i++)
- menus = g_slist_prepend(menus, &ecv_main_items[i]);
-
- gnome_calendar_view_popup_factory(cal_view->priv->calendar, (EPopup *)ep, "60.view");
- } else {
- for (i=0;i<sizeof(ecv_child_items)/sizeof(ecv_child_items[0]);i++)
- menus = g_slist_prepend(menus, &ecv_child_items[i]);
- }
-
- e_popup_add_items((EPopup *)ep, menus, NULL, ecv_popup_free, cal_view);
-
- return e_popup_create_menu_once((EPopup *)ep, (EPopupTarget *)t, 0);
-}
-
void
e_calendar_view_open_event (ECalendarView *cal_view)
{
@@@ -2564,11 -2657,32 +2564,11 @@@ draw_curved_rectangle (cairo_t *cr, dou
cairo_close_path (cr);
}
- static void
+ static void
error_response(GtkWidget *widget, gint response, void *data)
{
- if (response == GTK_RESPONSE_DELETE_EVENT)
- gtk_widget_destroy (widget);
-}
-
-void
-e_calendar_utils_show_error_silent (GtkWidget *widget)
-{
- EActivityHandler *handler = calendar_component_peek_activity_handler (calendar_component_peek ());
-
- if(!g_object_get_data ((GObject *) widget, "response-handled")) {
- g_signal_connect(widget, "response", G_CALLBACK(error_response), NULL);
- }
-
- e_activity_handler_make_error (handler, "calendar", E_LOG_ERROR, widget);
-}
-
-void
-e_calendar_utils_show_info_silent (GtkWidget *widget)
-{
- EActivityHandler *handler = calendar_component_peek_activity_handler (calendar_component_peek ());
-
- if(!g_object_get_data ((GObject *) widget, "response-handled")) {
- g_signal_connect(widget, "response", G_CALLBACK(error_response), NULL);
- }
-
- e_activity_handler_make_error (handler, "calendar", E_LOG_WARNINGS, widget);
++ if (response == GTK_RESPONSE_DELETE_EVENT)
+ gtk_widget_destroy(widget);
- else if (response == GTK_RESPONSE_OK)
++ else if (response == GTK_RESPONSE_OK)
+ gtk_widget_destroy(widget);
}
diff --cc calendar/gui/e-memo-list-selector.c
index 9d34089,0000000..e31a9d4
mode 100644,000000..100644
--- a/calendar/gui/e-memo-list-selector.c
+++ b/calendar/gui/e-memo-list-selector.c
@@@ -1,287 -1,0 +1,287 @@@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-memo-list-selector.c
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU 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 General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "e-memo-list-selector.h"
+
+#include <string.h>
+#include <libecal/e-cal.h>
+#include "calendar/common/authentication.h"
+#include "calendar/gui/comp-util.h"
+
+#define E_MEMO_LIST_SELECTOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_LIST_SELECTOR, EMemoListSelectorPrivate))
+
+struct _EMemoListSelectorPrivate {
+ gint dummy_value;
+};
+
+enum {
+ DND_TARGET_TYPE_CALENDAR_LIST
+};
+
+static GtkTargetEntry drag_types[] = {
- { "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST },
- { "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }
++ { (gchar *) "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST },
++ { (gchar *) "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }
+};
+
+static gpointer parent_class;
+
+static gboolean
+memo_list_selector_update_single_object (ECal *client,
+ icalcomponent *icalcomp)
+{
+ gchar *uid;
+ icalcomponent *tmp_icalcomp;
+
+ uid = (gchar *) icalcomponent_get_uid (icalcomp);
+
+ if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, NULL))
+ return e_cal_modify_object (
+ client, icalcomp, CALOBJ_MOD_ALL, NULL);
+
+ return e_cal_create_object (client, icalcomp, &uid, NULL);
+}
+
+static gboolean
+memo_list_selector_update_objects (ECal *client,
+ icalcomponent *icalcomp)
+{
+ icalcomponent *subcomp;
+ icalcomponent_kind kind;
+
+ kind = icalcomponent_isa (icalcomp);
+ if (kind == ICAL_VJOURNAL_COMPONENT)
+ return memo_list_selector_update_single_object (
+ client, icalcomp);
+ else if (kind != ICAL_VCALENDAR_COMPONENT)
+ return FALSE;
+
+ subcomp = icalcomponent_get_first_component (
+ icalcomp, ICAL_ANY_COMPONENT);
+ while (subcomp != NULL) {
+ gboolean success;
+
+ kind = icalcomponent_isa (subcomp);
+ if (kind == ICAL_VTIMEZONE_COMPONENT) {
+ icaltimezone *zone;
+
+ zone = icaltimezone_new ();
+ icaltimezone_set_component (zone, subcomp);
+
+ success = e_cal_add_timezone (client, zone, NULL);
+ icaltimezone_free (zone, 1);
+ if (!success)
+ return FALSE;
+ } else if (kind == ICAL_VJOURNAL_COMPONENT) {
+ success = memo_list_selector_update_single_object (
+ client, subcomp);
+ if (!success)
+ return FALSE;
+ }
+
+ subcomp = icalcomponent_get_next_component (
+ icalcomp, ICAL_ANY_COMPONENT);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+memo_list_selector_process_data (ESourceSelector *selector,
+ ECal *client,
+ const gchar *source_uid,
+ icalcomponent *icalcomp,
+ GdkDragAction action)
+{
+ ESourceList *source_list;
+ ESource *source;
+ icalcomponent *tmp_icalcomp = NULL;
+ const gchar *uid;
+ gchar *old_uid = NULL;
+ gboolean success = FALSE;
+ gboolean read_only = TRUE;
+ GError *error = NULL;
+
+ /* FIXME Deal with GDK_ACTION_ASK. */
+ if (action == GDK_ACTION_COPY) {
+ old_uid = g_strdup (icalcomponent_get_uid (icalcomp));
+ uid = e_cal_component_gen_uid ();
+ icalcomponent_set_uid (icalcomp, uid);
+ }
+
+ uid = icalcomponent_get_uid (icalcomp);
+ if (old_uid == NULL)
+ old_uid = g_strdup (uid);
+
+ if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, &error)) {
+ icalcomponent_free (tmp_icalcomp);
+ success = TRUE;
+ goto exit;
+ }
+
+ if (error != NULL && error->code != E_CALENDAR_STATUS_OBJECT_NOT_FOUND) {
+ g_message (
+ "Failed to search the object in destination "
+ "task list: %s", error->message);
+ g_error_free (error);
+ goto exit;
+ }
+
+ success = memo_list_selector_update_objects (client, icalcomp);
+
+ if (!success || action != GDK_ACTION_MOVE)
+ goto exit;
+
+ source_list = e_source_selector_get_source_list (selector);
+ source = e_source_list_peek_source_by_uid (source_list, source_uid);
+
+ if (!E_IS_SOURCE (source) || e_source_get_readonly (source))
+ goto exit;
+
+ client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
+ if (client == NULL) {
+ g_message ("Cannot create source client to remove old memo");
+ goto exit;
+ }
+
+ e_cal_is_read_only (client, &read_only, NULL);
+ if (!read_only && e_cal_open (client, TRUE, NULL))
+ e_cal_remove_object (client, old_uid, NULL);
+ else if (!read_only)
+ g_message ("Cannot open source client to remove old memo");
+
+ g_object_unref (client);
+
+exit:
+ g_free (old_uid);
+
+ return success;
+}
+
+static gboolean
+memo_list_selector_data_dropped (ESourceSelector *selector,
+ GtkSelectionData *selection_data,
+ ESource *destination,
+ GdkDragAction action,
+ guint info)
+{
+ ECal *client;
+ GSList *list, *iter;
+ gboolean success = FALSE;
+
+ client = auth_new_cal_from_source (
+ destination, E_CAL_SOURCE_TYPE_JOURNAL);
+
+ if (client == NULL || !e_cal_open (client, TRUE, NULL))
+ goto exit;
+
+ list = cal_comp_selection_get_string_list (selection_data);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ gchar *source_uid = iter->data;
+ icalcomponent *icalcomp;
+ gchar *component_string;
+
+ /* Each string is "source_uid\ncomponent_string". */
+ component_string = strchr (source_uid, '\n');
+ if (component_string == NULL)
+ continue;
+
+ *component_string++ = '\0';
+ icalcomp = icalparser_parse_string (component_string);
+ if (icalcomp == NULL)
+ continue;
+
+ success = memo_list_selector_process_data (
+ selector, client, source_uid, icalcomp, action);
+
+ icalcomponent_free (icalcomp);
+ }
+
+ g_slist_foreach (list, (GFunc) g_free, NULL);
+ g_slist_free (list);
+
+exit:
+ if (client != NULL)
+ g_object_unref (client);
+
+ return success;
+}
+
+static void
+memo_list_selector_class_init (EMemoListSelectorClass *class)
+{
+ ESourceSelectorClass *source_selector_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMemoListSelectorPrivate));
+
+ source_selector_class = E_SOURCE_SELECTOR_CLASS (class);
+ source_selector_class->data_dropped = memo_list_selector_data_dropped;
+}
+
+static void
+memo_list_selector_init (EMemoListSelector *selector)
+{
+ selector->priv = E_MEMO_LIST_SELECTOR_GET_PRIVATE (selector);
+
+ gtk_drag_dest_set (
+ GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL,
+ drag_types, G_N_ELEMENTS (drag_types),
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+}
+
+GType
+e_memo_list_selector_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (EMemoListSelectorClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) memo_list_selector_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMemoListSelector),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) memo_list_selector_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_SOURCE_SELECTOR, "EMemoListSelector",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_memo_list_selector_new (ESourceList *source_list)
+{
+ g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
+
+ return g_object_new (
+ E_TYPE_MEMO_LIST_SELECTOR,
+ "source-list", source_list, NULL);
+}
diff --cc calendar/gui/e-memo-table.c
index 25e6005,ac43b39..7f14d4f
--- a/calendar/gui/e-memo-table.c
+++ b/calendar/gui/e-memo-table.c
@@@ -88,8 -64,8 +88,8 @@@ enum
};
static GtkTargetEntry target_types[] = {
- { "text/calendar", 0, TARGET_TYPE_VCALENDAR },
- { "text/x-calendar", 0, TARGET_TYPE_VCALENDAR }
- { (gchar *) "text/x-calendar", 0, TARGET_TYPE_VCALENDAR },
- { (gchar *) "text/calendar", 0, TARGET_TYPE_VCALENDAR }
++ { (gchar *) "text/calendar", 0, TARGET_TYPE_VCALENDAR },
++ { (gchar *) "text/x-calendar", 0, TARGET_TYPE_VCALENDAR }
};
static guint n_target_types = G_N_ELEMENTS (target_types);
diff --cc calendar/gui/e-task-list-selector.c
index 910ab3f,0000000..fa6bd32
mode 100644,000000..100644
--- a/calendar/gui/e-task-list-selector.c
+++ b/calendar/gui/e-task-list-selector.c
@@@ -1,288 -1,0 +1,288 @@@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-task-list-selector.c
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU 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 General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "e-task-list-selector.h"
+
+#include <string.h>
+#include <libecal/e-cal.h>
+#include "calendar/common/authentication.h"
+#include "calendar/gui/comp-util.h"
+
+#define E_TASK_LIST_SELECTOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_LIST_SELECTOR, ETaskListSelectorPrivate))
+
+struct _ETaskListSelectorPrivate {
+ gint dummy_value;
+};
+
+enum {
+ DND_TARGET_TYPE_CALENDAR_LIST
+};
+
+static GtkTargetEntry drag_types[] = {
- { "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST },
- { "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }
++ { (gchar *) "text/calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST },
++ { (gchar *) "text/x-calendar", 0, DND_TARGET_TYPE_CALENDAR_LIST }
+};
+
+static gpointer parent_class;
+
+static gboolean
+task_list_selector_update_single_object (ECal *client,
+ icalcomponent *icalcomp)
+{
+ gchar *uid;
+ icalcomponent *tmp_icalcomp;
+
+ uid = (gchar *) icalcomponent_get_uid (icalcomp);
+
+ if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, NULL))
+ return e_cal_modify_object (
+ client, icalcomp, CALOBJ_MOD_ALL, NULL);
+
+ return e_cal_create_object (client, icalcomp, &uid, NULL);
+}
+
+static gboolean
+task_list_selector_update_objects (ECal *client,
+ icalcomponent *icalcomp)
+{
+ icalcomponent *subcomp;
+ icalcomponent_kind kind;
+
+ kind = icalcomponent_isa (icalcomp);
+ if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT)
+ return task_list_selector_update_single_object (
+ client, icalcomp);
+ else if (kind != ICAL_VCALENDAR_COMPONENT)
+ return FALSE;
+
+ subcomp = icalcomponent_get_first_component (
+ icalcomp, ICAL_ANY_COMPONENT);
+ while (subcomp != NULL) {
+ gboolean success;
+
+ kind = icalcomponent_isa (subcomp);
+ if (kind == ICAL_VTIMEZONE_COMPONENT) {
+ icaltimezone *zone;
+
+ zone = icaltimezone_new ();
+ icaltimezone_set_component (zone, subcomp);
+
+ success = e_cal_add_timezone (client, zone, NULL);
+ icaltimezone_free (zone, 1);
+ if (!success)
+ return FALSE;
+ } else if (kind == ICAL_VTODO_COMPONENT ||
+ kind == ICAL_VEVENT_COMPONENT) {
+ success = task_list_selector_update_single_object (
+ client, subcomp);
+ if (!success)
+ return FALSE;
+ }
+
+ subcomp = icalcomponent_get_next_component (
+ icalcomp, ICAL_ANY_COMPONENT);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+task_list_selector_process_data (ESourceSelector *selector,
+ ECal *client,
+ const gchar *source_uid,
+ icalcomponent *icalcomp,
+ GdkDragAction action)
+{
+ ESourceList *source_list;
+ ESource *source;
+ icalcomponent *tmp_icalcomp = NULL;
+ const gchar *uid;
+ gchar *old_uid = NULL;
+ gboolean success = FALSE;
+ gboolean read_only = TRUE;
+ GError *error = NULL;
+
+ /* FIXME Deal with GDK_ACTION_ASK. */
+ if (action == GDK_ACTION_COPY) {
+ old_uid = g_strdup (icalcomponent_get_uid (icalcomp));
+ uid = e_cal_component_gen_uid ();
+ icalcomponent_set_uid (icalcomp, uid);
+ }
+
+ uid = icalcomponent_get_uid (icalcomp);
+ if (old_uid == NULL)
+ old_uid = g_strdup (uid);
+
+ if (e_cal_get_object (client, uid, NULL, &tmp_icalcomp, &error)) {
+ icalcomponent_free (tmp_icalcomp);
+ success = TRUE;
+ goto exit;
+ }
+
+ if (error != NULL && error->code != E_CALENDAR_STATUS_OBJECT_NOT_FOUND) {
+ g_message (
+ "Failed to search the object in destination "
+ "task list: %s", error->message);
+ g_error_free (error);
+ goto exit;
+ }
+
+ success = task_list_selector_update_objects (client, icalcomp);
+
+ if (!success || action != GDK_ACTION_MOVE)
+ goto exit;
+
+ source_list = e_source_selector_get_source_list (selector);
+ source = e_source_list_peek_source_by_uid (source_list, source_uid);
+
+ if (!E_IS_SOURCE (source) || e_source_get_readonly (source))
+ goto exit;
+
+ client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO);
+ if (client == NULL) {
+ g_message ("Cannot create source client to remove old task");
+ goto exit;
+ }
+
+ e_cal_is_read_only (client, &read_only, NULL);
+ if (!read_only && e_cal_open (client, TRUE, NULL))
+ e_cal_remove_object (client, old_uid, NULL);
+ else if (!read_only)
+ g_message ("Cannot open source client to remove old task");
+
+ g_object_unref (client);
+
+exit:
+ g_free (old_uid);
+
+ return success;
+}
+
+static gboolean
+task_list_selector_data_dropped (ESourceSelector *selector,
+ GtkSelectionData *selection_data,
+ ESource *destination,
+ GdkDragAction action,
+ guint info)
+{
+ ECal *client;
+ GSList *list, *iter;
+ gboolean success = FALSE;
+
+ client = auth_new_cal_from_source (
+ destination, E_CAL_SOURCE_TYPE_TODO);
+
+ if (client == NULL || !e_cal_open (client, TRUE, NULL))
+ goto exit;
+
+ list = cal_comp_selection_get_string_list (selection_data);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ gchar *source_uid = iter->data;
+ icalcomponent *icalcomp;
+ gchar *component_string;
+
+ /* Each string is "source_uid\ncomponent_string". */
+ component_string = strchr (source_uid, '\n');
+ if (component_string == NULL)
+ continue;
+
+ *component_string++ = '\0';
+ icalcomp = icalparser_parse_string (component_string);
+ if (icalcomp == NULL)
+ continue;
+
+ success = task_list_selector_process_data (
+ selector, client, source_uid, icalcomp, action);
+
+ icalcomponent_free (icalcomp);
+ }
+
+ g_slist_foreach (list, (GFunc) g_free, NULL);
+ g_slist_free (list);
+
+exit:
+ if (client != NULL)
+ g_object_unref (client);
+
+ return success;
+}
+
+static void
+task_list_selector_class_init (ETaskListSelectorClass *class)
+{
+ ESourceSelectorClass *source_selector_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETaskListSelectorPrivate));
+
+ source_selector_class = E_SOURCE_SELECTOR_CLASS (class);
+ source_selector_class->data_dropped = task_list_selector_data_dropped;
+}
+
+static void
+task_list_selector_init (ETaskListSelector *selector)
+{
+ selector->priv = E_TASK_LIST_SELECTOR_GET_PRIVATE (selector);
+
+ gtk_drag_dest_set (
+ GTK_WIDGET (selector), GTK_DEST_DEFAULT_ALL,
+ drag_types, G_N_ELEMENTS (drag_types),
+ GDK_ACTION_COPY | GDK_ACTION_MOVE);
+}
+
+GType
+e_task_list_selector_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (ETaskListSelectorClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) task_list_selector_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ETaskListSelector),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) task_list_selector_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_SOURCE_SELECTOR, "ETaskListSelector",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_task_list_selector_new (ESourceList *source_list)
+{
+ g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
+
+ return g_object_new (
+ E_TYPE_TASK_LIST_SELECTOR,
+ "source-list", source_list, NULL);
+}
diff --cc calendar/gui/e-week-view.c
index 90ea61e,57c0547..f2082c5
--- a/calendar/gui/e-week-view.c
+++ b/calendar/gui/e-week-view.c
@@@ -1938,12 -1937,9 +1938,12 @@@ set_text_as_bold (EWeekViewEvent *event
break;
}
}
+ e_cal_component_free_attendee_list (attendees);
+ g_free (address);
+ g_object_unref (comp);
/* The attendee has not yet accepted the meeting, display the summary as bolded.
- If the attendee is not present, it might have come through a mailing list.
+ If the attendee is not present, it might have come through a mailing list.
In that case, we never show the meeting as bold even if it is unaccepted. */
if (at && (at->status == ICAL_PARTSTAT_NEEDSACTION))
gnome_canvas_item_set (span->text_item, "bold", TRUE, NULL);
diff --cc calendar/gui/gnome-cal.c
index 75a3764,18f4a47..7e0043d
--- a/calendar/gui/gnome-cal.c
+++ b/calendar/gui/gnome-cal.c
@@@ -744,9 -889,9 +744,9 @@@ update_query_async (struct _date_query_
g_slice_free (struct _date_query_msg, msg);
return; /* No time range is set, so don't start a query */
}
-
+
/* create queries for each loaded client */
- for (l = priv->clients_list[E_CAL_SOURCE_TYPE_EVENT]; l != NULL; l = l->next) {
+ for (l = priv->clients_list; l != NULL; l = l->next) {
GError *error = NULL;
gint tries = 0;
@@@ -1592,27 -1921,40 +1592,27 @@@ gnome_calendar_destroy (GtkObject *obje
e_categories_unregister_change_listener (G_CALLBACK (categories_changed_cb), gcal);
/* Clean up the clients */
- for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
- for (l = priv->clients_list[i]; l != NULL; l = l->next) {
- ESource *source = e_cal_get_source (l->data);
-
- g_signal_handlers_disconnect_matched (l->data, G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL, gcal);
-
- if (source)
- g_signal_handlers_disconnect_matched (source, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gcal);
- }
-
- g_hash_table_destroy (priv->clients[i]);
- g_list_free (priv->clients_list[i]);
-
- priv->clients[i] = NULL;
- priv->clients_list[i] = NULL;
-
- if (priv->default_client[i]) {
- ESource *source = e_cal_get_source (priv->default_client[i]);
+ for (l = priv->clients_list; l != NULL; l = l->next) {
+ g_signal_handlers_disconnect_matched (l->data, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, gcal);
+ }
- g_signal_handlers_disconnect_matched (priv->default_client[i],
- G_SIGNAL_MATCH_DATA,
- 0, 0, NULL, NULL, gcal);
+ g_hash_table_destroy (priv->clients);
+ g_list_free (priv->clients_list);
- if (source)
- g_signal_handlers_disconnect_matched (source, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gcal);
+ priv->clients = NULL;
+ priv->clients_list = NULL;
- g_object_unref (priv->default_client[i]);
- }
- priv->default_client[i] = NULL;
+ if (priv->default_client) {
+ g_signal_handlers_disconnect_matched (priv->default_client,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, gcal);
+ g_object_unref (priv->default_client);
}
+ priv->default_client = NULL;
for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) {
- if (priv->configs[i])
+ if (priv->configs[i])
g_object_unref (priv->configs[i]);
priv->configs[i] = NULL;
}
@@@ -2114,32 -2655,103 +2114,32 @@@ struct _mclient_msg
};
static void
-gc_popup_free (EPopup *ep, GSList *list, void *data)
+add_mclient_async (struct _mclient_msg *msg)
{
- while (list) {
- GSList *n = list->next;
- EPopupItem *pitem = list->data;
-
- g_free(pitem->path);
- g_free(pitem->label);
- g_free(pitem->user_data);
- g_free(pitem);
- g_slist_free_1(list);
- list = n;
- }
-}
+ e_cal_model_add_client (msg->model, msg->client);
-static void
-gc_popup_free_static (EPopup *ep, GSList *list, void *data)
-{
- while (list) {
- GSList *n = list->next;
- EPopupItem *pitem = list->data;
-
- g_free(pitem->path);
- g_free(pitem);
- g_slist_free_1(list);
- list = n;
- }
+ g_object_unref (msg->client);
+ g_object_unref (msg->model);
+ g_slice_free (struct _mclient_msg, msg);
}
-void
-gnome_calendar_view_popup_factory (GnomeCalendar *gcal, EPopup *ep, const char *prefix)
+static void
+add_mclient (ECalModel *model, ECal *client)
{
- GnomeCalendarPrivate *priv;
- int length;
- int i;
- gboolean found = FALSE;
- char *id;
- GSList *menus = NULL;
- EPopupItem *pitem;
-
- g_return_if_fail (gcal != NULL);
- g_return_if_fail (GNOME_IS_CALENDAR (gcal));
- g_return_if_fail (prefix != NULL);
-
- priv = gcal->priv;
-
- g_return_if_fail (priv->view_instance != NULL);
-
- length = gal_view_collection_get_count(priv->view_instance->collection);
- id = gal_view_instance_get_current_view_id (priv->view_instance);
-
- for (i = 0; i < length; i++) {
- GalViewCollectionItem *item = gal_view_collection_get_view_item(priv->view_instance->collection, i);
-
- pitem = g_malloc0(sizeof(*pitem));
- pitem->type = E_POPUP_RADIO;
- pitem->path = g_strdup_printf("%s/%02d.item", prefix, i);
- pitem->label = g_strdup(item->title);
- pitem->activate = gc_set_view;
- pitem->user_data = g_strdup(item->id);
-
- if (!found && id && !strcmp (id, item->id)) {
- found = TRUE;
- pitem->type |= E_POPUP_ACTIVE;
- }
-
- menus = g_slist_prepend(menus, pitem);
- }
-
- if (menus)
- e_popup_add_items(ep, menus, NULL, gc_popup_free, gcal);
+ struct _mclient_msg *msg;
- menus = NULL;
- for (i = found?3:0; i<sizeof(gc_popups)/sizeof(gc_popups[0]);i++) {
- pitem = g_malloc0(sizeof(*pitem));
- memcpy(pitem, &gc_popups[i], sizeof(*pitem));
- pitem->path = g_strdup_printf("%s/%02d.item", prefix, i+length);
- menus = g_slist_prepend(menus, pitem);
- }
+ msg = g_slice_new0 (struct _mclient_msg);
+ msg->header.func = (MessageFunc) add_mclient_async;
+ msg->model = g_object_ref (model);
+ msg->client = g_object_ref (client);
- e_popup_add_items(ep, menus, NULL, gc_popup_free_static, gcal);
+ message_push ((Message *) msg);
}
- static void
+ static void
-gnome_calendar_set_pane_positions (GnomeCalendar *gcal)
+non_intrusive_error_remove(GtkWidget *w, void *data)
{
- GnomeCalendarPrivate *priv;
-
- priv = gcal->priv;
-
- if (priv->current_view_type == GNOME_CAL_MONTH_VIEW && !priv->range_selected) {
- gtk_paned_set_position (GTK_PANED (priv->hpane), priv->hpane_pos_month_view);
- gtk_paned_set_position (GTK_PANED (priv->vpane), priv->vpane_pos_month_view);
- } else {
- gtk_paned_set_position (GTK_PANED (priv->hpane), priv->hpane_pos);
- gtk_paned_set_position (GTK_PANED (priv->vpane), priv->vpane_pos);
- }
+ g_hash_table_remove(non_intrusive_error_table, data);
}
struct _mclient_msg {
@@@ -2303,15 -2974,15 +2303,15 @@@ default_client_cal_opened_cb (ECal *eca
g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gcal);
/* FIXME should we do this to prevent multiple error dialogs? */
- priv->clients_list[source_type] = g_list_remove (priv->clients_list[source_type], ecal);
- g_hash_table_remove (priv->clients[source_type], e_source_peek_uid (source));
+ priv->clients_list = g_list_remove (priv->clients_list, ecal);
+ g_hash_table_remove (priv->clients, e_source_peek_uid (source));
/* FIXME Is there a better way to handle this? */
- if (priv->default_client)
- if (priv->default_client[source_type])
- g_object_unref (priv->default_client[source_type]);
- priv->default_client[source_type] = NULL;
++ if (priv->default_client)
+ g_object_unref (priv->default_client);
+ priv->default_client = NULL;
- g_signal_emit (gcal, gnome_calendar_signals[SOURCE_REMOVED], 0, source_type, source);
+ g_signal_emit (gcal, gnome_calendar_signals[SOURCE_REMOVED], 0, source);
g_object_unref (source);
g_warning ("Unable to load the calendar %s \n", e_cal_get_error_message (status));
diff --cc calendar/gui/itip-utils.c
index c6aa021,ae822c9..bf270de
--- a/calendar/gui/itip-utils.c
+++ b/calendar/gui/itip-utils.c
@@@ -37,9 -37,10 +37,9 @@@
#include <time.h>
#include <composer/e-msg-composer.h>
-#include <mail/em-composer-utils.h>
#include <camel/camel-mime-filter-tohtml.h>
- static gchar *itip_methods[] = {
+ static const gchar *itip_methods[] = {
"PUBLISH",
"REQUEST",
"REPLY",
diff --cc calendar/gui/tasks-control.c
index 62a283f,7ee468e..1be68ac
--- a/calendar/gui/tasks-control.c
+++ b/calendar/gui/tasks-control.c
@@@ -70,8 -91,70 +70,8 @@@ static void tasks_control_forward_cm
gpointer data,
const char *path);
-static void tasks_control_view_preview (BonoboUIComponent *uic,
- const char *path,
- Bonobo_UIComponent_EventType type,
- const char *state,
- void *data);
-
-struct focus_changed_data {
- BonoboControl *control;
- ETasks *tasks;
-};
-
-static gboolean tasks_control_focus_changed (GtkWidget *widget, GdkEventFocus *event, struct focus_changed_data *fc_data);
-
-BonoboControl *
-tasks_control_new (void)
-{
- BonoboControl *control;
- GtkWidget *tasks, *preview;
- struct focus_changed_data *fc_data;
-
- tasks = e_tasks_new ();
- if (!tasks)
- return NULL;
- gtk_widget_show (tasks);
-
- control = bonobo_control_new (tasks);
- if (!control) {
- gtk_widget_destroy (tasks);
- g_message ("control_factory_fn(): could not create the control!");
- return NULL;
- }
-
- g_signal_connect (control, "activate", G_CALLBACK (tasks_control_activate_cb), tasks);
-
- fc_data = g_new0 (struct focus_changed_data, 1);
- fc_data->control = control;
- fc_data->tasks = E_TASKS (tasks);
-
- preview = e_cal_component_preview_get_html (E_CAL_COMPONENT_PREVIEW (e_tasks_get_preview (fc_data->tasks)));
- g_object_set_data_full (G_OBJECT (preview), "tasks-ctrl-fc-data", fc_data, g_free);
- g_signal_connect (preview, "focus-in-event", G_CALLBACK (tasks_control_focus_changed), fc_data);
- g_signal_connect (preview, "focus-out-event", G_CALLBACK (tasks_control_focus_changed), fc_data);
-
- return control;
-}
-
-
-static void
-tasks_control_activate_cb (BonoboControl *control,
- gboolean activate,
- gpointer user_data)
-{
- ETasks *tasks;
-
- tasks = E_TASKS (user_data);
-
- if (activate)
- tasks_control_activate (control, tasks);
- else
- tasks_control_deactivate (control, tasks);
-}
-
struct _tasks_sensitize_item {
- char *command;
+ const gchar *command;
guint32 enable;
};
diff --cc calendar/module/e-cal-shell-backend.c
index 9c38555,0000000..675a3d4
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-backend.c
+++ b/calendar/module/e-cal-shell-backend.c
@@@ -1,666 -1,0 +1,666 @@@
+/*
+ * e-cal-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-backend.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/e-cal.h>
+#include <libedataserver/e-url.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-group.h>
+
+#include "e-util/e-import.h"
+#include "shell/e-shell.h"
+#include "shell/e-shell-backend.h"
+#include "shell/e-shell-window.h"
+#include "widgets/misc/e-preferences-window.h"
+
+#include "calendar/common/authentication.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-attachment-handler-calendar.h"
+#include "calendar/gui/e-cal-config.h"
+#include "calendar/gui/e-cal-event.h"
+#include "calendar/gui/dialogs/cal-prefs-dialog.h"
+#include "calendar/gui/dialogs/calendar-setup.h"
+#include "calendar/gui/dialogs/event-editor.h"
+#include "calendar/importers/evolution-calendar-importer.h"
+
+#include "e-cal-shell-migrate.h"
+#include "e-cal-shell-settings.h"
+#include "e-cal-shell-view.h"
+
+#define E_CAL_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendPrivate))
+
+#define CONTACTS_BASE_URI "contacts://"
+#define WEATHER_BASE_URI "weather://"
+#define WEB_BASE_URI "webcal://"
+#define PERSONAL_RELATIVE_URI "system"
+
+struct _ECalShellBackendPrivate {
+ ESourceList *source_list;
+};
+
+enum {
+ PROP_0,
+ PROP_SOURCE_LIST
+};
+
+static gpointer parent_class;
+static GType cal_shell_backend_type;
+
+static void
+cal_shell_backend_ensure_sources (EShellBackend *shell_backend)
+{
+ /* XXX This is basically the same algorithm across all backends.
+ * Maybe we could somehow integrate this into EShellBackend? */
+
+ ECalShellBackendPrivate *priv;
+ ESourceGroup *on_this_computer;
+ ESourceGroup *on_the_web;
+ ESourceGroup *contacts;
+ ESourceGroup *weather;
+ ESource *birthdays;
+ ESource *personal;
+ EShell *shell;
+ EShellSettings *shell_settings;
+ GSList *groups, *iter;
+ const gchar *data_dir;
+ const gchar *name;
+ gchar *base_uri;
+ gchar *filename;
+ gchar *property;
+
+ on_this_computer = NULL;
+ on_the_web = NULL;
+ contacts = NULL;
+ weather = NULL;
+ birthdays = NULL;
+ personal = NULL;
+
+ priv = E_CAL_SHELL_BACKEND_GET_PRIVATE (shell_backend);
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ if (!e_cal_get_sources (&priv->source_list, E_CAL_SOURCE_TYPE_EVENT, NULL)) {
+ g_warning ("Could not get calendar sources from GConf!");
+ return;
+ }
+
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ filename = g_build_filename (data_dir, "local", NULL);
+ base_uri = g_filename_to_uri (filename, NULL, NULL);
+ g_free (filename);
+
+ groups = e_source_list_peek_groups (priv->source_list);
+ for (iter = groups; iter != NULL; iter = iter->next) {
+ ESourceGroup *source_group = iter->data;
+ const gchar *group_base_uri;
+
+ group_base_uri = e_source_group_peek_base_uri (source_group);
+
+ /* Compare only "file://" part. if the user's home
+ * changes, we do not want to create another group. */
+ if (on_this_computer == NULL &&
+ strncmp (base_uri, group_base_uri, 7) == 0)
+ on_this_computer = source_group;
+
+ else if (on_the_web == NULL &&
+ strcmp (WEB_BASE_URI, group_base_uri) == 0)
+ on_the_web = source_group;
+
+ else if (contacts == NULL &&
+ strcmp (CONTACTS_BASE_URI, group_base_uri) == 0)
+ contacts = source_group;
+
+ else if (weather == NULL &&
+ strcmp (WEATHER_BASE_URI, group_base_uri) == 0)
+ weather = source_group;
+ }
+
+ name = _("On This Computer");
+
+ if (on_this_computer != NULL) {
+ GSList *sources;
+ const gchar *group_base_uri;
+
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (on_this_computer, name);
+
+ sources = e_source_group_peek_sources (on_this_computer);
+ group_base_uri = e_source_group_peek_base_uri (on_this_computer);
+
+ /* Make sure this group includes a "Personal" source. */
+ for (iter = sources; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (relative_uri == NULL)
+ continue;
+
+ if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0)
+ continue;
+
+ personal = source;
+ break;
+ }
+
+ /* Make sure we have the correct base URI. This can
+ * change when the user's home directory changes. */
+ if (strcmp (base_uri, group_base_uri) != 0) {
+ e_source_group_set_base_uri (
+ on_this_computer, base_uri);
+
+ /* XXX We shouldn't need this sync call here as
+ * set_base_uri() results in synching to GConf,
+ * but that happens in an idle loop and too late
+ * to prevent the user from seeing a "Cannot
+ * Open ... because of invalid URI" error. */
+ e_source_list_sync (priv->source_list, NULL);
+ }
+
+ } else {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, base_uri);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ }
+
+ name = _("Personal");
+
+ if (personal == NULL) {
+ ESource *source;
+ GSList *selected;
+ gchar *primary;
+
+ source = e_source_new (name, PERSONAL_RELATIVE_URI);
+ e_source_group_add_source (on_this_computer, source, -1);
+ g_object_unref (source);
+
+ primary = e_shell_settings_get_string (
+ shell_settings, "cal-primary-calendar");
+
+ selected = calendar_config_get_calendars_selected ();
+
+ if (primary == NULL && selected == NULL) {
+ const gchar *uid;
+
+ uid = e_source_peek_uid (source);
+ selected = g_slist_prepend (NULL, g_strdup (uid));
+
+ e_shell_settings_set_string (
+ shell_settings, "cal-primary-calendar", uid);
+ calendar_config_set_calendars_selected (selected);
+ }
+
+ g_slist_foreach (selected, (GFunc) g_free, NULL);
+ g_slist_free (selected);
+ g_free (primary);
+ } else {
+ /* Force the source name to the current locale. */
+ e_source_set_name (personal, name);
+ }
+
+ name = _("On The Web");
+
+ if (on_the_web == NULL) {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, WEB_BASE_URI);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ } else {
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (on_the_web, name);
+ }
+
+ name = _("Contacts");
+
+ if (contacts != NULL) {
+ GSList *sources;
+
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (contacts, name);
+
+ sources = e_source_group_peek_sources (contacts);
+
+ if (sources != NULL) {
+ GSList *trash;
+
+ /* There is only one source under Contacts. */
+ birthdays = E_SOURCE (sources->data);
+ sources = g_slist_next (sources);
+
+ /* Delete any other sources in this group.
+ * Earlier versions allowed you to create
+ * additional sources under Contacts. */
+ trash = g_slist_copy (sources);
+ while (trash != NULL) {
+ ESource *source = trash->data;
+ e_source_group_remove_source (contacts, source);
+ trash = g_slist_delete_link (trash, trash);
+ }
-
++
+ }
+ } else {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, CONTACTS_BASE_URI);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+
+ /* This is now a borrowed reference. */
+ contacts = source_group;
+ }
+
+ /* XXX e_source_group_get_property() returns a newly-allocated
+ * string when it could just as easily return a const string.
+ * Unfortunately, fixing that would break the API. */
+ property = e_source_group_get_property (contacts, "create_source");
+ if (property == NULL)
+ e_source_group_set_property (contacts, "create_source", "no");
+ g_free (property);
+
+ name = _("Birthdays & Anniversaries");
+
+ if (birthdays == NULL) {
+ ESource *source;
+ const gchar *name;
+
+ name = _("Birthdays & Anniversaries");
+ source = e_source_new (name, "/");
+ e_source_group_add_source (contacts, source, -1);
+ g_object_unref (source);
+
+ /* This is now a borrowed reference. */
+ birthdays = source;
+ } else {
+ /* Force the source name to the current locale. */
+ e_source_set_name (birthdays, name);
+ }
+
+ if (e_source_get_property (birthdays, "delete") == NULL)
+ e_source_set_property (birthdays, "delete", "no");
+
+ if (e_source_peek_color_spec (birthdays) == NULL)
+ e_source_set_color_spec (birthdays, "#DDBECE");
+
+ name = _("Weather");
+
+ if (weather == NULL) {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, WEATHER_BASE_URI);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ } else {
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (weather, name);
+ }
+
+ g_free (base_uri);
+}
+
+static void
+cal_shell_backend_cal_opened_cb (ECal *cal,
+ ECalendarStatus status,
+ GtkAction *action)
+{
+ EShell *shell;
+ ECalComponent *comp;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ const gchar *action_name;
+ gboolean all_day;
+
+ /* FIXME Pass this in. */
+ shell = e_shell_get_default ();
+
+ /* XXX Handle errors better. */
+ if (status != E_CALENDAR_STATUS_OK)
+ return;
+
+ action_name = gtk_action_get_name (action);
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+ flags |= COMP_EDITOR_USER_ORG;
+ if (strcmp (action_name, "event-meeting-new") == 0)
+ flags |= COMP_EDITOR_MEETING;
+
+ all_day = (strcmp (action_name, "event-all-day-new") == 0);
+
+ editor = event_editor_new (cal, shell, flags);
+ comp = cal_comp_event_new_with_current_time (cal, all_day);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+ g_object_unref (cal);
+}
+
+static void
+action_event_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ ECal *cal = NULL;
+ ECalSourceType source_type;
+ ESourceList *source_list;
+ EShellSettings *shell_settings;
+ EShell *shell;
+ gchar *uid;
+
+ /* This callback is used for both appointments and meetings. */
+
+ source_type = E_CAL_SOURCE_TYPE_EVENT;
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ if (!e_cal_get_sources (&source_list, source_type, NULL)) {
+ g_warning ("Could not get calendar sources from GConf!");
+ return;
+ }
+
+ uid = e_shell_settings_get_string (
+ shell_settings, "cal-primary-calendar");
+
+ if (uid != NULL) {
+ ESource *source;
+
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ if (source != NULL)
+ cal = auth_new_cal_from_source (source, source_type);
+ g_free (uid);
+ }
+
+ if (cal == NULL)
+ cal = auth_new_cal_from_default (source_type);
+
+ g_return_if_fail (cal != NULL);
+
+ g_signal_connect (
+ cal, "cal-opened",
+ G_CALLBACK (cal_shell_backend_cal_opened_cb), action);
+
+ e_cal_open_async (cal, FALSE);
+}
+
+static void
+action_calendar_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ calendar_setup_new_calendar (GTK_WINDOW (shell_window));
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "event-new",
+ "appointment-new",
+ NC_("New", "_Appointment"),
+ "<Shift><Control>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_new-meeting",
+ NC_("New", "M_eeting"),
+ "<Shift><Control>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_init_hooks (void)
+{
+ e_plugin_hook_register_type (e_cal_config_hook_get_type ());
+ e_plugin_hook_register_type (e_cal_event_hook_get_type ());
+}
+
+static void
+cal_shell_backend_init_importers (void)
+{
+ EImportClass *import_class;
+ EImportImporter *importer;
+
+ import_class = g_type_class_ref (e_import_get_type ());
+
+ importer = gnome_calendar_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = ical_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = vcal_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+}
+
+static void
+cal_shell_backend_init_preferences (EShell *shell)
+{
+ GtkWidget *preferences_window;
+
+ preferences_window = e_shell_get_preferences_window (shell);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "calendar-and-tasks",
+ "preferences-calendar-and-tasks",
+ _("Calendar and Tasks"),
+ calendar_prefs_dialog_new (shell),
+ 600);
+}
+
+static gboolean
+cal_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
+ const gchar *uri)
+{
+ /* FIXME */
+ return FALSE;
+}
+
+static void
+cal_shell_backend_window_created_cb (EShellBackend *shell_backend,
+ GtkWindow *window)
+{
+ const gchar *backend_name;
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+}
+
+static void
+cal_shell_backend_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE_LIST:
+ g_value_set_object (
+ value,
+ e_cal_shell_backend_get_source_list (
+ E_CAL_SHELL_BACKEND (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_backend_dispose (GObject *object)
+{
+ ECalShellBackendPrivate *priv;
+
+ priv = E_CAL_SHELL_BACKEND_GET_PRIVATE (object);
+
+ if (priv->source_list != NULL) {
+ g_object_unref (priv->source_list);
+ priv->source_list = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+cal_shell_backend_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ cal_shell_backend_ensure_sources (shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "handle-uri",
+ G_CALLBACK (cal_shell_backend_handle_uri_cb),
+ shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-created",
+ G_CALLBACK (cal_shell_backend_window_created_cb),
+ shell_backend);
+
+ cal_shell_backend_init_hooks ();
+ cal_shell_backend_init_importers ();
+
+ /* Initialize settings before initializing preferences,
+ * since the preferences bind to the shell settings. */
+ e_cal_shell_backend_init_settings (shell);
+ cal_shell_backend_init_preferences (shell);
+
+ e_attachment_handler_calendar_get_type ();
+}
+
+static void
+cal_shell_backend_class_init (ECalShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ECalShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = cal_shell_backend_get_property;
+ object_class->dispose = cal_shell_backend_dispose;
+ object_class->constructed = cal_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_CAL_SHELL_VIEW;
+ shell_backend_class->name = "calendar";
+ shell_backend_class->aliases = "";
+ shell_backend_class->schemes = "calendar";
+ shell_backend_class->sort_order = 400;
+ shell_backend_class->start = NULL;
+ shell_backend_class->is_busy = NULL;
+ shell_backend_class->shutdown = NULL;
+ shell_backend_class->migrate = e_cal_shell_backend_migrate;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SOURCE_LIST,
+ g_param_spec_object (
+ "source-list",
+ _("Source List"),
+ _("The registry of calendars"),
+ E_TYPE_SOURCE_LIST,
+ G_PARAM_READABLE));
+}
+
+static void
+cal_shell_backend_init (ECalShellBackend *cal_shell_backend)
+{
+ cal_shell_backend->priv =
+ E_CAL_SHELL_BACKEND_GET_PRIVATE (cal_shell_backend);
+}
+
+GType
+e_cal_shell_backend_get_type (void)
+{
+ return cal_shell_backend_type;
+}
+
+void
+e_cal_shell_backend_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (ECalShellBackendClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) cal_shell_backend_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ECalShellBackend),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) cal_shell_backend_init,
+ NULL /* value_table */
+ };
+
+ cal_shell_backend_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_BACKEND,
+ "ECalShellBackend", &type_info, 0);
+}
+
+ESourceList *
+e_cal_shell_backend_get_source_list (ECalShellBackend *cal_shell_backend)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_BACKEND (cal_shell_backend), NULL);
+
+ return cal_shell_backend->priv->source_list;
+}
diff --cc calendar/module/e-cal-shell-backend.h
index 434c87b,0000000..497e200
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-backend.h
+++ b/calendar/module/e-cal-shell-backend.h
@@@ -1,70 -1,0 +1,70 @@@
+/*
+ * e-cal-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_BACKEND_H
+#define E_CAL_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+#include <libedataserver/e-source-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SHELL_BACKEND \
+ (e_cal_shell_backend_get_type ())
+#define E_CAL_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackend))
+#define E_CAL_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendClass))
+#define E_IS_CAL_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SHELL_BACKEND))
+#define E_IS_CAL_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SHELL_BACKEND))
+#define E_CAL_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SHELL_BACKEND, ECalShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalShellBackend ECalShellBackend;
+typedef struct _ECalShellBackendClass ECalShellBackendClass;
+typedef struct _ECalShellBackendPrivate ECalShellBackendPrivate;
+
+struct _ECalShellBackend {
+ EShellBackend parent;
+ ECalShellBackendPrivate *priv;
+};
+
+struct _ECalShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+GType e_cal_shell_backend_get_type (void);
+void e_cal_shell_backend_register_type
+ (GTypeModule *type_module);
+ESourceList * e_cal_shell_backend_get_source_list
+ (ECalShellBackend *cal_shell_backend);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_BACKEND_H */
diff --cc calendar/module/e-cal-shell-content.c
index 7f750f5,0000000..6afb40d
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-content.c
+++ b/calendar/module/e-cal-shell-content.c
@@@ -1,827 -1,0 +1,827 @@@
+/*
+ * e-cal-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-content.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-util/gconf-bridge.h"
+
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/e-cal-list-view-config.h"
+#include "calendar/gui/e-cal-model-calendar.h"
+#include "calendar/gui/e-calendar-table.h"
+#include "calendar/gui/e-calendar-table-config.h"
+#include "calendar/gui/e-day-view-config.h"
+#include "calendar/gui/e-memo-table-config.h"
+#include "calendar/gui/e-week-view-config.h"
+
+#include "widgets/menus/gal-view-etable.h"
+
+#define E_CAL_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentPrivate))
+
+struct _ECalShellContentPrivate {
+ GtkWidget *hpaned;
+ GtkWidget *notebook;
+ GtkWidget *vpaned;
+
+ GtkWidget *day_view;
+ GtkWidget *work_week_view;
+ GtkWidget *week_view;
+ GtkWidget *month_view;
+ GtkWidget *list_view;
+ GtkWidget *task_table;
+ GtkWidget *memo_table;
+
+ EDayViewConfig *day_view_config;
+ EDayViewConfig *work_week_view_config;
+ EWeekViewConfig *week_view_config;
+ EWeekViewConfig *month_view_config;
+ ECalListViewConfig *list_view_config;
+ ECalendarTableConfig *task_table_config;
+ EMemoTableConfig *memo_table_config;
+
+ GalViewInstance *view_instance;
+
+ guint paned_binding_id;
+};
+
+enum {
+ PROP_0
+};
+
+/* Used to indicate who has the focus within the calendar view. */
+typedef enum {
+ FOCUS_CALENDAR,
+ FOCUS_MEMO_TABLE,
+ FOCUS_TASK_TABLE,
+ FOCUS_OTHER
+} FocusLocation;
+
+static gpointer parent_class;
+static GType cal_shell_content_type;
+
+static void
+cal_shell_content_display_view_cb (ECalShellContent *cal_shell_content,
+ GalView *gal_view)
+{
+ /* FIXME */
+}
+
+static void
+cal_shell_content_notify_view_id_cb (ECalShellContent *cal_shell_content)
+{
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GConfBridge *bridge;
+ GtkWidget *paned;
+ guint binding_id;
+ const gchar *key;
+ const gchar *view_id;
+
+ bridge = gconf_bridge_get ();
+ paned = cal_shell_content->priv->hpaned;
+ binding_id = cal_shell_content->priv->paned_binding_id;
+
+ shell_content = E_SHELL_CONTENT (cal_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ view_id = e_shell_view_get_view_id (shell_view);
+
+ if (binding_id > 0)
+ gconf_bridge_unbind (bridge, binding_id);
+
+ if (view_id != NULL && strcmp (view_id, "Month_View") == 0)
+ key = "/apps/evolution/calendar/display/month_hpane_position";
+ else
+ key = "/apps/evolution/calendar/display/hpane_position";
+
+ binding_id = gconf_bridge_bind_property_delayed (
+ bridge, key, G_OBJECT (paned), "position");
+
+ cal_shell_content->priv->paned_binding_id = binding_id;
+}
+
+static FocusLocation
+cal_shell_content_get_focus_location (ECalShellContent *cal_shell_content)
+{
+ return FOCUS_OTHER;
+#if 0 /* TEMPORARILY DISABLED */
+ GtkWidget *widget;
+ GnomeCalendar *calendar;
+ ECalendarTable *task_table;
+ EMemoTable *memo_table;
+ ETable *table;
+ ECalendarView *calendar_view;
+
+ calendar = GNOME_CALENDAR (cal_shell_content->priv->calendar);
+ widget = gnome_calendar_get_current_view_widget (calendar);
+
+ memo_table = E_MEMO_TABLE (cal_shell_content->priv->memo_table);
+ task_table = E_CALENDAR_TABLE (cal_shell_content->priv->task_table);
+
+ table = e_memo_table_get_table (memo_table);
+ if (GTK_WIDGET_HAS_FOCUS (table->table_canvas))
+ return FOCUS_MEMO_TABLE;
+
+ table = e_calendar_table_get_table (task_table);
+ if (GTK_WIDGET_HAS_FOCUS (table->table_canvas))
+ return FOCUS_TASK_TABLE;
+
+ if (E_IS_DAY_VIEW (widget)) {
+ EDayView *view = E_DAY_VIEW (widget);
+
+ if (GTK_WIDGET_HAS_FOCUS (view->top_canvas))
+ return FOCUS_CALENDAR;
+
+ if (GNOME_CANVAS (view->top_canvas)->focused_item != NULL)
+ return FOCUS_CALENDAR;
+
+ if (GTK_WIDGET_HAS_FOCUS (view->main_canvas))
+ return FOCUS_CALENDAR;
+
+ if (GNOME_CANVAS (view->main_canvas)->focused_item != NULL)
+ return FOCUS_CALENDAR;
+
+ } else if (E_IS_WEEK_VIEW (widget)) {
+ EWeekView *view = E_WEEK_VIEW (widget);
+
+ if (GTK_WIDGET_HAS_FOCUS (view->main_canvas))
+ return FOCUS_CALENDAR;
+
+ if (GNOME_CANVAS (view->main_canvas)->focused_item != NULL)
+ return FOCUS_CALENDAR;
+
+ } else if (E_IS_CAL_LIST_VIEW (widget)) {
+ ECalListView *view = E_CAL_LIST_VIEW (widget);
+
+ table = e_table_scrolled_get_table (view->table_scrolled);
+ if (GTK_WIDGET_HAS_FOCUS (table))
+ return FOCUS_CALENDAR;
+ }
+
+ return FOCUS_OTHER;
+#endif
+}
+
+static void
+cal_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_content_dispose (GObject *object)
+{
+ ECalShellContentPrivate *priv;
+
+ priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->hpaned != NULL) {
+ g_object_unref (priv->hpaned);
+ priv->hpaned = NULL;
+ }
+
+ if (priv->notebook != NULL) {
+ g_object_unref (priv->notebook);
+ priv->notebook = NULL;
+ }
+
+ if (priv->vpaned != NULL) {
+ g_object_unref (priv->vpaned);
+ priv->vpaned = NULL;
+ }
+
+ if (priv->day_view != NULL) {
+ g_object_unref (priv->day_view);
+ priv->day_view = NULL;
+ }
+
+ if (priv->work_week_view != NULL) {
+ g_object_unref (priv->work_week_view);
+ priv->work_week_view = NULL;
+ }
+
+ if (priv->week_view != NULL) {
+ g_object_unref (priv->week_view);
+ priv->week_view = NULL;
+ }
+
+ if (priv->month_view != NULL) {
+ g_object_unref (priv->month_view);
+ priv->month_view = NULL;
+ }
+
+ if (priv->list_view != NULL) {
+ g_object_unref (priv->list_view);
+ priv->list_view = NULL;
+ }
+
+ if (priv->task_table != NULL) {
+ g_object_unref (priv->task_table);
+ priv->task_table = NULL;
+ }
+
+ if (priv->memo_table != NULL) {
+ g_object_unref (priv->memo_table);
+ priv->memo_table = NULL;
+ }
+
+ if (priv->day_view_config != NULL) {
+ g_object_unref (priv->day_view_config);
+ priv->day_view_config = NULL;
+ }
+
+ if (priv->work_week_view_config != NULL) {
+ g_object_unref (priv->work_week_view_config);
+ priv->work_week_view_config = NULL;
+ }
+
+ if (priv->week_view_config != NULL) {
+ g_object_unref (priv->week_view_config);
+ priv->week_view_config = NULL;
+ }
+
+ if (priv->month_view_config != NULL) {
+ g_object_unref (priv->month_view_config);
+ priv->month_view_config = NULL;
+ }
+
+ if (priv->list_view_config != NULL) {
+ g_object_unref (priv->list_view_config);
+ priv->list_view_config = NULL;
+ }
+
+ if (priv->task_table_config != NULL) {
+ g_object_unref (priv->task_table_config);
+ priv->task_table_config = NULL;
+ }
+
+ if (priv->memo_table_config != NULL) {
+ g_object_unref (priv->memo_table_config);
+ priv->memo_table_config = NULL;
+ }
+
+ if (priv->view_instance != NULL) {
+ g_object_unref (priv->view_instance);
+ priv->view_instance = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+cal_shell_content_finalize (GObject *object)
+{
+ ECalShellContentPrivate *priv;
+
+ priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+cal_shell_content_constructed (GObject *object)
+{
+ ECalShellContentPrivate *priv;
+ ECalModelCalendar *cal_model;
+ ECalModel *memo_model;
+ ECalModel *task_model;
+ EShellContent *shell_content;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *foreign_content;
+ EShellView *foreign_view;
+ GalViewInstance *view_instance;
+ GConfBridge *bridge;
+ GtkWidget *container;
+ GtkWidget *widget;
+ const gchar *config_dir;
+ const gchar *key;
+ gchar *filename;
+ gchar *markup;
+ gint page_num;
+
+ priv = E_CAL_SHELL_CONTENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ config_dir = e_shell_backend_get_config_dir (shell_backend);
+
+ /* Calendar model for the views. */
+ cal_model = e_cal_model_calendar_new ();
+ e_cal_model_set_flags (
+ E_CAL_MODEL (cal_model),
+ E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES);
+
+ /* We borrow the memopad and taskpad models from the memo
+ * and task views, loading the views if necessary. */
+
+ foreign_view = e_shell_window_get_shell_view (shell_window, "memos");
+ foreign_content = e_shell_view_get_shell_content (foreign_view);
+ g_object_get (foreign_content, "model", &memo_model, NULL);
+
+ foreign_view = e_shell_window_get_shell_view (shell_window, "tasks");
+ foreign_content = e_shell_view_get_shell_content (foreign_view);
+ g_object_get (foreign_content, "model", &task_model, NULL);
+
+ /* Build content widgets. */
+
+ container = GTK_WIDGET (object);
+
+ /* FIXME Need to deal with saving and restoring the position.
+ * Month view has its own position. */
+ widget = gtk_hpaned_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->hpaned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->hpaned;
+
+ widget = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
+ gtk_paned_pack1 (GTK_PANED (container), widget, FALSE, TRUE);
+ priv->notebook = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* FIXME Need to deal with saving and restoring the position.
+ * Month view has its own position. */
+ widget = gtk_vpaned_new ();
+ gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
+ priv->vpaned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->notebook;
+
+ /* Add views in the order defined by GnomeCalendarViewType, such
+ * that the notebook page number corresponds to the view type.
+ * The assertions below ensure that stays true. */
+
+#if 0 /* Not so fast... get the memo/task pads working first. */
+ /* FIXME Need to establish a calendar and timezone first. */
+ widget = e_day_view_new (E_CAL_MODEL (cal_model));
+ e_calendar_view_set_calendar (
+ E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
+ e_calendar_view_set_timezone (
+ E_CALENDAR_VIEW (widget), priv->timezone);
+ page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
+ gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+ g_return_if_fail (page_num == GNOME_CAL_DAY_VIEW);
+ priv->day_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* FIXME Need to establish a calendar and timezone first. */
+ widget = e_day_view_new (E_CAL_MODEL (cal_model));
+ e_day_view_set_work_week_view (E_DAY_VIEW (widget), TRUE);
+ e_day_view_set_days_shown (E_DAY_VIEW (widget), 5);
+ e_calendar_view_set_calendar (
+ E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
+ e_calendar_view_set_timezone (
+ E_CALENDAR_VIEW (widget), priv->timezone);
+ page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
+ gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+ g_return_if_fail (page_num == GNOME_CAL_WORK_WEEK_VIEW);
+ priv->work_week_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* FIXME Need to establish a calendar and timezone first. */
+ widget = e_week_view_new (E_CAL_MODEL (cal_model));
+ e_calendar_view_set_calendar (
+ E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
+ e_calendar_view_set_timezone (
+ E_CALENDAR_VIEW (widget), priv->timezone);
+ page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
+ gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+ g_return_if_fail (page_num == GNOME_CAL_WEEK_VIEW);
+ priv->week_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* FIXME Need to establish a calendar and timezone first. */
+ widget = e_week_view_new (E_CAL_MODEL (cal_model));
+ e_week_view_set_multi_week_view (E_WEEK_VIEW (widget), TRUE);
+ e_week_view_set_weeks_shown (E_WEEK_VIEW (widget), 6);
+ e_calendar_view_set_calendar (
+ E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
+ e_calendar_view_set_timezone (
+ E_CALENDAR_VIEW (widget), priv->timezone);
+ page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
+ gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+ g_return_if_fail (page_num == GNOME_CAL_MONTH_VIEW);
+ priv->month_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* FIXME Need to establish a calendar and timezone first. */
+ widget = e_cal_list_view_new (E_CAL_MODEL (cal_model));
+ e_calendar_view_set_calendar (
+ E_CALENDAR_VIEW (widget), GNOME_CALENDAR (priv->calendar));
+ e_calendar_view_set_timezone (
+ E_CALENDAR_VIEW (widget), priv->timezone);
+ page_num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (widget));
+ gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL);
+ g_return_if_fail (page_num == GNOME_CAL_LIST_VIEW);
+ priv->list_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+#endif
+
+ container = priv->vpaned;
+
+ widget = gtk_vbox_new (FALSE, 0);
+ gtk_paned_pack1 (GTK_PANED (container), widget, FALSE, FALSE);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_hseparator_new ();
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new (NULL);
+ markup = g_strdup_printf ("<b>%s</b>", _("Tasks"));
+ gtk_label_set_markup (GTK_LABEL (widget), markup);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+ gtk_widget_show (widget);
+ g_free (markup);
+
+ widget = e_calendar_table_new (shell_view, task_model);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ priv->task_table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ filename = g_build_filename (config_dir, "TaskPad", NULL);
+ e_calendar_table_load_state (E_CALENDAR_TABLE (widget), filename);
+ g_free (filename);
+
+ container = priv->vpaned;
+
+ widget = gtk_vbox_new (FALSE, 0);
+ gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, FALSE);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_label_new (NULL);
+ markup = g_strdup_printf ("<b>%s</b>", _("Memos"));
+ gtk_label_set_markup (GTK_LABEL (widget), markup);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+ gtk_widget_show (widget);
+ g_free (markup);
+
+ widget = e_memo_table_new (shell_view, memo_model);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ priv->memo_table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ filename = g_build_filename (config_dir, "MemoPad", NULL);
+ e_memo_table_load_state (E_MEMO_TABLE (widget), filename);
+ g_free (filename);
+
+ /* Configuration managers for views and tables. */
+ priv->day_view_config = e_day_view_config_new (
+ E_DAY_VIEW (priv->day_view));
+ priv->work_week_view_config = e_day_view_config_new (
+ E_DAY_VIEW (priv->work_week_view));
+ priv->week_view_config = e_week_view_config_new (
+ E_WEEK_VIEW (priv->week_view));
+ priv->month_view_config = e_week_view_config_new (
+ E_WEEK_VIEW (priv->month_view));
+ priv->list_view_config = e_cal_list_view_config_new (
+ E_CAL_LIST_VIEW (priv->list_view));
+ priv->task_table_config = e_calendar_table_config_new (
+ E_CALENDAR_TABLE (priv->task_table));
+ priv->memo_table_config = e_memo_table_config_new (
+ E_MEMO_TABLE (priv->memo_table));
+
+ /* Load the view instance. */
+
+ view_instance = e_shell_view_new_view_instance (shell_view, NULL);
+ g_signal_connect_swapped (
+ view_instance, "display-view",
+ G_CALLBACK (cal_shell_content_display_view_cb),
+ object);
+ gal_view_instance_load (view_instance);
+ priv->view_instance = view_instance;
+
+ g_signal_connect_swapped (
+ shell_view, "notify::view-id",
+ G_CALLBACK (cal_shell_content_notify_view_id_cb),
+ object);
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (priv->vpaned);
+ key = "/apps/evolution/calendar/display/vpane_position";
+ gconf_bridge_bind_property_delayed (bridge, key, object, "position");
+
+ g_object_unref (memo_model);
+ g_object_unref (task_model);
+}
+
+static void
+cal_shell_content_class_init (ECalShellContentClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ECalShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = cal_shell_content_set_property;
+ object_class->get_property = cal_shell_content_get_property;
+ object_class->dispose = cal_shell_content_dispose;
+ object_class->finalize = cal_shell_content_finalize;
+ object_class->constructed = cal_shell_content_constructed;
+}
+
+static void
+cal_shell_content_init (ECalShellContent *cal_shell_content)
+{
+ cal_shell_content->priv =
+ E_CAL_SHELL_CONTENT_GET_PRIVATE (cal_shell_content);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_cal_shell_content_get_type (void)
+{
+ return cal_shell_content_type;
+}
+
+void
+e_cal_shell_content_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (ECalShellContentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) cal_shell_content_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ECalShellContent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) cal_shell_content_init,
+ NULL /* value_table */
+ };
+
+ cal_shell_content_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_CONTENT,
+ "ECalShellContent", &type_info, 0);
+}
+
+GtkWidget *
+e_cal_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_CAL_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+GnomeCalendar *
+e_cal_shell_content_get_calendar (ECalShellContent *cal_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ /* FIXME */
+ /*return GNOME_CALENDAR (cal_shell_content->priv->calendar);*/
+ return NULL;
+}
+
+EMemoTable *
+e_cal_shell_content_get_memo_table (ECalShellContent *cal_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ return E_MEMO_TABLE (cal_shell_content->priv->memo_table);
+}
+
+ECalendarTable *
+e_cal_shell_content_get_task_table (ECalShellContent *cal_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ return E_CALENDAR_TABLE (cal_shell_content->priv->task_table);
+}
+
+icaltimezone *
+e_cal_shell_content_get_timezone (ECalShellContent *cal_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ /* FIXME */
+ /*return cal_shell_content->priv->timezone;*/
+ return NULL;
+}
+
+GalViewInstance *
+e_cal_shell_content_get_view_instance (ECalShellContent *cal_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_CONTENT (cal_shell_content), NULL);
+
+ return cal_shell_content->priv->view_instance;
+}
+
+void
+e_cal_shell_content_copy_clipboard (ECalShellContent *cal_shell_content)
+{
+#if 0
+ GnomeCalendar *calendar;
+ EMemoTable *memo_table;
+ ECalendarTable *task_table;
+
+ g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ switch (cal_shell_content_get_focus_location (cal_shell_content)) {
+ case FOCUS_CALENDAR:
+ gnome_calendar_copy_clipboard (calendar);
+ break;
+
+ case FOCUS_MEMO_TABLE:
+ e_memo_table_copy_clipboard (memo_table);
+ break;
+
+ case FOCUS_TASK_TABLE:
+ e_calendar_table_copy_clipboard (task_table);
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+#endif
+}
+
+void
+e_cal_shell_content_cut_clipboard (ECalShellContent *cal_shell_content)
+{
+#if 0
+ GnomeCalendar *calendar;
+ EMemoTable *memo_table;
+ ECalendarTable *task_table;
+
+ g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ switch (cal_shell_content_get_focus_location (cal_shell_content)) {
+ case FOCUS_CALENDAR:
+ gnome_calendar_cut_clipboard (calendar);
+ break;
+
+ case FOCUS_MEMO_TABLE:
+ e_memo_table_copy_clipboard (memo_table);
+ break;
+
+ case FOCUS_TASK_TABLE:
+ e_calendar_table_copy_clipboard (task_table);
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+#endif
+}
+
+void
+e_cal_shell_content_paste_clipboard (ECalShellContent *cal_shell_content)
+{
+#if 0
+ GnomeCalendar *calendar;
+ EMemoTable *memo_table;
+ ECalendarTable *task_table;
+
+ g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ switch (cal_shell_content_get_focus_location (cal_shell_content)) {
+ case FOCUS_CALENDAR:
+ gnome_calendar_paste_clipboard (calendar);
+ break;
+
+ case FOCUS_MEMO_TABLE:
+ e_memo_table_copy_clipboard (memo_table);
+ break;
+
+ case FOCUS_TASK_TABLE:
+ e_calendar_table_copy_clipboard (task_table);
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+#endif
+}
+
+void
+e_cal_shell_content_delete_selection (ECalShellContent *cal_shell_content)
+{
+#if 0
+ GnomeCalendar *calendar;
+ EMemoTable *memo_table;
+ ECalendarTable *task_table;
+
+ g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ switch (cal_shell_content_get_focus_location (cal_shell_content)) {
+ case FOCUS_CALENDAR:
+ gnome_calendar_delete_selection (calendar);
+ break;
+
+ case FOCUS_MEMO_TABLE:
+ e_memo_table_delete_selected (memo_table);
+ break;
+
+ case FOCUS_TASK_TABLE:
+ e_calendar_table_delete_selected (task_table);
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+#endif
+}
+
+void
+e_cal_shell_content_delete_selected_occurrence (ECalShellContent *cal_shell_content)
+{
+#if 0
+ GnomeCalendar *calendar;
+ FocusLocation focus;
+
+ g_return_if_fail (E_IS_CAL_SHELL_CONTENT (cal_shell_content));
+
+ focus = cal_shell_content_get_focus_location (cal_shell_content);
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ if (focus == FOCUS_CALENDAR)
+ gnome_calendar_delete_selected_occurrence (calendar);
+#endif
+}
diff --cc calendar/module/e-cal-shell-content.h
index 6b86179,0000000..44e13f7
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-content.h
+++ b/calendar/module/e-cal-shell-content.h
@@@ -1,108 -1,0 +1,108 @@@
+/*
+ * e-cal-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_CONTENT_H
+#define E_CAL_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-view.h>
+
+#include <calendar/gui/e-memo-table.h>
+#include <calendar/gui/gnome-cal.h>
+#include <menus/gal-view-instance.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SHELL_CONTENT \
+ (e_cal_shell_content_get_type ())
+#define E_CAL_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContent))
+#define E_CAL_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentClass))
+#define E_IS_CAL_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SHELL_CONTENT))
+#define E_IS_CAL_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SHELL_CONTENT))
+#define E_CAL_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SHELL_CONTENT, ECalShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalShellContent ECalShellContent;
+typedef struct _ECalShellContentClass ECalShellContentClass;
+typedef struct _ECalShellContentPrivate ECalShellContentPrivate;
+
+enum {
+ E_CAL_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
+ E_CAL_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_ASSIGNABLE = 1 << 2,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_COMPLETE = 1 << 3,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_EDITABLE = 1 << 4,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_MEETING = 1 << 5,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_ORGANIZER = 1 << 6,
+ E_CAL_SHELL_CONTENT_SELECTION_IS_RECURRING = 1 << 7,
+ E_CAL_SHELL_CONTENT_SELECTION_CAN_ACCEPT = 1 << 8,
+ E_CAL_SHELL_CONTENT_SELECTION_CAN_DELEGATE = 1 << 9,
+ E_CAL_SHELL_CONTENT_SELECTION_CAN_SAVE = 1 << 10
+};
+
+struct _ECalShellContent {
+ EShellContent parent;
+ ECalShellContentPrivate *priv;
+};
+
+struct _ECalShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_cal_shell_content_get_type (void);
+void e_cal_shell_content_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_cal_shell_content_new (EShellView *shell_view);
+GnomeCalendar * e_cal_shell_content_get_calendar
+ (ECalShellContent *cal_shell_content);
+EMemoTable * e_cal_shell_content_get_memo_table
+ (ECalShellContent *cal_shell_content);
+ECalendarTable *e_cal_shell_content_get_task_table
+ (ECalShellContent *cal_shell_content);
+icaltimezone * e_cal_shell_content_get_timezone
+ (ECalShellContent *cal_shell_content);
+GalViewInstance *
+ e_cal_shell_content_get_view_instance
+ (ECalShellContent *cal_shell_content);
+void e_cal_shell_content_copy_clipboard
+ (ECalShellContent *cal_shell_content);
+void e_cal_shell_content_cut_clipboard
+ (ECalShellContent *cal_shell_content);
+void e_cal_shell_content_paste_clipboard
+ (ECalShellContent *cal_shell_content);
+void e_cal_shell_content_delete_selection
+ (ECalShellContent *cal_shell_content);
+void e_cal_shell_content_delete_selected_occurrence
+ (ECalShellContent *cal_shell_content);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_CONTENT_H */
diff --cc calendar/module/e-cal-shell-migrate.c
index bdcca08,0000000..5414f4a
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-migrate.c
+++ b/calendar/module/e-cal-shell-migrate.c
@@@ -1,796 -1,0 +1,796 @@@
+/*
+ * e-cal-shell-backend-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-migrate.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <libebackend/e-dbhash.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-group.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-xml-hash-utils.h>
+
+#include "e-util/e-bconf-map.h"
+#include "e-util/e-folder-map.h"
+#include "e-util/e-util-private.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/calendar-config-keys.h"
+#include "calendar/gui/e-cal-event.h"
+#include "shell/e-shell.h"
+
+#define WEBCAL_BASE_URI "webcal://"
+#define CONTACTS_BASE_URI "contacts://"
+#define BAD_CONTACTS_BASE_URI "contact://"
+#define PERSONAL_RELATIVE_URI "system"
+
+static e_gconf_map_t calendar_display_map[] = {
+ /* /Calendar/Display */
+ { "Timezone", "calendar/display/timezone", E_GCONF_MAP_STRING },
+ { "Use24HourFormat", "calendar/display/use_24hour_format", E_GCONF_MAP_BOOL },
+ { "WeekStartDay", "calendar/display/week_start_day", E_GCONF_MAP_INT },
+ { "DayStartHour", "calendar/display/day_start_hour", E_GCONF_MAP_INT },
+ { "DayStartMinute", "calendar/display/day_start_minute", E_GCONF_MAP_INT },
+ { "DayEndHour", "calendar/display/day_end_hour", E_GCONF_MAP_INT },
+ { "DayEndMinute", "calendar/display/day_end_minute", E_GCONF_MAP_INT },
+ { "TimeDivisions", "calendar/display/time_divisions", E_GCONF_MAP_INT },
+ { "View", "calendar/display/default_view", E_GCONF_MAP_INT },
+ { "HPanePosition", "calendar/display/hpane_position", E_GCONF_MAP_FLOAT },
+ { "VPanePosition", "calendar/display/vpane_position", E_GCONF_MAP_FLOAT },
+ { "MonthHPanePosition", "calendar/display/month_hpane_position", E_GCONF_MAP_FLOAT },
+ { "MonthVPanePosition", "calendar/display/month_vpane_position", E_GCONF_MAP_FLOAT },
+ { "CompressWeekend", "calendar/display/compress_weekend", E_GCONF_MAP_BOOL },
+ { "ShowEventEndTime", "calendar/display/show_event_end", E_GCONF_MAP_BOOL },
+ { "WorkingDays", "calendar/display/working_days", E_GCONF_MAP_INT },
+ { NULL },
+};
+
+static e_gconf_map_t calendar_other_map[] = {
+ /* /Calendar/Other */
+ { "ConfirmDelete", "calendar/prompts/confirm_delete", E_GCONF_MAP_BOOL },
+ { "ConfirmExpunge", "calendar/prompts/confirm_purge", E_GCONF_MAP_BOOL },
+ { "UseDefaultReminder", "calendar/other/use_default_reminder", E_GCONF_MAP_BOOL },
+ { "DefaultReminderInterval", "calendar/other/default_reminder_interval", E_GCONF_MAP_INT },
+ { "DefaultReminderUnits", "calendar/other/default_reminder_units", E_GCONF_MAP_STRING },
+ { NULL },
+};
+
+static e_gconf_map_t calendar_datenavigator_map[] = {
+ /* /Calendar/DateNavigator */
+ { "ShowWeekNumbers", "calendar/date_navigator/show_week_numbers", E_GCONF_MAP_BOOL },
+ { NULL },
+};
+
+static e_gconf_map_t calendar_alarmnotify_map[] = {
+ /* /Calendar/AlarmNotify */
+ { "LastNotificationTime", "calendar/notify/last_notification_time", E_GCONF_MAP_INT },
+ { "CalendarToLoad%i", "calendar/notify/calendars", E_GCONF_MAP_STRING|E_GCONF_MAP_LIST },
+ { "BlessedProgram%i", "calendar/notify/programs", E_GCONF_MAP_STRING|E_GCONF_MAP_LIST },
+ { NULL },
+};
+
+static e_gconf_map_list_t calendar_remap_list[] = {
+
+ { "/Calendar/Display", calendar_display_map },
+ { "/Calendar/Other/Map", calendar_other_map },
+ { "/Calendar/DateNavigator", calendar_datenavigator_map },
+ { "/Calendar/AlarmNotify", calendar_alarmnotify_map },
+
+ { NULL },
+};
+
+static GtkWidget *window;
+static GtkLabel *label;
+static GtkProgressBar *progress;
+
+#ifndef G_OS_WIN32
+
+/* No previous versions have been available on Win32, so don't
+ * bother with upgrade support from 1.x on Win32.
+ */
+
+static void
+setup_progress_dialog (void)
+{
+ GtkWidget *vbox, *hbox, *w;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title ((GtkWindow *) window, _("Migrating..."));
+ gtk_window_set_modal ((GtkWindow *) window, TRUE);
+ gtk_container_set_border_width ((GtkContainer *) window, 6);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_container_add ((GtkContainer *) window, vbox);
+
+ w = gtk_label_new (_("The location and hierarchy of the Evolution calendar "
+ "folders has changed since Evolution 1.x.\n\nPlease be "
+ "patient while Evolution migrates your folders..."));
+
+ gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+ gtk_widget_show (w);
+ gtk_box_pack_start_defaults ((GtkBox *) vbox, w);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start_defaults ((GtkBox *) vbox, hbox);
+
+ label = (GtkLabel *) gtk_label_new ("");
+ gtk_widget_show ((GtkWidget *) label);
+ gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) label);
+
+ progress = (GtkProgressBar *) gtk_progress_bar_new ();
+ gtk_widget_show ((GtkWidget *) progress);
+ gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) progress);
+
+ gtk_widget_show (window);
+}
+
+static void
+dialog_close (void)
+{
+ gtk_widget_destroy ((GtkWidget *) window);
+}
+
+static void
+dialog_set_folder_name (const char *folder_name)
+{
+ char *text;
+
+ text = g_strdup_printf (_("Migrating '%s':"), folder_name);
+ gtk_label_set_text (label, text);
+ g_free (text);
+
+ gtk_progress_bar_set_fraction (progress, 0.0);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+static void
+dialog_set_progress (double percent)
+{
+ char text[5];
+
+ snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f));
+
+ gtk_progress_bar_set_fraction (progress, percent);
+ gtk_progress_bar_set_text (progress, text);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+static gboolean
+check_for_conflict (ESourceGroup *group, char *name)
+{
+ GSList *sources;
+ GSList *s;
+
+ sources = e_source_group_peek_sources (group);
+
+ for (s = sources; s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+
+ if (!strcmp (e_source_peek_name (source), name))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static char *
+get_source_name (ESourceGroup *group, const char *path)
+{
+ char **p = g_strsplit (path, "/", 0);
+ int i, j, starting_index;
+ int num_elements;
+ gboolean conflict;
+ GString *s = g_string_new (NULL);
+
+ for (i = 0; p[i]; i ++) ;
+
+ num_elements = i;
+ i--;
+
+ /* p[i] is now the last path element */
+
+ /* check if it conflicts */
+ starting_index = i;
+ do {
+ for (j = starting_index; j < num_elements; j += 2) {
+ if (j != starting_index)
+ g_string_append_c (s, '_');
+ g_string_append (s, p[j]);
+ }
+
+ conflict = check_for_conflict (group, s->str);
+
+
+ /* if there was a conflict back up 2 levels (skipping the /subfolder/ element) */
+ if (conflict)
+ starting_index -= 2;
+
+ /* we always break out if we can't go any further,
+ regardless of whether or not we conflict. */
+ if (starting_index < 0)
+ break;
+
+ } while (conflict);
+ g_strfreev (p);
+
+ return g_string_free (s, FALSE);
+}
+
+static gboolean
+migrate_ical (ECal *old_ecal, ECal *new_ecal)
+{
+ GList *l, *objects;
+ int num_added = 0;
+ int num_objects;
+ gboolean retval = TRUE;
+
+ /* both ecals are loaded, start the actual migration */
+ if (!e_cal_get_object_list (old_ecal, "#t", &objects, NULL))
+ return FALSE;
+
+ num_objects = g_list_length (objects);
+ for (l = objects; l; l = l->next) {
+ icalcomponent *ical_comp = l->data;
+ GError *error = NULL;
+
+ if (!e_cal_create_object (new_ecal, ical_comp, NULL, &error)) {
+ g_warning ("Migration of object failed: %s", error->message);
+ retval = FALSE;
+ }
+
+ g_clear_error (&error);
+
+ num_added ++;
+ dialog_set_progress ((double)num_added / num_objects);
+ }
+
+ g_list_foreach (objects, (GFunc) icalcomponent_free, NULL);
+ g_list_free (objects);
+
+ return retval;
+}
+
+static gboolean
+migrate_ical_folder_to_source (char *old_path, ESource *new_source, ECalSourceType type)
+{
+ ECal *old_ecal = NULL, *new_ecal = NULL;
+ ESource *old_source;
+ ESourceGroup *group;
+ char *old_uri = g_strdup_printf ("file://%s", old_path);
+ GError *error = NULL;
+ gboolean retval = FALSE;
+
+ group = e_source_group_new ("", old_uri);
+ old_source = e_source_new ("", "");
+ e_source_group_add_source (group, old_source, -1);
+
+ dialog_set_folder_name (e_source_peek_name (new_source));
+
+ if (!(old_ecal = e_cal_new (old_source, type))) {
+ g_warning ("could not find a backend for '%s'", e_source_get_uri (old_source));
+ goto finish;
+ }
+ if (!e_cal_open (old_ecal, FALSE, &error)) {
+ g_warning ("failed to load source ecal for migration: '%s' (%s)", error->message,
+ e_source_get_uri (old_source));
+ goto finish;
+ }
+
+ if (!(new_ecal = e_cal_new (new_source, type))) {
+ g_warning ("could not find a backend for '%s'", e_source_get_uri (new_source));
+ goto finish;
+ }
+ if (!e_cal_open (new_ecal, FALSE, &error)) {
+ g_warning ("failed to load destination ecal for migration: '%s' (%s)", error->message,
+ e_source_get_uri (new_source));
+ goto finish;
+ }
+
+ retval = migrate_ical (old_ecal, new_ecal);
+
+finish:
+ g_clear_error (&error);
+ if (old_ecal)
+ g_object_unref (old_ecal);
+ g_object_unref (group);
+ if (new_ecal)
+ g_object_unref (new_ecal);
+ g_free (old_uri);
+
+ return retval;
+}
+
+static gboolean
+migrate_ical_folder (char *old_path, ESourceGroup *dest_group, char *source_name, ECalSourceType type)
+{
+ ESource *new_source;
+ gboolean retval;
+
+ new_source = e_source_new (source_name, source_name);
+ e_source_set_relative_uri (new_source, e_source_peek_uid (new_source));
+ e_source_group_add_source (dest_group, new_source, -1);
+
+ retval = migrate_ical_folder_to_source (old_path, new_source, type);
+
+ g_object_unref (new_source);
+
+ return retval;
+}
+
+#endif /* !G_OS_WIN32 */
+
+#ifndef G_OS_WIN32
+
+static void
+migrate_pilot_db_key (const char *key, gpointer user_data)
+{
+ EXmlHash *xmlhash = user_data;
+
+ e_xmlhash_add (xmlhash, key, "");
+}
+
+static void
+migrate_pilot_data (const char *component, const char *conduit, const char *old_path, const char *new_path)
+{
+ char *changelog, *map;
+ const char *dent;
+ const char *ext;
+ char *filename;
+ GDir *dir;
+
+ if (!(dir = g_dir_open (old_path, 0, NULL)))
+ return;
+
+ map = g_alloca (12 + strlen (conduit));
+ sprintf (map, "pilot-map-%s-", conduit);
+
+ changelog = g_alloca (24 + strlen (conduit));
+ sprintf (changelog, "pilot-sync-evolution-%s-", conduit);
+
+ while ((dent = g_dir_read_name (dir))) {
+ if (!strncmp (dent, map, strlen (map)) &&
+ ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) {
+ /* pilot map file - src and dest file formats are identical */
+ unsigned char inbuf[4096];
+ size_t nread, nwritten;
+ int fd0, fd1;
+ ssize_t n;
+
+ filename = g_build_filename (old_path, dent, NULL);
+ if ((fd0 = g_open (filename, O_RDONLY|O_BINARY, 0)) == -1) {
+ g_free (filename);
+ continue;
+ }
+
+ g_free (filename);
+ filename = g_build_filename (new_path, dent, NULL);
+ if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) {
+ g_free (filename);
+ close (fd0);
+ continue;
+ }
+
+ do {
+ do {
+ n = read (fd0, inbuf, sizeof (inbuf));
+ } while (n == -1 && errno == EINTR);
+
+ if (n < 1)
+ break;
+
+ nread = n;
+ nwritten = 0;
+ do {
+ do {
+ n = write (fd1, inbuf + nwritten, nread - nwritten);
+ } while (n == -1 && errno == EINTR);
+
+ if (n > 0)
+ nwritten += n;
+ } while (nwritten < nread && n != -1);
+
+ if (n == -1)
+ break;
+ } while (1);
+
+ if (n != -1)
+ n = fsync (fd1);
+
+ if (n == -1) {
+ g_warning ("Failed to migrate %s: %s", dent, strerror (errno));
+ g_unlink (filename);
+ }
+
+ close (fd0);
+ close (fd1);
+ g_free (filename);
+ } else if (!strncmp (dent, changelog, strlen (changelog)) &&
+ ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db"))) {
+ /* src and dest formats differ, src format is db3 while dest format is xml */
+ EXmlHash *xmlhash;
+ EDbHash *dbhash;
+ struct stat st;
+
+ filename = g_build_filename (old_path, dent, NULL);
+ if (g_stat (filename, &st) == -1) {
+ g_free (filename);
+ continue;
+ }
+
+ dbhash = e_dbhash_new (filename);
+ g_free (filename);
+
+ filename = g_strdup_printf ("%s/%s.ics-%s", new_path, component, dent);
+ if (g_stat (filename, &st) != -1)
+ g_unlink (filename);
+ xmlhash = e_xmlhash_new (filename);
+ g_free (filename);
+
+ e_dbhash_foreach_key (dbhash, migrate_pilot_db_key, xmlhash);
+
+ e_dbhash_destroy (dbhash);
+
+ e_xmlhash_write (xmlhash);
+ e_xmlhash_destroy (xmlhash);
+ }
+ }
+
+ g_dir_close (dir);
+}
+
+#endif
+
+static ESourceGroup *
+create_calendar_contact_source (ESourceList *source_list)
+{
+ ESourceGroup *group;
+ ESource *source;
+
+ /* Create the contacts group */
+ group = e_source_group_new (_("Contacts"), CONTACTS_BASE_URI);
+ e_source_list_add_group (source_list, group, -1);
+
+ source = e_source_new (_("Birthdays & Anniversaries"), "/");
+ e_source_group_add_source (group, source, -1);
+ g_object_unref (source);
+
+ e_source_set_color_spec (source, "#FED4D3");
+ e_source_group_set_readonly (group, TRUE);
+
+ return group;
+}
+
+static void
+create_calendar_sources (EShellBackend *shell_backend,
+ ESourceList *source_list,
+ ESourceGroup **on_this_computer,
+ ESource **personal_source,
+ ESourceGroup **on_the_web,
+ ESourceGroup **contacts)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ GSList *groups;
+ ESourceGroup *group;
+ char *base_uri, *base_uri_proto;
+ const gchar *base_dir;
+
+ *on_this_computer = NULL;
+ *on_the_web = NULL;
+ *contacts = NULL;
+ *personal_source = NULL;
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ base_dir = e_shell_backend_get_config_dir (shell_backend);
+ base_uri = g_build_filename (base_dir, "local", NULL);
+
+ base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL);
+
+ groups = e_source_list_peek_groups (source_list);
+ if (groups) {
+ /* groups are already there, we need to search for things... */
+ GSList *g;
+
+ for (g = groups; g; g = g->next) {
+
+ group = E_SOURCE_GROUP (g->data);
+
+ if (!strcmp (BAD_CONTACTS_BASE_URI, e_source_group_peek_base_uri (group)))
+ e_source_group_set_base_uri (group, CONTACTS_BASE_URI);
+
+ if (!strcmp (base_uri, e_source_group_peek_base_uri (group)))
+ e_source_group_set_base_uri (group, base_uri_proto);
+
+ if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
+ *on_this_computer = g_object_ref (group);
+ else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group)))
+ *on_the_web = g_object_ref (group);
+ else if (!*contacts && !strcmp (CONTACTS_BASE_URI, e_source_group_peek_base_uri (group)))
+ *contacts = g_object_ref (group);
+ }
+ }
+
+ if (*on_this_computer) {
+ /* make sure "Personal" shows up as a source under
+ this group */
+ GSList *sources = e_source_group_peek_sources (*on_this_computer);
+ GSList *s;
+ for (s = sources; s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (relative_uri == NULL)
+ continue;
+ if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) {
+ *personal_source = g_object_ref (source);
+ break;
+ }
+ }
+ } else {
+ /* create the local source group */
+ group = e_source_group_new (_("On This Computer"), base_uri_proto);
+ e_source_list_add_group (source_list, group, -1);
+
+ *on_this_computer = group;
+ }
+
+ if (!*personal_source) {
+ char *primary_calendar;
+
+ /* Create the default Person calendar */
+ ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
+ e_source_group_add_source (*on_this_computer, source, -1);
+
+ primary_calendar = e_shell_settings_get_string (
+ shell_settings, "cal-primary-calendar");
+
+ if (!primary_calendar && !calendar_config_get_calendars_selected ()) {
+ GSList selected;
+
+ e_shell_settings_set_string (
+ shell_settings, "cal-primary-calendar",
+ e_source_peek_uid (source));
+
+ selected.data = (gpointer)e_source_peek_uid (source);
+ selected.next = NULL;
+ calendar_config_set_calendars_selected (&selected);
+ }
+
+ g_free (primary_calendar);
+ e_source_set_color_spec (source, "#BECEDD");
+ *personal_source = source;
+ }
+
+ if (!*on_the_web) {
+ /* Create the Webcal source group */
+ group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI);
+ e_source_list_add_group (source_list, group, -1);
+
+ *on_the_web = group;
+ }
+
+ if (!*contacts) {
+ group = create_calendar_contact_source (source_list);
+
+ *contacts = group;
+ }
+
+ g_free (base_uri_proto);
+ g_free (base_uri);
+}
+
+gboolean
+e_cal_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ ESourceGroup *on_this_computer = NULL, *on_the_web = NULL, *contacts = NULL;
+ ESource *personal_source = NULL;
+ ESourceList *source_list;
+ ECalEvent *ece;
+ ECalEventTargetModule *target;
+ gboolean retval = FALSE;
+
+ source_list = g_object_get_data (
+ G_OBJECT (shell_backend), "source-list");
+
+ /* we call this unconditionally now - create_groups either
+ creates the groups/sources or it finds the necessary
+ groups/sources. */
+ create_calendar_sources (
+ shell_backend, source_list, &on_this_computer,
+ &personal_source, &on_the_web, &contacts);
+
+#ifndef G_OS_WIN32
+ if (major == 1) {
+ xmlDocPtr config_doc = NULL;
+ char *conf_file;
+ struct stat st;
+
+ conf_file = g_build_filename (g_get_home_dir (), "evolution", "config.xmldb", NULL);
+ if (lstat (conf_file, &st) == 0 && S_ISREG (st.st_mode))
+ config_doc = xmlParseFile (conf_file);
+ g_free (conf_file);
+
+ if (config_doc && minor <= 2) {
+ GConfClient *gconf;
+ int res = 0;
+
+ /* move bonobo config to gconf */
+ gconf = gconf_client_get_default ();
+
+ res = e_bconf_import (gconf, config_doc, calendar_remap_list);
+
+ g_object_unref (gconf);
+
+ xmlFreeDoc(config_doc);
+
+ if (res != 0) {
+ /* FIXME: set proper domain/code */
+ g_set_error(error, 0, 0, _("Unable to migrate old settings from evolution/config.xmldb"));
+ goto fail;
+ }
+ }
+
+ if (minor <= 4) {
+ GSList *migration_dirs, *l;
+ char *path, *local_cal_folder;
+
+ setup_progress_dialog ();
+
+ path = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+ migration_dirs = e_folder_map_local_folders (path, "calendar");
+ local_cal_folder = g_build_filename (path, "Calendar", NULL);
+ g_free (path);
+
+ if (personal_source)
+ migrate_ical_folder_to_source (local_cal_folder, personal_source, E_CAL_SOURCE_TYPE_EVENT);
+
+ for (l = migration_dirs; l; l = l->next) {
+ char *source_name;
+
+ if (personal_source && !strcmp ((char*)l->data, local_cal_folder))
+ continue;
+
+ source_name = get_source_name (on_this_computer, (char*)l->data);
+
+ if (!migrate_ical_folder (l->data, on_this_computer, source_name, E_CAL_SOURCE_TYPE_EVENT)) {
+ /* FIXME: domain/code */
+ g_set_error(error, 0, 0, _("Unable to migrate calendar `%s'"), source_name);
+ g_free(source_name);
+ goto fail;
+ }
+
+ g_free (source_name);
+ }
+
+ g_free (local_cal_folder);
+
+ dialog_close ();
+ }
+
+ if (minor <= 4 || (minor == 5 && micro < 5)) {
+ GConfClient *gconf;
+ GConfValue *gconf_val;
+ int i;
+ const char *keys[] = {
+ CALENDAR_CONFIG_HPANE_POS,
+ CALENDAR_CONFIG_VPANE_POS,
+ CALENDAR_CONFIG_MONTH_HPANE_POS,
+ CALENDAR_CONFIG_MONTH_VPANE_POS,
+ NULL
+ };
+
+ gconf = gconf_client_get_default ();
+
+ for (i = 0; keys[i]; i++) {
+ gconf_val = gconf_client_get (gconf, keys[i], NULL);
+ if (gconf_val) {
+ if (gconf_val->type != GCONF_VALUE_INT)
+ gconf_client_unset (gconf, keys[i], NULL);
+ gconf_value_free (gconf_val);
+ }
+ }
+
+ g_object_unref (gconf);
+ }
+
+ if (minor < 5 || (minor == 5 && micro <= 10)) {
+ char *old_path, *new_path;
+
+ old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Calendar", NULL);
+ new_path = g_build_filename (e_shell_backend_get_config_dir (shell_backend),
+ "local", "system", NULL);
+ migrate_pilot_data ("calendar", "calendar", old_path, new_path);
+ g_free (new_path);
+ g_free (old_path);
+ }
+
+ /* we only need to do this next step if people ran
+ older versions of 1.5. We need to clear out the
+ absolute URI's that were assigned to ESources
+ during one phase of development, as they take
+ precedent over relative uris (but aren't updated
+ when editing an ESource). */
+ if (minor == 5 && micro <= 11) {
+ GSList *g;
+ for (g = e_source_list_peek_groups (source_list); g; g = g->next) {
+ ESourceGroup *group = g->data;
+ GSList *s;
+
+ for (s = e_source_group_peek_sources (group); s; s = s->next) {
+ ESource *source = s->data;
+ e_source_set_absolute_uri (source, NULL);
+ }
+ }
+ }
+
+ }
+#endif /* !G_OS_WIN32 */
+
+ e_source_list_sync (source_list, NULL);
+
+ /** @Event: component.migration
+ * @Title: Migration step in component initialization
+ * @Target: ECalEventTargetComponent
+ *
+ * component.migration is emitted during the calendar component
+ * initialization process. This allows new calendar backend types
+ * to be distributed as an e-d-s backend and a plugin without
+ * reaching their grubby little fingers into migration.c
+ */
+ /* Fire off migration event */
+ ece = e_cal_event_peek ();
+ target = e_cal_event_target_new_module (ece, shell_backend, 0);
+ e_event_emit ((EEvent *) ece, "module.migration", (EEventTarget *) target);
+
+ retval = TRUE;
+fail:
+ if (on_this_computer)
+ g_object_unref (on_this_computer);
+ if (on_the_web)
+ g_object_unref (on_the_web);
+ if (contacts)
+ g_object_unref (contacts);
+ if (personal_source)
+ g_object_unref (personal_source);
+
+ return retval;
+}
+
diff --cc calendar/module/e-cal-shell-migrate.h
index 44cbf68,0000000..359ca5e
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-migrate.h
+++ b/calendar/module/e-cal-shell-migrate.h
@@@ -1,38 -1,0 +1,38 @@@
+/*
+ * e-cal-shell-backend-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_BACKEND_MIGRATE_H
+#define E_CAL_SHELL_BACKEND_MIGRATE_H
+
+#include <glib.h>
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_cal_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_BACKEND_MIGRATE_H */
diff --cc calendar/module/e-cal-shell-settings.c
index 639622f,0000000..03af4ae
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-settings.c
+++ b/calendar/module/e-cal-shell-settings.c
@@@ -1,59 -1,0 +1,59 @@@
+/*
+ * e-cal-shell-backend-settings.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-settings.h"
+
+#include <gconf/gconf-client.h>
+
+void
+e_cal_shell_backend_init_settings (EShell *shell)
+{
+ EShellSettings *shell_settings;
+
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ /* XXX Default values should match the GConf schema.
+ * Yes it's redundant, but we're stuck with GConf. */
+
+ e_shell_settings_install_property (
+ g_param_spec_string (
+ "cal-primary-calendar",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "cal-primary-calendar",
+ "/apps/evolution/calendar/display/primary_calendar");
+
+ e_shell_settings_install_property (
+ g_param_spec_boolean (
+ "cal-use-system-timezone",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ e_shell_settings_bind_to_gconf (
+ shell_settings, "cal-use-system-timezone",
+ "/apps/evolution/calendar/display/use_system_timezone");
+}
diff --cc calendar/module/e-cal-shell-settings.h
index 7382130,0000000..de8b228
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-settings.h
+++ b/calendar/module/e-cal-shell-settings.h
@@@ -1,33 -1,0 +1,33 @@@
+/*
+ * e-cal-shell-backend-settings.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_BACKEND_SETTINGS_H
+#define E_CAL_SHELL_BACKEND_SETTINGS_H
+
+#include <shell/e-shell.h>
+
+G_BEGIN_DECLS
+
+void e_cal_shell_backend_init_settings (EShell *shell);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_BACKEND_SETTINGS_H */
diff --cc calendar/module/e-cal-shell-sidebar.c
index 2646836,0000000..dc7df59
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-sidebar.c
+++ b/calendar/module/e-cal-shell-sidebar.c
@@@ -1,759 -1,0 +1,759 @@@
+/*
+ * e-cal-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-sidebar.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-error.h"
+#include "e-util/gconf-bridge.h"
+#include "calendar/common/authentication.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/e-calendar-selector.h"
+#include "calendar/gui/e-mini-calendar-config.h"
+#include "calendar/gui/misc.h"
+
+#include "e-cal-shell-backend.h"
+#include "e-cal-shell-view.h"
+
+#define E_CAL_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarPrivate))
+
+struct _ECalShellSidebarPrivate {
+ GtkWidget *paned;
+ GtkWidget *selector;
+ GtkWidget *mini_calendar;
+
+ /* UID -> Client */
+ GHashTable *client_table;
+
+ EMiniCalendarConfig *mini_calendar_config;
+};
+
+enum {
+ PROP_0,
+ PROP_MINI_CALENDAR,
+ PROP_SELECTOR
+};
+
+enum {
+ CLIENT_ADDED,
+ CLIENT_REMOVED,
+ STATUS_MESSAGE,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+static GType cal_shell_sidebar_type;
+
+static void
+cal_shell_sidebar_emit_client_added (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client)
+{
+ guint signal_id = signals[CLIENT_ADDED];
+
+ g_signal_emit (cal_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+cal_shell_sidebar_emit_client_removed (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client)
+{
+ guint signal_id = signals[CLIENT_REMOVED];
+
+ g_signal_emit (cal_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+cal_shell_sidebar_emit_status_message (ECalShellSidebar *cal_shell_sidebar,
+ const gchar *status_message)
+{
+ guint signal_id = signals[STATUS_MESSAGE];
+
+ g_signal_emit (cal_shell_sidebar, signal_id, 0, status_message);
+}
+
+static void
+cal_shell_sidebar_backend_died_cb (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ GHashTable *client_table;
+ ESource *source;
+ const gchar *uid;
+
+ client_table = cal_shell_sidebar->priv->client_table;
+
+ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ source = e_cal_get_source (client);
+ uid = e_source_peek_uid (source);
+
+ g_object_ref (source);
+
+ g_hash_table_remove (client_table, uid);
+ cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
+
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:calendar-crashed", NULL);
+
+ g_object_unref (source);
+}
+
+static void
+cal_shell_sidebar_backend_error_cb (ECalShellSidebar *cal_shell_sidebar,
+ const gchar *message,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ GtkWidget *dialog;
+ const gchar *uri;
+ gchar *uri_no_passwd;
+
+ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ uri = e_cal_get_uri (client);
+ uri_no_passwd = get_uri_without_password (uri);
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("Error on %s\n%s"),
+ uri_no_passwd, message);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_free (uri_no_passwd);
+}
+
+static void
+cal_shell_sidebar_client_opened_cb (ECalShellSidebar *cal_shell_sidebar,
+ ECalendarStatus status,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ ESource *source;
+
+ source = e_cal_get_source (client);
+
+ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
+ status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
+ auth_cal_forget_password (client);
+
+ switch (status) {
+ case E_CALENDAR_STATUS_OK:
+ g_signal_handlers_disconnect_matched (
+ client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+ cal_shell_sidebar_client_opened_cb, NULL);
+
+ cal_shell_sidebar_emit_status_message (
+ cal_shell_sidebar, _("Loading calendars"));
+ cal_shell_sidebar_emit_client_added (
+ cal_shell_sidebar, client);
+ cal_shell_sidebar_emit_status_message (
+ cal_shell_sidebar, NULL);
+ break;
+
+ case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
+ e_cal_open_async (client, FALSE);
+ break;
+
+ case E_CALENDAR_STATUS_BUSY:
+ break;
+
+ case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-no-contents-offline-calendar",
+ NULL);
+ break;
+
+ default:
+ cal_shell_sidebar_emit_client_removed (
+ cal_shell_sidebar, client);
+ break;
+ }
+}
+
+static void
+cal_shell_sidebar_row_changed_cb (ECalShellSidebar *cal_shell_sidebar,
+ GtkTreePath *tree_path,
+ GtkTreeIter *tree_iter,
+ GtkTreeModel *tree_model)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ /* XXX ESourceSelector's underlying tree store has only one
+ * column: ESource objects. While we're not supposed to
+ * know this, listening for "row-changed" signals from
+ * the model is easier to deal with than the selector's
+ * "selection-changed" signal, which doesn't tell you
+ * _which_ row changed. */
+
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ gtk_tree_model_get (tree_model, tree_iter, 0, &source, -1);
+
+ /* XXX This signal gets emitted a lot while the model is being
+ * rebuilt, during which time we won't get a valid ESource.
+ * ESourceSelector should probably block this signal while
+ * rebuilding the model, but we'll be forgiving and not
+ * emit a warning. */
+ if (!E_IS_SOURCE (source))
+ return;
+
+ if (e_source_selector_source_is_selected (selector, source))
+ e_cal_shell_sidebar_add_source (cal_shell_sidebar, source);
+ else
+ e_cal_shell_sidebar_remove_source (cal_shell_sidebar, source);
+}
+
+static void
+cal_shell_sidebar_selection_changed_cb (ECalShellSidebar *cal_shell_sidebar,
+ ESourceSelector *selector)
+{
+ GSList *list, *iter;
+
+ /* This signal is emitted less frequently than "row-changed",
+ * especially when the model is being rebuilt. So we'll take
+ * it easy on poor GConf. */
+
+ list = e_source_selector_get_selection (selector);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+
+ iter->data = (gpointer) e_source_peek_uid (source);
+ g_object_unref (source);
+ }
+
+ calendar_config_set_calendars_selected (list);
+
+ g_slist_free (list);
+}
+
+static void
+cal_shell_sidebar_primary_selection_changed_cb (ECalShellSidebar *cal_shell_sidebar,
+ ESourceSelector *selector)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ EShellSettings *shell_settings;
+ ESource *source;
+
+ /* XXX ESourceSelector needs a "primary-selection-uid" property
+ * so we can just bind the property with GConfBridge. */
+
+ source = e_source_selector_peek_primary_selection (selector);
+ if (source == NULL)
+ return;
+
+ shell_sidebar = E_SHELL_SIDEBAR (cal_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ e_shell_settings_set_string (
+ shell_settings, "cal-primary-calendar",
+ e_source_peek_uid (source));
+}
+
+static void
+cal_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MINI_CALENDAR:
+ g_value_set_object (
+ value, e_cal_shell_sidebar_get_mini_calendar (
+ E_CAL_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_SELECTOR:
+ g_value_set_object (
+ value, e_cal_shell_sidebar_get_selector (
+ E_CAL_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+cal_shell_sidebar_dispose (GObject *object)
+{
+ ECalShellSidebarPrivate *priv;
+
+ priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->selector != NULL) {
+ g_object_unref (priv->selector);
+ priv->selector = NULL;
+ }
+
+ if (priv->mini_calendar != NULL) {
+ g_object_unref (priv->mini_calendar);
+ priv->mini_calendar = NULL;
+ }
+
+ g_hash_table_remove_all (priv->client_table);
+
+ if (priv->mini_calendar_config != NULL) {
+ g_object_unref (priv->mini_calendar_config);
+ priv->mini_calendar = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+cal_shell_sidebar_finalize (GObject *object)
+{
+ ECalShellSidebarPrivate *priv;
+
+ priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->client_table);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+cal_shell_sidebar_constructed (GObject *object)
+{
+ ECalShellSidebarPrivate *priv;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellBackend *shell_backend;
+ EShellSidebar *shell_sidebar;
+ EShellSettings *shell_settings;
+ ESourceSelector *selector;
+ ESourceList *source_list;
+ ESource *source;
+ ECalendarItem *calitem;
+ GConfBridge *bridge;
+ GtkTreeModel *model;
+ GtkWidget *container;
+ GtkWidget *widget;
+ AtkObject *a11y;
+ GSList *list, *iter;
+ const gchar *key;
+ gchar *uid;
+
+ priv = E_CAL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ source_list = e_cal_shell_backend_get_source_list (
+ E_CAL_SHELL_BACKEND (shell_backend));
+
+ container = GTK_WIDGET (shell_sidebar);
+
+ widget = gtk_vpaned_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_paned_add1 (GTK_PANED (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_calendar_selector_new (source_list);
+ e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ a11y = gtk_widget_get_accessible (widget);
+ atk_object_set_name (a11y, _("Calendar Selector"));
+ priv->selector = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->paned;
+
+ widget = e_calendar_new ();
+ calitem = E_CALENDAR (widget)->calitem;
+ e_calendar_item_set_days_start_week_sel (calitem, 9);
+ e_calendar_item_set_max_days_sel (calitem, 42);
+ gtk_paned_add2 (GTK_PANED (container), widget);
+ priv->mini_calendar = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ priv->mini_calendar_config =
+ e_mini_calendar_config_new (E_CALENDAR (widget));
+
+ /* Restore the selector state from the last session. */
+
+ selector = E_SOURCE_SELECTOR (priv->selector);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (selector));
+
+ g_signal_connect_swapped (
+ model, "row-changed",
+ G_CALLBACK (cal_shell_sidebar_row_changed_cb),
+ object);
+
+ source = NULL;
+ uid = e_shell_settings_get_string (
+ shell_settings, "cal-primary-calendar");
+ if (uid != NULL)
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ if (source == NULL)
+ source = e_source_list_peek_source_any (source_list);
+ if (source != NULL)
+ e_source_selector_set_primary_selection (selector, source);
+ g_free (uid);
+
+ list = calendar_config_get_calendars_selected ();
+ for (iter = list; iter != NULL; iter = iter->next) {
+ uid = iter->data;
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ g_free (uid);
+
+ if (source == NULL)
+ continue;
+
+ e_source_selector_select_source (selector, source);
+ }
+ g_slist_free (list);
+
+ /* Listen for subsequent changes to the selector. */
+
+ g_signal_connect_swapped (
+ selector, "selection-changed",
+ G_CALLBACK (cal_shell_sidebar_selection_changed_cb),
+ object);
+
+ g_signal_connect_swapped (
+ selector, "primary-selection-changed",
+ G_CALLBACK (cal_shell_sidebar_primary_selection_changed_cb),
+ object);
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (priv->paned);
+ key = "/apps/evolution/calendar/display/date_navigator_vpane_position";
+ gconf_bridge_bind_property_delayed (bridge, key, object, "position");
+}
+
+static void
+cal_shell_sidebar_client_removed (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ESource *source;
+ const gchar *uid;
+
+ client_table = cal_shell_sidebar->priv->client_table;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ g_signal_handlers_disconnect_matched (
+ client, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, cal_shell_sidebar);
+
+ source = e_cal_get_source (client);
+ e_source_selector_unselect_source (selector, source);
+
+ uid = e_source_peek_uid (source);
+ g_hash_table_remove (client_table, uid);
+
+ cal_shell_sidebar_emit_status_message (cal_shell_sidebar, NULL);
+}
+
+static void
+cal_shell_sidebar_class_init (ECalShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ECalShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = cal_shell_sidebar_get_property;
+ object_class->dispose = cal_shell_sidebar_dispose;
+ object_class->finalize = cal_shell_sidebar_finalize;
+ object_class->constructed = cal_shell_sidebar_constructed;
+
+ class->client_removed = cal_shell_sidebar_client_removed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MINI_CALENDAR,
+ g_param_spec_object (
+ "mini-calendar",
+ _("Mini-Calendar Widget"),
+ _("This widget displays a miniature calendar"),
+ E_TYPE_CALENDAR,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTOR,
+ g_param_spec_object (
+ "selector",
+ _("Source Selector Widget"),
+ _("This widget displays groups of calendars"),
+ E_TYPE_SOURCE_SELECTOR,
+ G_PARAM_READABLE));
+
+ signals[CLIENT_ADDED] = g_signal_new (
+ "client-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECalShellSidebarClass, client_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL);
+
+ signals[CLIENT_REMOVED] = g_signal_new (
+ "client-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ECalShellSidebarClass, client_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL);
+
+ signals[STATUS_MESSAGE] = g_signal_new (
+ "status-message",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ECalShellSidebarClass, status_message),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
+
+static void
+cal_shell_sidebar_init (ECalShellSidebar *cal_shell_sidebar)
+{
+ GHashTable *client_table;
+
+ client_table = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ cal_shell_sidebar->priv =
+ E_CAL_SHELL_SIDEBAR_GET_PRIVATE (cal_shell_sidebar);
+
+ cal_shell_sidebar->priv->client_table = client_table;
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_cal_shell_sidebar_get_type (void)
+{
+ return cal_shell_sidebar_type;
+}
+
+void
+e_cal_shell_sidebar_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (ECalShellSidebarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) cal_shell_sidebar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ECalShellSidebar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) cal_shell_sidebar_init,
+ NULL /* value_table */
+ };
+
+ cal_shell_sidebar_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_SIDEBAR,
+ "ECalShellSidebar", &type_info, 0);
+}
+
+GtkWidget *
+e_cal_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_CAL_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+GList *
+e_cal_shell_sidebar_get_clients (ECalShellSidebar *cal_shell_sidebar)
+{
+ GHashTable *client_table;
+
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
+
+ client_table = cal_shell_sidebar->priv->client_table;
+
+ return g_hash_table_get_values (client_table);
+}
+
+ECalendar *
+e_cal_shell_sidebar_get_mini_calendar (ECalShellSidebar *cal_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
+
+ return E_CALENDAR (cal_shell_sidebar->priv->mini_calendar);
+}
+
+ESourceSelector *
+e_cal_shell_sidebar_get_selector (ECalShellSidebar *cal_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar), NULL);
+
+ return E_SOURCE_SELECTOR (cal_shell_sidebar->priv->selector);
+}
+
+void
+e_cal_shell_sidebar_add_source (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ECal *client;
+ const gchar *uid;
+ const gchar *uri;
+ gchar *message;
+
+ g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ client_table = cal_shell_sidebar->priv->client_table;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ uid = e_source_peek_uid (source);
+ client = g_hash_table_lookup (client_table, uid);
+
+ if (client != NULL)
+ return;
+
+ client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_EVENT);
+ g_return_if_fail (client != NULL);
+
+ g_signal_connect_swapped (
+ client, "backend-died",
+ G_CALLBACK (cal_shell_sidebar_backend_died_cb),
+ cal_shell_sidebar);
+
+ g_signal_connect_swapped (
+ client, "backend-error",
+ G_CALLBACK (cal_shell_sidebar_backend_error_cb),
+ cal_shell_sidebar);
+
+ g_hash_table_insert (client_table, g_strdup (uid), client);
+ e_source_selector_select_source (selector, source);
+
+ uri = e_cal_get_uri (client);
+ message = g_strdup_printf (_("Opening calendar at %s"), uri);
+ cal_shell_sidebar_emit_status_message (cal_shell_sidebar, message);
+ g_free (message);
+
+ g_signal_connect_swapped (
+ client, "cal-opened",
+ G_CALLBACK (cal_shell_sidebar_client_opened_cb),
+ cal_shell_sidebar);
+
+ e_cal_open_async (client, FALSE);
+}
+
+void
+e_cal_shell_sidebar_remove_source (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ECal *client;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_CAL_SHELL_SIDEBAR (cal_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ client_table = cal_shell_sidebar->priv->client_table;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ uid = e_source_peek_uid (source);
+ client = g_hash_table_lookup (client_table, uid);
+
+ if (client == NULL)
+ return;
+
+ cal_shell_sidebar_emit_client_removed (cal_shell_sidebar, client);
+}
diff --cc calendar/module/e-cal-shell-sidebar.h
index d4e881a,0000000..c555537
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-sidebar.h
+++ b/calendar/module/e-cal-shell-sidebar.h
@@@ -1,101 -1,0 +1,101 @@@
+/*
+ * e-cal-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_SIDEBAR_H
+#define E_CAL_SHELL_SIDEBAR_H
+
+#include <libecal/e-cal.h>
+#include <libedataserverui/e-source-selector.h>
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+#include <misc/e-calendar.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SHELL_SIDEBAR \
+ (e_cal_shell_sidebar_get_type ())
+#define E_CAL_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebar))
+#define E_CAL_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarClass))
+#define E_IS_CAL_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SHELL_SIDEBAR))
+#define E_IS_CAL_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SHELL_SIDEBAR))
+#define E_CAL_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SHELL_SIDEBAR, ECalShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalShellSidebar ECalShellSidebar;
+typedef struct _ECalShellSidebarClass ECalShellSidebarClass;
+typedef struct _ECalShellSidebarPrivate ECalShellSidebarPrivate;
+
+enum {
+ E_CAL_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
+ E_CAL_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_EMPTY = 1 << 1,
+ E_CAL_SHELL_SIDEBAR_SOURCE_CAN_GO_OFFLINE = 1 << 2,
+ E_CAL_SHELL_SIDEBAR_SOURCE_CAN_DELETE = 1 << 3
+};
+
+struct _ECalShellSidebar {
+ EShellSidebar parent;
+ ECalShellSidebarPrivate *priv;
+};
+
+struct _ECalShellSidebarClass {
+ EShellSidebarClass parent_class;
+
+ /* Signals */
+ void (*client_added) (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client);
+ void (*client_removed) (ECalShellSidebar *cal_shell_sidebar,
+ ECal *client);
+ void (*status_message) (ECalShellSidebar *cal_shell_sidebar,
+ const gchar *status_message);
+};
+
+GType e_cal_shell_sidebar_get_type (void);
+void e_cal_shell_sidebar_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_cal_shell_sidebar_new (EShellView *shell_view);
+GList * e_cal_shell_sidebar_get_clients
+ (ECalShellSidebar *cal_shell_sidebar);
+ECalendar * e_cal_shell_sidebar_get_mini_calendar
+ (ECalShellSidebar *cal_shell_sidebar);
+ESourceSelector *
+ e_cal_shell_sidebar_get_selector
+ (ECalShellSidebar *cal_shell_sidebar);
+void e_cal_shell_sidebar_add_source
+ (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source);
+void e_cal_shell_sidebar_remove_source
+ (ECalShellSidebar *cal_shell_sidebar,
+ ESource *source);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_SIDEBAR_H */
diff --cc calendar/module/e-cal-shell-view-actions.c
index 53898ff,0000000..a5d0dd8
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-actions.c
+++ b/calendar/module/e-cal-shell-view-actions.c
@@@ -1,1173 -1,0 +1,1173 @@@
+/*
+ * e-cal-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-view-private.h"
+
+static void
+action_calendar_copy_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ESourceSelector *selector;
+ ESource *source;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ copy_source_dialog (
+ GTK_WINDOW (shell_window),
+ source, E_CAL_SOURCE_TYPE_EVENT);
+}
+
+static void
+action_calendar_delete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ ECalShellSidebar *cal_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ECalendarView *calendar_view;
+ GnomeCalendarViewType view_type;
+ ECalModel *model;
+ ESourceSelector *selector;
+ ESourceGroup *source_group;
+ ESourceList *source_list;
+ ESource *source;
+ gint response;
+ gchar *uri;
+ GError *error = NULL;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = cal_shell_content->priv->cal_shell_content;
+ view_type = e_cal_shell_content_get_current_view (cal_shell_content);
+ calendar_view = e_cal_shell_content_get_calendar_view (
+ cal_shell_content, view_type);
+ model = e_calendar_view_get_model (calendar_view);
+
+ cal_shell_sidebar = cal_shell_sidebar->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ /* Ask for confirmation. */
+ response = e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-calendar",
+ e_source_peek_name (source));
+ if (response != GTK_RESPONSE_YES)
+ return;
+
+ uri = e_source_get_uri (source);
+ client = e_cal_model_get_client_for_uri (model, uri);
+ if (client == NULL)
+ client = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_EVENT);
+ g_free (uri);
+
+ g_return_if_fail (client != NULL);
+
+ if (!e_cal_remove (client, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (e_source_selector_source_is_selected (selector, source)) {
+ e_cal_shell_sidebar_remove_source (
+ cal_shell_sidebar, source);
+ e_source_selector_unselect_source (selector, source);
+ }
+
+ source_group = e_source_peek_group (source);
+ e_source_group_remove_source (source_group, source);
+
+ source_list = cal_shell_view->priv->source_list;
+ if (!e_source_list_sync (source_list, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+#endif
+}
+
+static void
+action_calendar_go_back_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
- #if 0
++#if 0
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ gnome_calendar_previous (calendar);
+#endif
+}
+
+static void
+action_calendar_go_forward_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ gnome_calendar_next (calendar);
+#endif
+}
+
+static void
+action_calendar_go_today_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ gnome_calendar_goto_today (calendar);
+#endif
+}
+
+static void
+action_calendar_jump_to_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+
+ goto_dialog (calendar);
+#endif
+}
+
+static void
+action_calendar_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ calendar_setup_new_calendar (GTK_WINDOW (shell_window));
+#endif
+}
+
+static void
+action_calendar_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ GtkPrintOperationAction print_action;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+
+ if (gnome_calendar_get_view (calendar) == GNOME_CAL_LIST_VIEW) {
+ ECalListView *list_view;
+ GtkWidget *widget;
+ ETable *table;
+
+ widget = gnome_calendar_get_current_view_widget (calendar);
+ list_view = E_CAL_LIST_VIEW (widget);
+ table = e_table_scrolled_get_table (list_view->table_scrolled);
+ print_table (table, _("Print"), _("Calendar"), action);
+ } else {
+ time_t start;
+
+ gnome_calendar_get_current_time_range (calendar, &start, NULL);
+ print_calendar (calendar, action, start);
+ }
+#endif
+}
+
+static void
+action_calendar_print_preview_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ GtkPrintOperationAction print_action;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
+
+ if (gnome_calendar_get_view (calendar) == GNOME_CAL_LIST_VIEW) {
+ ECalListView *list_view;
+ GtkWidget *widget;
+ ETable *table;
+
+ widget = gnome_calendar_get_current_view_widget (calendar);
+ list_view = E_CAL_LIST_VIEW (widget);
+ table = e_table_scrolled_get_table (list_view->table_scrolled);
+ print_table (table, _("Print"), _("Calendar"), action);
+ } else {
+ time_t start;
+
+ gnome_calendar_get_current_time_range (calendar, &start, NULL);
+ print_calendar (calendar, action, start);
+ }
+#endif
+}
+
+static void
+action_calendar_properties_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellSidebar *cal_shell_sidebar;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESource *source;
+ ESourceSelector *selector;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ calendar_setup_edit_calendar (GTK_WINDOW (shell_window), source);
+#endif
+}
+
+static void
+action_calendar_purge_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_calendar_rename_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ ESourceSelector *selector;
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ e_source_selector_edit_primary_selection (selector);
+}
+
+static void
+action_calendar_select_one_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellSidebar *cal_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *primary;
+ GSList *list, *iter;
+
+ /* XXX ESourceSelector should provide a function for this. */
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ primary = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (primary != NULL);
+
+ list = e_source_selector_get_selection (selector);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+
+ if (source == primary)
+ continue;
+
+ e_source_selector_unselect_source (selector, source);
+ }
+ e_source_selector_free_selection (list);
+
+ e_source_selector_select_source (selector, primary);
+}
+
+static void
+action_calendar_view_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ GnomeCalendarViewType view_type;
+ const gchar *view_id;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ view_type = gtk_radio_action_get_current_value (action);
+
+ switch (view_type) {
+ case GNOME_CAL_DAY_VIEW:
+ view_id = "Day_View";
+ break;
+
+ case GNOME_CAL_WORK_WEEK_VIEW:
+ view_id = "Work_Week_View";
+ break;
+
+ case GNOME_CAL_WEEK_VIEW:
+ view_id = "Week_View";
+ break;
+
+ case GNOME_CAL_MONTH_VIEW:
+ view_id = "Month_View";
+ break;
+
+ case GNOME_CAL_LIST_VIEW:
+ view_id = "List_View";
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+
+ e_shell_view_set_view_id (shell_view, view_id);
+}
+
+static void
+action_event_all_day_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_clipboard_copy_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ e_cal_shell_content_copy_clipboard (cal_shell_content);
+}
+
+static void
+action_event_clipboard_cut_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ e_cal_shell_content_cut_clipboard (cal_shell_content);
+}
+
+static void
+action_event_clipboard_paste_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ e_cal_shell_content_paste_clipboard (cal_shell_content);
+}
+
+static void
+action_event_copy_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_delegate_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_delete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ e_cal_shell_content_delete_selection (cal_shell_content);
+}
+
+static void
+action_event_delete_occurrence_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ e_cal_shell_content_delete_selected_occurrence (cal_shell_content);
+}
+
+static void
+action_event_delete_occurrence_all_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+
+ /* XXX Same as "event-delete". */
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ e_cal_shell_content_delete_selection (cal_shell_content);
+}
+
+static void
+action_event_forward_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_meeting_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_move_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_occurrence_movable_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_open_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ GnomeCalendar *calendar;
+ GtkWidget *widget;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ widget = gnome_calendar_get_current_view_widget (calendar);
+
+ e_calendar_view_open_event (E_CALENDAR_VIEW (widget));
+#endif
+}
+
+static void
+action_event_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_reply_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_reply_all_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_save_as_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_event_schedule_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+static void
+action_gal_save_custom_view_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShellView *shell_view;
+ GalViewInstance *view_instance;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with saving the custom view. */
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ view_instance = e_cal_shell_content_get_view_instance (cal_shell_content);
+ gal_view_instance_save_as (view_instance);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with executing the search. */
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ e_cal_shell_view_execute_search (cal_shell_view);
+}
+
+static void
+action_search_filter_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ ECalShellView *cal_shell_view)
+{
+ e_cal_shell_view_execute_search (cal_shell_view);
+}
+
+static GtkActionEntry calendar_entries[] = {
+
+ { "calendar-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_copy_cb) },
+
+ { "calendar-delete",
+ GTK_STOCK_DELETE,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_delete_cb) },
+
+ { "calendar-go-back",
+ GTK_STOCK_GO_BACK,
+ N_("Previous"),
+ NULL,
+ N_("Go Back"),
+ G_CALLBACK (action_calendar_go_back_cb) },
+
+ { "calendar-go-forward",
+ GTK_STOCK_GO_FORWARD,
+ N_("Next"),
+ NULL,
+ N_("Go Forward"),
+ G_CALLBACK (action_calendar_go_forward_cb) },
+
+ { "calendar-go-today",
+ "go-today",
+ N_("Select _Today"),
+ "<Control>t",
+ N_("Select today"),
+ G_CALLBACK (action_calendar_go_today_cb) },
+
+ { "calendar-jump-to",
+ GTK_STOCK_JUMP_TO,
+ N_("Select _Date"),
+ "<Control>g",
+ N_("Select a specific date"),
+ G_CALLBACK (action_calendar_jump_to_cb) },
+
+ { "calendar-new",
+ "x-office-calendar",
+ N_("_New Calendar"),
+ NULL,
+ N_("Create a new calendar"),
+ G_CALLBACK (action_calendar_new_cb) },
+
+ { "calendar-properties",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_properties_cb) },
+
+ { "calendar-purge",
+ NULL,
+ N_("Purg_e"),
+ "<Control>e",
+ N_("Purge old appointments and meetings"),
+ G_CALLBACK (action_calendar_purge_cb) },
+
+ { "calendar-rename",
+ NULL,
+ N_("_Rename..."),
+ "F2",
+ N_("Rename the selected calendar"),
+ G_CALLBACK (action_calendar_rename_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-clipboard-copy",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy the selection"),
+ G_CALLBACK (action_event_clipboard_copy_cb) },
+
+ { "event-clipboard-cut",
+ GTK_STOCK_CUT,
+ NULL,
+ NULL,
+ N_("Cut the selection"),
+ G_CALLBACK (action_event_clipboard_cut_cb) },
+
+ { "event-clipboard-paste",
+ GTK_STOCK_PASTE,
+ NULL,
+ NULL,
+ N_("Paste the clipboard"),
+ G_CALLBACK (action_event_clipboard_paste_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",
+ GTK_STOCK_DELETE,
+ NULL,
+ NULL,
+ N_("Delete the appointment"),
+ G_CALLBACK (action_event_delete_cb) },
+
+ { "event-delete-occurrence",
+ GTK_STOCK_DELETE,
+ N_("Delete This _Occurrence"),
+ NULL,
+ N_("Delete this occurrence"),
+ G_CALLBACK (action_event_delete_occurrence_cb) },
+
+ { "event-delete-occurrence-all",
+ GTK_STOCK_DELETE,
+ N_("Delete _All Occurrences"),
+ NULL,
+ N_("Delete all occurrences"),
+ G_CALLBACK (action_event_delete_occurrence_all_cb) },
+
+ { "event-all-day-new",
+ NULL,
+ N_("New All Day _Event..."),
+ NULL,
+ N_("Create a new all day event"),
+ G_CALLBACK (action_event_all_day_new_cb) },
+
+ { "event-forward",
+ "mail-forward",
+ N_("_Forward as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_forward_cb) },
+
+ { "event-meeting-new",
+ NULL,
+ N_("New _Meeting..."),
+ NULL,
+ N_("Create a new meeting"),
+ G_CALLBACK (action_event_meeting_new_cb) },
+
+ { "event-move",
+ NULL,
+ N_("Mo_ve to Calendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_move_cb) },
+
+ { "event-new",
+ NULL,
+ N_("New _Appointment..."),
+ NULL,
+ N_("Create a new appointment"),
+ G_CALLBACK (action_event_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",
+ NULL,
+ N_("_Open Appointment"),
+ "<Control>o",
+ N_("View the current appointment"),
+ 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-save-as",
+ GTK_STOCK_SAVE_AS,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_save_as_cb) },
+
+ { "event-schedule",
+ NULL,
+ N_("_Schedule Meeting..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_schedule_cb) },
+
+ /*** Menus ***/
+
+ { "calendar-actions-menu",
+ NULL,
+ N_("_Actions"),
+ 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",
+ NULL,
+ "calendar-delete" },
+
+ { "calendar-popup-go-today",
+ NULL,
+ "calendar-go-today" },
+
+ { "calendar-popup-jump-to",
+ NULL,
+ "calendar-jump-to" },
+
+ { "calendar-popup-properties",
+ NULL,
+ "calendar-properties" },
+
+ { "calendar-popup-rename",
+ NULL,
+ "calendar-rename" },
+
+ { "calendar-popup-select-one",
+ NULL,
+ "calendar-select-one" },
+
+ { "event-popup-clipboard-copy",
+ NULL,
+ "event-clipboard-copy" },
+
+ { "event-popup-clipboard-cut",
+ NULL,
+ "event-clipboard-cut" },
+
+ { "event-popup-clipboard-paste",
+ NULL,
+ "event-clipboard-paste" },
+
+ { "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-all",
+ NULL,
+ "event-delete-occurrence-all" },
+
+ { "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-save-as",
+ NULL,
+ "event-save-as" },
+
+ { "event-popup-schedule",
+ NULL,
+ "event-schedule" }
+};
+
+static GtkRadioActionEntry calendar_view_entries[] = {
+
+ { "calendar-view-day",
+ "view-calendar-day",
+ N_("Day"),
+ NULL,
+ N_("Show one day"),
+ GNOME_CAL_DAY_VIEW },
+
+ { "calendar-view-list",
+ "view-calendar-list",
+ N_("List"),
+ NULL,
+ N_("Show as list"),
+ GNOME_CAL_LIST_VIEW },
+
+ { "calendar-view-month",
+ "view-calendar-month",
+ N_("Month"),
+ NULL,
+ N_("Show one month"),
+ GNOME_CAL_MONTH_VIEW },
+
+ { "calendar-view-week",
+ "view-calendar-week",
+ N_("Week"),
+ NULL,
+ N_("Show one week"),
+ GNOME_CAL_WEEK_VIEW },
+
+ { "calendar-view-workweek",
+ "view-calendar-workweek",
+ N_("Work Week"),
+ NULL,
+ N_("Show one work week"),
+ GNOME_CAL_WORK_WEEK_VIEW }
+};
+
+static GtkRadioActionEntry calendar_filter_entries[] = {
+
+ { "calendar-filter-active-appointments",
+ NULL,
+ N_("Active Appointements"),
+ 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-unmatched",
+ NULL,
+ N_("Unmatched"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ CALENDAR_FILTER_UNMATCHED }
+};
+
+static GtkRadioActionEntry calendar_search_entries[] = {
+
+ { "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",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print this calendar"),
+ G_CALLBACK (action_calendar_print_cb) },
+
+ { "calendar-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ NULL,
+ N_("Preview the calendar to be printed"),
+ G_CALLBACK (action_calendar_print_preview_cb) },
+
+ { "event-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_event_print_cb) }
+};
+
+static EPopupActionEntry lockdown_printing_popup_entries[] = {
+
+ { "event-popup-print",
+ NULL,
+ "event-print" }
+};
+
+void
+e_cal_shell_view_actions_init (ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+ GtkAction *action;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (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_radio_actions (
+ action_group, calendar_view_entries,
+ G_N_ELEMENTS (calendar_view_entries), GNOME_CAL_DAY_VIEW,
+ G_CALLBACK (action_calendar_view_cb), cal_shell_view);
+ gtk_action_group_add_radio_actions (
+ action_group, calendar_search_entries,
+ G_N_ELEMENTS (calendar_search_entries),
+ CALENDAR_SEARCH_SUMMARY_CONTAINS,
+ NULL, NULL);
+
+ /* 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));
+
+ /* Fine tuning. */
+
+ action = ACTION (CALENDAR_GO_TODAY);
+ g_object_set (action, "short-label", _("Today"), NULL);
+
+ action = ACTION (CALENDAR_JUMP_TO);
+ g_object_set (action, "short-label", _("Go To"), NULL);
+
+ action = ACTION (EVENT_DELETE);
+ g_object_set (action, "short-label", _("Delete"), NULL);
+
+ g_signal_connect (
+ ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
+ G_CALLBACK (action_gal_save_custom_view_cb), cal_shell_view);
+
+ g_signal_connect (
+ ACTION (SEARCH_EXECUTE), "activate",
+ G_CALLBACK (action_search_execute_cb), cal_shell_view);
+
+ /* 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);
+}
+
+void
+e_cal_shell_view_update_search_filter (ECalShellView *cal_shell_view)
+{
+ EShellContent *shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GList *list, *iter;
+ GSList *group;
+ gint ii;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_content = e_shell_view_get_shell_content (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);
+
+ /* Add the standard filter actions. */
+ gtk_action_group_add_radio_actions (
+ action_group, calendar_filter_entries,
+ G_N_ELEMENTS (calendar_filter_entries),
+ CALENDAR_FILTER_ANY_CATEGORY,
+ G_CALLBACK (action_search_filter_cb),
+ cal_shell_view);
+
+ /* 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);
+
+ /* Build the category actions. */
+
+ list = e_categories_get_list ();
+ for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+ const gchar *category_name = iter->data;
+ const gchar *filename;
+ GtkAction *action;
+ gchar *action_name;
+
+ 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);
+
+ /* Convert the category icon file to a themed icon name. */
+ filename = e_categories_get_icon_file_for (category_name);
+ if (filename != NULL && *filename != '\0') {
+ gchar *basename;
+ gchar *cp;
+
+ basename = g_path_get_basename (filename);
+
+ /* Lose the file extension. */
+ if ((cp = strrchr (basename, '.')) != NULL)
+ *cp = '\0';
+
+ g_object_set (
+ radio_action, "icon-name", basename, NULL);
+
+ g_free (basename);
+ }
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_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_list_free (list);
+
+ /* Use any action in the group; doesn't matter which. */
+ e_shell_content_set_filter_action (shell_content, radio_action);
+
+ ii = CALENDAR_FILTER_UNMATCHED;
+ e_shell_content_add_filter_separator_after (shell_content, ii);
+
+ ii = CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS;
+ e_shell_content_add_filter_separator_after (shell_content, ii);
+}
diff --cc calendar/module/e-cal-shell-view-actions.h
index 1ad6aa7,0000000..b02906f
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-actions.h
+++ b/calendar/module/e-cal-shell-view-actions.h
@@@ -1,153 -1,0 +1,153 @@@
+/*
+ * e-cal-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_VIEW_ACTIONS_H
+#define E_CAL_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* 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_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_RENAME(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-rename")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_SELECT_ONE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-select-one")
+#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")
+
+/* Event Actions */
+#define E_SHELL_WINDOW_ACTION_EVENT_CLIPBOARD_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-clipboard-copy")
+#define E_SHELL_WINDOW_ACTION_EVENT_CLIPBOARD_CUT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-clipboard-cut")
+#define E_SHELL_WINDOW_ACTION_EVENT_CLIPBOARD_PASTE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-clipboard-paste")
+#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_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-delete-occurrence-all")
+#define E_SHELL_WINDOW_ACTION_EVENT_OPEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "event-open")
+
+/* Memo Pad Actions */
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_CLIPBOARD_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-clipboard-copy")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_CLIPBOARD_CUT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-clipboard-cut")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_CLIPBOARD_PASTE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-clipboard-paste")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_MEMOPAD_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-memopad-delete")
+#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")
+
+/* 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_CLIPBOARD_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-clipboard-copy")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_CLIPBOARD_CUT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-clipboard-cut")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_CLIPBOARD_PASTE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-clipboard-paste")
+#define E_SHELL_WINDOW_ACTION_CALENDAR_TASKPAD_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-taskpad-delete")
+#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")
+
+/* 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_UNMATCHED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "calendar-filter-unmatched")
+#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")
+
+#endif /* E_CAL_SHELL_VIEW_ACTIONS_H */
diff --cc calendar/module/e-cal-shell-view-memopad.c
index d9adf23,0000000..ecee72d
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-memopad.c
+++ b/calendar/module/e-cal-shell-view-memopad.c
@@@ -1,526 -1,0 +1,526 @@@
+/*
+ * e-cal-shell-view-memopad.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-view-private.h"
+
+/* Much of this file is based on e-memo-shell-view-actions.c. */
+
+static void
+action_calendar_memopad_clipboard_copy_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ e_memo_table_copy_clipboard (memo_table);
+}
+
+static void
+action_calendar_memopad_clipboard_cut_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ e_memo_table_cut_clipboard (memo_table);
+}
+
+static void
+action_calendar_memopad_clipboard_paste_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ e_memo_table_paste_clipboard (memo_table);
+}
+
+static void
+action_calendar_memopad_delete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ e_cal_shell_view_memopad_set_status_message (
+ cal_shell_view, _("Deleting selected memos..."), -1.0);
+ e_memo_table_delete_selected (memo_table);
+ e_cal_shell_view_memopad_set_status_message (
+ cal_shell_view, NULL, -1.0);
+}
+
+static void
+action_calendar_memopad_forward_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only forward the first selected memo. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+ itip_send_comp (
+ E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+ comp_data->client, NULL, NULL, NULL, TRUE);
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_memopad_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECal *client;
+ ECalComponent *comp;
+ CompEditor *editor;
+ GSList *list;
+
+ 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);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ client = comp_data->client;
+ editor = memo_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
+ comp = cal_comp_memo_new_with_defaults (client);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+ g_object_unref (client);
+}
+
+static void
+action_calendar_memopad_open_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected memo. */
+ e_cal_shell_view_memopad_open_memo (cal_shell_view, comp_data);
+}
+
+static void
+action_calendar_memopad_open_url_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ icalproperty *prop;
+ const gchar *uri;
+ GSList *list;
+
+ 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);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the URI of the first selected memo. */
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ g_return_if_fail (prop == NULL);
+
+ uri = icalproperty_get_url (prop);
+ e_show_uri (GTK_WINDOW (shell_window), uri);
+}
+
+static void
+action_calendar_memopad_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GtkPrintOperationAction print_action;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only print the first selected memo. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ e_cal_component_set_icalcomponent (comp, clone);
+ print_comp (comp, comp_data->client, print_action);
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_memopad_save_as_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+ gchar *filename;
+ gchar *string;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ filename = e_file_dialog_save (_("Save as..."), NULL);
+ if (filename == NULL)
+ return;
+
+ /* XXX We only save the first selected memo. */
+ string = e_cal_get_component_as_string (
+ comp_data->client, comp_data->icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert memo to a string.");
+ return;
+ }
+
+ e_write_file_uri (filename, string);
+
+ g_free (filename);
+ g_free (string);
+}
+
+static GtkActionEntry calendar_memopad_entries[] = {
+
+ { "calendar-memopad-clipboard-copy",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy selected memo"),
+ G_CALLBACK (action_calendar_memopad_clipboard_copy_cb) },
+
+ { "calendar-memopad-clipboard-cut",
+ GTK_STOCK_CUT,
+ NULL,
+ NULL,
+ N_("Cut selected memo"),
+ G_CALLBACK (action_calendar_memopad_clipboard_cut_cb) },
+
+ { "calendar-memopad-clipboard-paste",
+ GTK_STOCK_PASTE,
+ NULL,
+ NULL,
+ N_("Paste memo from the clipboard"),
+ G_CALLBACK (action_calendar_memopad_clipboard_paste_cb) },
+
+ { "calendar-memopad-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete Memo"),
+ NULL,
+ N_("Delete selected memos"),
+ G_CALLBACK (action_calendar_memopad_delete_cb) },
+
+ { "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",
+ GTK_STOCK_OPEN,
+ N_("_Open Memo"),
+ NULL,
+ 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) },
+
+ { "calendar-memopad-save-as",
+ GTK_STOCK_SAVE_AS,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_memopad_save_as_cb) }
+};
+
+static GtkActionEntry lockdown_printing_entries[] = {
+
+ { "calendar-memopad-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ N_("Print the selected memo"),
+ G_CALLBACK (action_calendar_memopad_print_cb) }
+};
+
+void
+e_cal_shell_view_memopad_actions_init (ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (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);
+
+ /* 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);
+}
+
+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;
+ ETable *table;
+ GtkAction *action;
+ GSList *list, *iter;
+ const gchar *label;
+ gboolean editable = TRUE;
+ 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);
+
+ table = e_memo_table_get_table (memo_table);
+ n_selected = e_table_selected_count (table);
+
+ list = e_memo_table_get_selected (memo_table);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ icalproperty *prop;
+ gboolean read_only;
+
+ e_cal_is_read_only (comp_data->client, &read_only, NULL);
+ editable &= !read_only;
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ has_url |= (prop != NULL);
+ }
+ g_slist_free (list);
+
+ action = ACTION (CALENDAR_MEMOPAD_CLIPBOARD_COPY);
+ sensitive = (n_selected > 0);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_CLIPBOARD_CUT);
+ sensitive = (n_selected > 0) && editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_CLIPBOARD_PASTE);
+ sensitive = editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_DELETE);
+ sensitive = (n_selected > 0) && editable;
+ gtk_action_set_sensitive (action, sensitive);
+ label = ngettext ("Delete Memo", "Delete Memos", n_selected);
+ g_object_set (action, "label", label, NULL);
+
+ action = ACTION (CALENDAR_MEMOPAD_FORWARD);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_OPEN);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_OPEN_URL);
+ sensitive = (n_selected == 1) && has_url;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_PRINT);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_MEMOPAD_SAVE_AS);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+void
+e_cal_shell_view_memopad_open_memo (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ 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);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ if (e_cal_component_has_organizer (comp))
+ flags |= COMP_EDITOR_IS_SHARED;
+
+ if (itip_organizer_is_user (comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = memo_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_cal_shell_view_memopad_set_status_message (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ activity = cal_shell_view->priv->memopad_activity;
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_complete (activity);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new (status_message);
+ e_activity_set_percent (activity, percent);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_primary_text (activity, status_message);
+ }
+
+ cal_shell_view->priv->memopad_activity = activity;
+}
diff --cc calendar/module/e-cal-shell-view-private.c
index aa7b6e3,0000000..f681a2c
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-private.c
+++ b/calendar/module/e-cal-shell-view-private.c
@@@ -1,650 -1,0 +1,650 @@@
+/*
+ * e-cal-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-view-private.h"
+
+#include "calendar/gui/calendar-view-factory.h"
+#include "widgets/menus/gal-view-factory-etable.h"
+
+static void
+cal_shell_view_process_completed_tasks (ECalShellView *cal_shell_view,
+ gboolean config_changed)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ e_calendar_table_process_completed_tasks (
+ task_table, clients, config_changed);
+#endif
+}
+
+static void
+cal_shell_view_config_timezone_changed_cb (GConfClient *client,
+ guint id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ ECalShellView *cal_shell_view = user_data;
+
+ e_cal_shell_view_update_timezone (cal_shell_view);
+}
+
+static struct tm
+cal_shell_view_get_current_time (ECalendarItem *calitem,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ struct icaltimetype tt;
+ icaltimezone *timezone;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ timezone = e_cal_shell_content_get_timezone (cal_shell_content);
+
+ tt = icaltime_from_timet_with_zone (time (NULL), FALSE, timezone);
+
+ return icaltimetype_to_tm (&tt);
+}
+
+static void
+cal_shell_view_mini_calendar_date_range_changed_cb (ECalShellView *cal_shell_view,
+ ECalendarItem *calitem)
+{
+ /* FIXME gnome-calendar.c calls update_query() here. */
+}
-
++
+static void
+cal_shell_view_mini_calendar_selection_changed_cb (ECalShellView *cal_shell_view,
+ ECalendarItem *calitem)
+{
+ /* FIXME */
+}
+
+static void
+cal_shell_view_mini_calendar_scroll_event_cb (ECalShellView *cal_shell_view,
+ GdkEventScroll *event,
+ ECalendar *mini_calendar)
+{
+ ECalendarItem *calitem;
+ GDate start_date, end_date;
+
+ calitem = mini_calendar->calitem;
+ if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
+ return;
+
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ g_date_subtract_months (&start_date, 1);
+ g_date_subtract_months (&end_date, 1);
+ break;
+
+ case GDK_SCROLL_DOWN:
+ g_date_add_months (&start_date, 1);
+ g_date_add_months (&end_date, 1);
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+
+ /* XXX Does ECalendarItem emit a signal for this? If so, maybe
+ * we could move this handler into ECalShellSidebar. */
+ e_calendar_item_set_selection (calitem, &start_date, &end_date);
+
+ cal_shell_view_mini_calendar_date_range_changed_cb (
+ cal_shell_view, calitem);
+}
+
+static gboolean
+cal_shell_view_selector_popup_event_cb (EShellView *shell_view,
+ ESource *primary_source,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/calendar-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+
+ return TRUE;
+}
+
+static void
+cal_shell_view_memopad_popup_event_cb (EShellView *shell_view,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/calendar-memopad-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+}
+
+static void
+cal_shell_view_taskpad_popup_event_cb (EShellView *shell_view,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/calendar-taskpad-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+}
+
+static void
+cal_shell_view_load_view_collection (EShellViewClass *shell_view_class)
+{
+ GalViewCollection *collection;
+ GalViewFactory *factory;
+ ETableSpecification *spec;
+ const gchar *base_dir;
+ gchar *filename;
+
+ collection = shell_view_class->view_collection;
+
+ base_dir = EVOLUTION_ETSPECDIR;
+ spec = e_table_specification_new ();
+ filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
+ if (!e_table_specification_load_from_file (spec, filename))
+ g_critical ("Unable to load ETable specification file "
+ "for calendars");
+ g_free (filename);
+
+ factory = calendar_view_factory_new (GNOME_CAL_DAY_VIEW);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+
+ factory = calendar_view_factory_new (GNOME_CAL_WORK_WEEK_VIEW);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+
+ factory = calendar_view_factory_new (GNOME_CAL_WEEK_VIEW);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+
+ factory = calendar_view_factory_new (GNOME_CAL_MONTH_VIEW);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+
+ factory = gal_view_factory_etable_new (spec);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+ g_object_unref (spec);
+
+ gal_view_collection_load (collection);
+}
+
+static void
+cal_shell_view_notify_view_id_cb (ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ view_instance =
+ e_cal_shell_content_get_view_instance (cal_shell_content);
+ view_id = e_shell_view_get_view_id (E_SHELL_VIEW (cal_shell_view));
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_cal_shell_view_private_init (ECalShellView *cal_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ if (!gal_view_collection_loaded (shell_view_class->view_collection))
+ cal_shell_view_load_view_collection (shell_view_class);
+
+ g_signal_connect (
+ cal_shell_view, "notify::view-id",
+ G_CALLBACK (cal_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_cal_shell_view_private_constructed (ECalShellView *cal_shell_view)
+{
+ ECalShellViewPrivate *priv = cal_shell_view->priv;
+ ECalShellContent *cal_shell_content;
+ ECalShellSidebar *cal_shell_sidebar;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GnomeCalendar *calendar;
+ ECalendar *mini_calendar;
+ EMemoTable *memo_table;
+ ECalendarTable *task_table;
+ ESourceSelector *selector;
+ guint id;
+
+ shell_view = E_SHELL_VIEW (cal_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);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ e_shell_window_add_action_group (shell_window, "calendar");
+ e_shell_window_add_action_group (shell_window, "calendar-filter");
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->cal_shell_backend = g_object_ref (shell_backend);
+ priv->cal_shell_content = g_object_ref (shell_content);
+ priv->cal_shell_sidebar = g_object_ref (shell_sidebar);
+
+ cal_shell_content = E_CAL_SHELL_CONTENT (shell_content);
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ memo_table = e_cal_shell_content_get_memo_table (cal_shell_content);
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ cal_shell_sidebar = E_CAL_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+ mini_calendar = e_cal_shell_sidebar_get_mini_calendar (cal_shell_sidebar);
+
+ e_calendar_item_set_get_time_callback (
+ mini_calendar->calitem, (ECalendarItemGetTimeCallback)
+ cal_shell_view_get_current_time, cal_shell_view, NULL);
+
+#if 0 /* KILL-BONOBO */
+ g_signal_connect_swapped (
+ calendar, "dates-shown-changed",
+ G_CALLBACK (e_cal_shell_view_update_sidebar),
+ cal_shell_view);
+#endif
+
+ g_signal_connect_swapped (
+ mini_calendar, "scroll-event",
+ G_CALLBACK (cal_shell_view_mini_calendar_scroll_event_cb),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ mini_calendar->calitem, "date-range-changed",
+ G_CALLBACK (cal_shell_view_mini_calendar_date_range_changed_cb),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ mini_calendar->calitem, "selection-changed",
+ G_CALLBACK (cal_shell_view_mini_calendar_selection_changed_cb),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "popup-event",
+ G_CALLBACK (cal_shell_view_selector_popup_event_cb),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ memo_table, "popup-event",
+ G_CALLBACK (cal_shell_view_memopad_popup_event_cb),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ memo_table, "status-message",
+ G_CALLBACK (e_cal_shell_view_memopad_set_status_message),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ task_table, "popup-event",
+ G_CALLBACK (cal_shell_view_taskpad_popup_event_cb),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ task_table, "status-message",
+ G_CALLBACK (e_cal_shell_view_taskpad_set_status_message),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ e_memo_table_get_table (memo_table), "selection-change",
+ G_CALLBACK (e_cal_shell_view_memopad_actions_update),
+ cal_shell_view);
+
+ g_signal_connect_swapped (
+ e_calendar_table_get_table (task_table), "selection-change",
+ G_CALLBACK (e_cal_shell_view_taskpad_actions_update),
+ cal_shell_view);
+
+ e_categories_register_change_listener (
+ G_CALLBACK (e_cal_shell_view_update_search_filter),
+ cal_shell_view);
+
+ /* Listen for configuration changes. */
+
+ /* Timezone */
+ id = calendar_config_add_notification_timezone (
+ cal_shell_view_config_timezone_changed_cb, cal_shell_view);
+ priv->notifications = g_list_prepend (
+ priv->notifications, GUINT_TO_POINTER (id));
+
+ e_cal_shell_view_actions_init (cal_shell_view);
+ e_cal_shell_view_update_sidebar (cal_shell_view);
+ e_cal_shell_view_update_search_filter (cal_shell_view);
+ e_cal_shell_view_update_timezone (cal_shell_view);
+}
+
+void
+e_cal_shell_view_private_dispose (ECalShellView *cal_shell_view)
+{
+ ECalShellViewPrivate *priv = cal_shell_view->priv;
+ GList *iter;
+
+ DISPOSE (priv->cal_shell_backend);
+ DISPOSE (priv->cal_shell_content);
+ DISPOSE (priv->cal_shell_sidebar);
+
+ if (priv->calendar_activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_complete (priv->calendar_activity);
+ g_object_unref (priv->calendar_activity);
+ priv->calendar_activity = NULL;
+ }
+
+ if (priv->memopad_activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_complete (priv->memopad_activity);
+ g_object_unref (priv->memopad_activity);
+ priv->memopad_activity = NULL;
+ }
+
+ if (priv->taskpad_activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_complete (priv->taskpad_activity);
+ g_object_unref (priv->taskpad_activity);
+ priv->taskpad_activity = NULL;
+ }
+
+ for (iter = priv->notifications; iter != NULL; iter = iter->next) {
+ guint notification_id = GPOINTER_TO_UINT (iter->data);
+ calendar_config_remove_notification (notification_id);
+ }
+ g_list_free (priv->notifications);
+ priv->notifications = NULL;
+}
+
+void
+e_cal_shell_view_private_finalize (ECalShellView *cal_shell_view)
+{
+ /* XXX Nothing to do? */
+}
+
+void
+e_cal_shell_view_execute_search (ECalShellView *cal_shell_view)
+{
+ /* FIXME */
+}
+
+void
+e_cal_shell_view_open_event (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ icalproperty *prop;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ 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);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
+ if (prop != NULL)
+ flags |= COMP_EDITOR_MEETING;
+
+ if (itip_organizer_is_user (comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (itip_sentby_is_user (comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = event_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_ref (comp);
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_cal_shell_view_set_status_message (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ activity = cal_shell_view->priv->calendar_activity;
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_complete (activity);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new (status_message);
+ e_activity_set_percent (activity, percent);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_primary_text (activity, status_message);
+ }
+
+ cal_shell_view->priv->calendar_activity = activity;
+}
+
+void
+e_cal_shell_view_update_sidebar (ECalShellView *cal_shell_view)
+{
+#if 0 /* KILL-BONOBO */
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ GnomeCalendar *calendar;
+ GnomeCalendarViewType view;
+ time_t start_time, end_time;
+ struct tm start_tm, end_tm;
+ struct icaltimetype start_tt, end_tt;
+ icaltimezone *timezone;
+ gchar buffer[512];
+ gchar end_buffer[512];
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ calendar = e_cal_shell_view_get_calendar (cal_shell_view);
+
+ gnome_calendar_get_visible_time_range (
+ calendar, &start_time, &end_time);
+ timezone = gnome_calendar_get_timezone (calendar);
+ view = gnome_calendar_get_view (calendar);
+
+ start_tt = icaltime_from_timet_with_zone (start_time, FALSE, timezone);
+ start_tm.tm_year = start_tt.year - 1900;
+ start_tm.tm_mon = start_tt.month - 1;
+ start_tm.tm_mday = start_tt.day;
+ start_tm.tm_hour = start_tt.hour;
+ start_tm.tm_min = start_tt.minute;
+ start_tm.tm_sec = start_tt.second;
+ start_tm.tm_isdst = -1;
+ start_tm.tm_wday = time_day_of_week (
+ start_tt.day, start_tt.month - 1, start_tt.year);
+
+ /* Subtract one from end_time so we don't get an extra day. */
+ end_tt = icaltime_from_timet_with_zone (end_time - 1, FALSE, timezone);
+ end_tm.tm_year = end_tt.year - 1900;
+ end_tm.tm_mon = end_tt.month - 1;
+ end_tm.tm_mday = end_tt.day;
+ end_tm.tm_hour = end_tt.hour;
+ end_tm.tm_min = end_tt.minute;
+ end_tm.tm_sec = end_tt.second;
+ end_tm.tm_isdst = -1;
+ end_tm.tm_wday = time_day_of_week (
+ end_tt.day, end_tt.month - 1, end_tt.year);
+
+ switch (view) {
+ case GNOME_CAL_DAY_VIEW:
+ case GNOME_CAL_WORK_WEEK_VIEW:
+ case GNOME_CAL_WEEK_VIEW:
+ if (start_tm.tm_year == end_tm.tm_year &&
+ start_tm.tm_mon == end_tm.tm_mon &&
+ start_tm.tm_mday == end_tm.tm_mday) {
+ e_utf8_strftime (
+ buffer, sizeof (buffer),
+ _("%A %d %b %Y"), &start_tm);
+ } else if (start_tm.tm_year == end_tm.tm_year) {
+ e_utf8_strftime (
+ buffer, sizeof (buffer),
+ _("%a %d %b"), &start_tm);
+ e_utf8_strftime (
+ end_buffer, sizeof (end_buffer),
+ _("%a %d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ } else {
+ e_utf8_strftime (
+ buffer, sizeof (buffer),
+ _("%a %d %b %Y"), &start_tm);
+ e_utf8_strftime (
+ end_buffer, sizeof (end_buffer),
+ _("%a %d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ }
+ break;
+
+ case GNOME_CAL_MONTH_VIEW:
+ case GNOME_CAL_LIST_VIEW:
+ if (start_tm.tm_year == end_tm.tm_year) {
+ if (start_tm.tm_mon == end_tm.tm_mon) {
+ e_utf8_strftime (
+ buffer,
+ sizeof (buffer),
+ "%d", &start_tm);
+ e_utf8_strftime (
+ end_buffer,
+ sizeof (end_buffer),
+ _("%d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ } else {
+ e_utf8_strftime (
+ buffer,
+ sizeof (buffer),
+ _("%d %b"), &start_tm);
+ e_utf8_strftime (
+ end_buffer,
+ sizeof (end_buffer),
+ _("%d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ }
+ } else {
+ e_utf8_strftime (
+ buffer, sizeof (buffer),
+ _("%d %b %Y"), &start_tm);
+ e_utf8_strftime (
+ end_buffer, sizeof (end_buffer),
+ _("%d %b %Y"), &end_tm);
+ strcat (buffer, " - ");
+ strcat (buffer, end_buffer);
+ }
+ break;
+
+ default:
+ g_return_if_reached ();
+ }
+
+ e_shell_sidebar_set_secondary_text (shell_sidebar, buffer);
+#endif
+}
+
+void
+e_cal_shell_view_update_timezone (ECalShellView *cal_shell_view)
+{
+#if 0
+ ECalShellContent *cal_shell_content;
+ ECalShellSidebar *cal_shell_sidebar;
+ GnomeCalendarViewType view_type;
+ ECalendarView *calendar_view;
+ icaltimezone *timezone;
+ GList *clients, *iter;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ view_type = e_cal_shell_content_get_current_view (cal_shell_content);
+ calendar_view = e_cal_shell_content_get_calendar_view (
+ cal_shell_content, view_type);
+
+ cal_shell_sidebar = cal_shell_view->priv->cal_shell_sidebar;
+ clients = e_cal_shell_sidebar_get_clients (cal_shell_sidebar);
+
+ timezone = calendar_config_get_icaltimezone ();
+
+ for (iter = clients; iter != NULL; iter = iter->next) {
+ ECal *client = iter->data;
+
+ if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED)
+ e_cal_set_default_timezone (client, timezone, NULL);
+ }
+
+ e_calendar_view_set_icaltimezone (calendar_view, timezone);
+
+ g_list_free (clients);
+#endif
+}
diff --cc calendar/module/e-cal-shell-view-private.h
index 16a06cc,0000000..8308e0b
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-private.h
+++ b/calendar/module/e-cal-shell-view-private.h
@@@ -1,170 -1,0 +1,170 @@@
+/*
+ * e-cal-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_VIEW_PRIVATE_H
+#define E_CAL_SHELL_VIEW_PRIVATE_H
+
+#include "e-cal-shell-view.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/e-cal-time-util.h>
+#include <libedataserver/e-categories.h>
+#include <libedataserver/e-data-server-util.h>
+
+#include "e-util/e-util.h"
+#include "e-util/e-dialog-utils.h"
+#include "widgets/misc/e-popup-action.h"
+
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-list-view.h"
+#include "calendar/gui/e-cal-model-tasks.h"
+#include "calendar/gui/e-calendar-view.h"
+#include "calendar/gui/gnome-cal.h"
+/*#include "calendar/gui/goto.h"*/
+#include "calendar/gui/print.h"
+#include "calendar/gui/dialogs/copy-source-dialog.h"
+#include "calendar/gui/dialogs/event-editor.h"
+#include "calendar/gui/dialogs/memo-editor.h"
+#include "calendar/gui/dialogs/task-editor.h"
+
+#include "e-cal-shell-backend.h"
+#include "e-cal-shell-content.h"
+#include "e-cal-shell-sidebar.h"
+#include "e-cal-shell-view-actions.h"
+
+#define E_CAL_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* For use in dispose() methods. */
+#define DISPOSE(obj) \
+ G_STMT_START { \
+ if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
+ } G_STMT_END
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "e-calendar-table.etspec"
+
+G_BEGIN_DECLS
+
+/* Filter items are displayed in ascending order.
+ * Non-negative values are reserved for categories. */
+enum {
+ CALENDAR_FILTER_ANY_CATEGORY = -4,
+ CALENDAR_FILTER_UNMATCHED = -3,
+ CALENDAR_FILTER_ACTIVE_APPOINTMENTS = -2,
+ CALENDAR_FILTER_NEXT_7_DAYS_APPOINTMENTS = -1
+};
+
+/* Search items are displayed in ascending order. */
+enum {
+ CALENDAR_SEARCH_SUMMARY_CONTAINS,
+ CALENDAR_SEARCH_DESCRIPTION_CONTAINS,
+ CALENDAR_SEARCH_ANY_FIELD_CONTAINS
+};
+
+struct _ECalShellViewPrivate {
+
+ /* These are just for convenience. */
+ ECalShellBackend *cal_shell_backend;
+ ECalShellContent *cal_shell_content;
+ ECalShellSidebar *cal_shell_sidebar;
+
+ /* The last time explicitly selected by the user. */
+ time_t base_view_time;
+
+ EActivity *calendar_activity;
+ EActivity *memopad_activity;
+ EActivity *taskpad_activity;
+
+ /* GConf notification IDs */
+ GList *notifications;
+};
+
+void e_cal_shell_view_private_init
+ (ECalShellView *cal_shell_view,
+ EShellViewClass *shell_view_class);
+void e_cal_shell_view_private_constructed
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_private_dispose
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_private_finalize
+ (ECalShellView *cal_shell_view);
+
+/* Private Utilities */
+
+void e_cal_shell_view_actions_init
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_execute_search
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_open_event
+ (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data);
+void e_cal_shell_view_set_status_message
+ (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+void e_cal_shell_view_update_sidebar
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_update_search_filter
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_update_timezone
+ (ECalShellView *cal_shell_view);
+
+/* Memo Pad Utilities */
+
+void e_cal_shell_view_memopad_actions_init
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_memopad_actions_update
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_memopad_open_memo
+ (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data);
+void e_cal_shell_view_memopad_set_status_message
+ (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+
+/* Task Pad Utilities */
+
+void e_cal_shell_view_taskpad_actions_init
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_taskpad_actions_update
+ (ECalShellView *cal_shell_view);
+void e_cal_shell_view_taskpad_open_task
+ (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data);
+void e_cal_shell_view_taskpad_set_status_message
+ (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_VIEW_PRIVATE_H */
diff --cc calendar/module/e-cal-shell-view-taskpad.c
index 6d00eb5,0000000..bdd136b
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view-taskpad.c
+++ b/calendar/module/e-cal-shell-view-taskpad.c
@@@ -1,654 -1,0 +1,654 @@@
+/*
+ * e-cal-shell-view-taskpad.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-view-private.h"
+
+/* 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)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected task. */
+ e_cal_shell_view_taskpad_open_task (cal_shell_view, comp_data);
+
+ /* FIXME Need to actually assign the task. */
+}
+
+static void
+action_calendar_taskpad_clipboard_copy_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ e_calendar_table_copy_clipboard (task_table);
+}
+
+static void
+action_calendar_taskpad_clipboard_cut_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ e_calendar_table_cut_clipboard (task_table);
+}
+
+static void
+action_calendar_taskpad_clipboard_paste_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ e_calendar_table_paste_clipboard (task_table);
+}
+
+static void
+action_calendar_taskpad_delete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ e_cal_shell_view_taskpad_set_status_message (
+ cal_shell_view, _("Deleting selected tasks..."), -1.0);
+ e_calendar_table_delete_selected (task_table);
+ e_cal_shell_view_taskpad_set_status_message (
+ cal_shell_view, NULL, -1.0);
+}
+
+static void
+action_calendar_taskpad_forward_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only forward the first selected task. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+ itip_send_comp (
+ E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+ comp_data->client, NULL, NULL, NULL, TRUE);
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_taskpad_mark_complete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModel *model;
+ GSList *list, *iter;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+ list = e_calendar_table_get_selected (task_table);
+ model = e_calendar_table_get_model (task_table);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ e_cal_model_tasks_mark_comp_complete (
+ E_CAL_MODEL_TASKS (model), comp_data);
+ }
+
+ g_slist_free (list);
+}
+
+static void
+action_calendar_taskpad_mark_incomplete_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModel *model;
+ GSList *list, *iter;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+ list = e_calendar_table_get_selected (task_table);
+ model = e_calendar_table_get_model (task_table);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ e_cal_model_tasks_mark_comp_incomplete (
+ E_CAL_MODEL_TASKS (model), comp_data);
+ }
+
+ g_slist_free (list);
+}
+
+static void
+action_calendar_taskpad_new_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ ECal *client;
+ ECalComponent *comp;
+ CompEditor *editor;
+ GSList *list;
+
+ 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);
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ client = comp_data->client;
+ editor = task_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
+ comp = cal_comp_task_new_with_defaults (client);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+ g_object_unref (client);
+}
+
+static void
+action_calendar_taskpad_open_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected task. */
+ e_cal_shell_view_taskpad_open_task (cal_shell_view, comp_data);
+}
+
+static void
+action_calendar_taskpad_open_url_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ icalproperty *prop;
+ const gchar *uri;
+ GSList *list;
+
+ 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);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+
+ /* XXX We only open the URI of the first selected task. */
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ g_return_if_fail (prop == NULL);
+
+ uri = icalproperty_get_url (prop);
+ e_show_uri (GTK_WINDOW (shell_window), uri);
+}
+
+static void
+action_calendar_taskpad_print_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GtkPrintOperationAction print_action;
+ GSList *list;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only print the first selected task. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ e_cal_component_set_icalcomponent (comp, clone);
+ print_comp (comp, comp_data->client, print_action);
+ g_object_unref (comp);
+}
+
+static void
+action_calendar_taskpad_save_as_cb (GtkAction *action,
+ ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+ gchar *filename;
+ gchar *string;
+
+ cal_shell_content = cal_shell_view->priv->cal_shell_content;
+ task_table = e_cal_shell_content_get_task_table (cal_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ filename = e_file_dialog_save (_("Save as..."), NULL);
+ if (filename == NULL)
+ return;
+
+ string = e_cal_get_component_as_string (
+ comp_data->client, comp_data->icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert task to a string");
+ return;
+ }
+
+ e_write_file_uri (filename, string);
+
+ g_free (filename);
+ g_free (string);
+}
+
+static GtkActionEntry calendar_taskpad_entries[] = {
+
+ { "calendar-taskpad-assign",
+ NULL,
+ N_("_Assign Task"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_taskpad_assign_cb) },
+
+ { "calendar-taskpad-clipboard-copy",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy selected tasks"),
+ G_CALLBACK (action_calendar_taskpad_clipboard_copy_cb) },
+
+ { "calendar-taskpad-clipboard-cut",
+ GTK_STOCK_CUT,
+ NULL,
+ NULL,
+ N_("Cut selected tasks"),
+ G_CALLBACK (action_calendar_taskpad_clipboard_cut_cb) },
+
+ { "calendar-taskpad-clipboard-paste",
+ GTK_STOCK_PASTE,
+ NULL,
+ NULL,
+ N_("Paste tasks from the clipboard"),
+ G_CALLBACK (action_calendar_taskpad_clipboard_paste_cb) },
+
+ { "calendar-taskpad-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete Task"),
+ NULL,
+ N_("Delete selected tasks"),
+ G_CALLBACK (action_calendar_taskpad_delete_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_("_Mar_k 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",
+ GTK_STOCK_OPEN,
+ N_("_Open Task"),
+ NULL,
+ 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) },
+
+ { "calendar-taskpad-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_calendar_taskpad_save_as_cb) }
+};
+
+static GtkActionEntry lockdown_printing_entries[] = {
+
+ { "calendar-taskpad-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ N_("Print the selected task"),
+ G_CALLBACK (action_calendar_taskpad_print_cb) }
+};
+
+void
+e_cal_shell_view_taskpad_actions_init (ECalShellView *cal_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_window = e_shell_view_get_shell_window (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);
+
+ /* 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);
+}
+
+void
+e_cal_shell_view_taskpad_actions_update (ECalShellView *cal_shell_view)
+{
+ ECalShellContent *cal_shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ECalendarTable *task_table;
+ ETable *table;
+ GtkAction *action;
+ GSList *list, *iter;
+ const gchar *label;
+ gboolean assignable = TRUE;
+ gboolean editable = TRUE;
+ gboolean has_url = FALSE;
+ gboolean sensitive;
+ gint n_selected;
+ gint n_complete = 0;
+ 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);
+
+ table = e_calendar_table_get_table (task_table);
+ n_selected = e_table_selected_count (table);
+
+ list = e_calendar_table_get_selected (task_table);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ icalproperty *prop;
+ const gchar *cap;
+ gboolean read_only;
+
+ e_cal_is_read_only (comp_data->client, &read_only, NULL);
+ editable &= !read_only;
+
+ cap = CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT;
+ if (e_cal_get_static_capability (comp_data->client, cap))
+ assignable = FALSE;
+
+ cap = CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK;
+ if (e_cal_get_static_capability (comp_data->client, cap))
+ assignable = FALSE;
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ has_url |= (prop != NULL);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
+ if (prop != NULL)
+ n_complete++;
+ else
+ n_incomplete++;
+ }
+ g_slist_free (list);
+
+ action = ACTION (CALENDAR_TASKPAD_ASSIGN);
+ sensitive = (n_selected == 1) && editable && assignable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_CLIPBOARD_COPY);
+ sensitive = (n_selected > 0);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_CLIPBOARD_CUT);
+ sensitive = (n_selected > 0) && editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_CLIPBOARD_PASTE);
+ sensitive = editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_DELETE);
+ sensitive = (n_selected > 0) && editable;
+ gtk_action_set_sensitive (action, sensitive);
+ label = ngettext ("Delete Task", "Delete Tasks", n_selected);
+ g_object_set (action, "label", label, NULL);
+
+ action = ACTION (CALENDAR_TASKPAD_FORWARD);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_MARK_COMPLETE);
+ sensitive = (n_selected > 0) && editable && (n_incomplete > 0);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_MARK_INCOMPLETE);
+ sensitive = (n_selected > 0) && editable && (n_complete > 0);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_OPEN);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_OPEN_URL);
+ sensitive = (n_selected == 1) && has_url;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_PRINT);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_TASKPAD_SAVE_AS);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+void
+e_cal_shell_view_taskpad_open_task (ECalShellView *cal_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ icalproperty *prop;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ 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);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
+ if (prop != NULL)
+ flags |= COMP_EDITOR_IS_ASSIGNED;
+
+ if (itip_organizer_is_user (comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = task_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_ref (comp);
+
+ if (flags & COMP_EDITOR_IS_ASSIGNED)
+ task_editor_show_assignment (TASK_EDITOR (editor));
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_cal_shell_view_taskpad_set_status_message (ECalShellView *cal_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view));
+
+ shell_view = E_SHELL_VIEW (cal_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ activity = cal_shell_view->priv->taskpad_activity;
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_complete (activity);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new (status_message);
+ e_activity_set_percent (activity, percent);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_primary_text (activity, status_message);
+ }
+
+ cal_shell_view->priv->taskpad_activity = activity;
+}
diff --cc calendar/module/e-cal-shell-view.c
index 593b955,0000000..5bf1c74
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view.c
+++ b/calendar/module/e-cal-shell-view.c
@@@ -1,226 -1,0 +1,226 @@@
+/*
+ * e-cal-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-view-private.h"
+
+static gpointer parent_class;
+static GType cal_shell_view_type;
+
+static void
+cal_shell_view_dispose (GObject *object)
+{
+ e_cal_shell_view_private_dispose (E_CAL_SHELL_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+cal_shell_view_finalize (GObject *object)
+{
+ e_cal_shell_view_private_finalize (E_CAL_SHELL_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+cal_shell_view_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ e_cal_shell_view_private_constructed (E_CAL_SHELL_VIEW (object));
+}
+
+static void
+cal_shell_view_update_actions (EShellView *shell_view)
+{
+#if 0
+ ECalShellViewPrivate *priv;
+ ECalShellContent *cal_shell_content;
+ ECalShellSidebar *cal_shell_sidebar;
+ EShellWindow *shell_window;
+ GnomeCalendar *calendar;
+ ECalModel *model;
+ ESourceSelector *selector;
+ ESource *source;
+ GtkAction *action;
+ GtkWidget *widget;
+ GList *list, *iter;
+ const gchar *uri = NULL;
+ gboolean user_created_source;
+ gboolean editable = TRUE;
+ gboolean recurring = FALSE;
+ gboolean sensitive;
+ gint n_selected;
+
+ priv = E_CAL_SHELL_VIEW_GET_PRIVATE (shell_view);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ cal_shell_content = priv->cal_shell_content;
+ calendar = e_cal_shell_content_get_calendar (cal_shell_content);
+ widget = gnome_calendar_get_current_view_widget (calendar);
+ model = e_calendar_view_get_model (E_CALENDAR_VIEW (widget));
+
+ cal_shell_sidebar = priv->cal_shell_sidebar;
+ selector = e_cal_shell_sidebar_get_selector (cal_shell_sidebar);
+
+ list = e_calendar_view_get_selected_events (E_CALENDAR_VIEW (widget));
+ n_selected = g_list_length (list);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ gboolean read_only;
+
+ e_cal_is_read_only (comp_data->client, &read_only, NULL);
+ editable &= !read_only;
+
+ if (e_cal_util_component_has_recurrences (comp_data->icalcomp))
+ recurring |= TRUE;
+ else if (e_cal_util_component_is_instance (comp_data->icalcomp))
+ recurring |= TRUE;
+ }
+
+ source = e_source_selector_peek_primary_selection (selector);
+ if (source != NULL)
+ uri = e_source_peek_relative_uri (source);
+ user_created_source = (uri != NULL && strcmp (uri, "system") != 0);
+
+ action = ACTION (CALENDAR_COPY);
+ sensitive = (source != NULL);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_DELETE);
+ sensitive = user_created_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_PROPERTIES);
+ sensitive = (source != NULL);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (CALENDAR_RENAME);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_CLIPBOARD_COPY);
+ sensitive = (n_selected > 0);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_CLIPBOARD_CUT);
+ sensitive = (n_selected > 0) && editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_CLIPBOARD_PASTE);
+ sensitive = editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_DELETE);
+ sensitive = (n_selected > 0) && editable && !recurring;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_DELETE_OCCURRENCE);
+ sensitive = (n_selected > 0) && editable && recurring;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_DELETE_OCCURRENCE_ALL);
+ sensitive = (n_selected > 0) && editable && recurring;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (EVENT_OPEN);
+ sensitive = (n_selected == 1);
+ gtk_action_set_sensitive (action, sensitive);
+#endif
+}
+
+static void
+cal_shell_view_class_init (ECalShellViewClass *class,
+ GTypeModule *type_module)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ECalShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = cal_shell_view_dispose;
+ object_class->finalize = cal_shell_view_finalize;
+ object_class->constructed = cal_shell_view_constructed;
+
+ 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_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_shell_sidebar_new;
+ shell_view_class->update_actions = cal_shell_view_update_actions;
+}
+
+static void
+cal_shell_view_init (ECalShellView *cal_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ cal_shell_view->priv =
+ E_CAL_SHELL_VIEW_GET_PRIVATE (cal_shell_view);
+
+ e_cal_shell_view_private_init (cal_shell_view, shell_view_class);
+}
+
+GType
+e_cal_shell_view_get_type (void)
+{
+ return cal_shell_view_type;
+}
+
+void
+e_cal_shell_view_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (ECalShellViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) cal_shell_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ type_module,
+ sizeof (ECalShellView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) cal_shell_view_init,
+ NULL /* value_table */
+ };
+
+ cal_shell_view_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_VIEW,
+ "ECalShellView", &type_info, 0);
+}
+
+GnomeCalendar *
+e_cal_shell_view_get_calendar (ECalShellView *cal_shell_view)
+{
+ g_return_val_if_fail (E_IS_CAL_SHELL_VIEW (cal_shell_view), NULL);
+
+ /* FIXME */
+ return NULL;
+}
diff --cc calendar/module/e-cal-shell-view.h
index 42fddec,0000000..67fa152
mode 100644,000000..100644
--- a/calendar/module/e-cal-shell-view.h
+++ b/calendar/module/e-cal-shell-view.h
@@@ -1,69 -1,0 +1,69 @@@
+/*
+ * e-cal-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_CAL_SHELL_VIEW_H
+#define E_CAL_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+#include <calendar/gui/gnome-cal.h>
+#include <libedataserver/e-source-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CAL_SHELL_VIEW \
+ (e_cal_shell_view_get_type ())
+#define E_CAL_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellView))
+#define E_CAL_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_CAL_SHELL_VIEW, ECalShellViewClass))
+#define E_IS_CAL_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_CAL_SHELL_VIEW))
+#define E_IS_CAL_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_CAL_SHELL_VIEW))
+#define E_CAL_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_CAL_SHELL_VIEW, ECalShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECalShellView ECalShellView;
+typedef struct _ECalShellViewClass ECalShellViewClass;
+typedef struct _ECalShellViewPrivate ECalShellViewPrivate;
+
+struct _ECalShellView {
+ EShellView parent;
+ ECalShellViewPrivate *priv;
+};
+
+struct _ECalShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_cal_shell_view_get_type (void);
+void e_cal_shell_view_register_type (GTypeModule *type_module);
+GnomeCalendar * e_cal_shell_view_get_calendar (ECalShellView *cal_shell_view);
+
+G_END_DECLS
+
+#endif /* E_CAL_SHELL_VIEW_H */
diff --cc calendar/module/e-memo-shell-backend.c
index f910bcf,0000000..d2734e0
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-backend.c
+++ b/calendar/module/e-memo-shell-backend.c
@@@ -1,613 -1,0 +1,613 @@@
+/*
+ * e-memo-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-memo-shell-backend.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/e-cal.h>
+#include <libedataserver/e-url.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-source-group.h>
+
+#include "shell/e-shell.h"
+#include "shell/e-shell-backend.h"
+#include "shell/e-shell-window.h"
+
+#include "calendar/common/authentication.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/dialogs/calendar-setup.h"
+#include "calendar/gui/dialogs/memo-editor.h"
+
+#include "e-memo-shell-migrate.h"
+#include "e-memo-shell-view.h"
+
+#define E_MEMO_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendPrivate))
+
+#define WEB_BASE_URI "webcal://"
+#define PERSONAL_RELATIVE_URI "system"
+
+struct _EMemoShellBackendPrivate {
+ ESourceList *source_list;
+};
+
+enum {
+ PROP_0,
+ PROP_SOURCE_LIST
+};
+
+static gpointer parent_class;
+static GType memo_shell_backend_type;
+
+static void
+memo_module_ensure_sources (EShellBackend *shell_backend)
+{
+ /* XXX This is basically the same algorithm across all modules.
+ * Maybe we could somehow integrate this into EShellBackend? */
+
+ EMemoShellBackendPrivate *priv;
+ ESourceGroup *on_this_computer;
+ ESourceGroup *on_the_web;
+ ESource *personal;
+ GSList *groups, *iter;
+ const gchar *data_dir;
+ const gchar *name;
+ gchar *base_uri;
+ gchar *filename;
+
+ on_this_computer = NULL;
+ on_the_web = NULL;
+ personal = NULL;
+
+ priv = E_MEMO_SHELL_BACKEND_GET_PRIVATE (shell_backend);
+
+ if (!e_cal_get_sources (&priv->source_list, E_CAL_SOURCE_TYPE_JOURNAL, NULL)) {
+ g_warning ("Could not get memo sources from GConf!");
+ return;
+ }
+
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ filename = g_build_filename (data_dir, "local", NULL);
+ base_uri = g_filename_to_uri (filename, NULL, NULL);
+ g_free (filename);
+
+ groups = e_source_list_peek_groups (priv->source_list);
+ for (iter = groups; iter != NULL; iter = iter->next) {
+ ESourceGroup *source_group = iter->data;
+ const gchar *group_base_uri;
+
+ group_base_uri = e_source_group_peek_base_uri (source_group);
+
+ /* Compare only "file://" part. If the user's home
+ * changes, we do not want to create another group. */
+ if (on_this_computer == NULL &&
+ strncmp (base_uri, group_base_uri, 7) == 0)
+ on_this_computer = source_group;
+
+ else if (on_the_web == NULL &&
+ strcmp (WEB_BASE_URI, group_base_uri) == 0)
+ on_the_web = source_group;
+ }
+
+ name = _("On This Computer");
+
+ if (on_this_computer != NULL) {
+ GSList *sources;
+ const gchar *group_base_uri;
+
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (on_this_computer, name);
+
+ sources = e_source_group_peek_sources (on_this_computer);
+ group_base_uri = e_source_group_peek_base_uri (on_this_computer);
+
+ /* Make sure this group includes a "Personal" source. */
+ for (iter = sources; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (relative_uri == NULL)
+ continue;
+
+ if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0)
+ continue;
+
+ personal = source;
+ break;
+ }
+
+ /* Make sure we have the correct base URI. This can
+ * change when the user's home directory changes. */
+ if (strcmp (base_uri, group_base_uri) != 0) {
+ e_source_group_set_base_uri (
+ on_this_computer, base_uri);
+
+ /* XXX We shouldn't need this sync call here as
+ * set_base_uri() results in synching to GConf,
+ * but that happens in an idle loop and too late
+ * to prevent the user from seeing a "Cannot
+ * Open ... because of invalid URI" error. */
+ e_source_list_sync (priv->source_list, NULL);
+ }
+
+ } else {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, base_uri);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ }
+
+ name = _("Personal");
+
+ if (personal == NULL) {
+ ESource *source;
+ GSList *selected;
+ gchar *primary;
+
+ source = e_source_new (name, PERSONAL_RELATIVE_URI);
+ e_source_group_add_source (on_this_computer, source, -1);
+ g_object_unref (source);
+
+ primary = calendar_config_get_primary_memos ();
+ selected = calendar_config_get_memos_selected ();
+
+ if (primary == NULL && selected == NULL) {
+ const gchar *uid;
+
+ uid = e_source_peek_uid (source);
+ selected = g_slist_prepend (NULL, g_strdup (uid));
+
+ calendar_config_set_primary_memos (uid);
+ calendar_config_set_memos_selected (selected);
+ }
+
+ g_slist_foreach (selected, (GFunc) g_free, NULL);
+ g_slist_free (selected);
+ g_free (primary);
+ } else {
+ /* Force the source name to the current locale. */
+ e_source_set_name (personal, name);
+ }
+
+ name = _("On The Web");
+
+ if (on_the_web == NULL) {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, WEB_BASE_URI);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ } else {
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (on_the_web, name);
+ }
+
+ g_free (base_uri);
+}
+
+static void
+memo_module_cal_opened_cb (ECal *cal,
+ ECalendarStatus status,
+ GtkAction *action)
+{
+ EShell *shell;
+ ECalComponent *comp;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ const gchar *action_name;
+
+ /* FIXME Pass this in. */
+ shell = e_shell_get_default ();
+
+ /* XXX Handle errors better. */
+ if (status != E_CALENDAR_STATUS_OK)
+ return;
+
+ action_name = gtk_action_get_name (action);
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+ if (strcmp (action_name, "memo-shared-new") == 0) {
+ flags |= COMP_EDITOR_IS_SHARED;
+ flags |= COMP_EDITOR_USER_ORG;
+ }
+
+ editor = memo_editor_new (cal, shell, flags);
+ comp = cal_comp_memo_new_with_defaults (cal);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+ g_object_unref (cal);
+}
+
+static void
+action_memo_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ ECal *cal = NULL;
+ ECalSourceType source_type;
+ ESourceList *source_list;
+ gchar *uid;
+
+ /* This callback is used for both memos and shared memos. */
+
+ source_type = E_CAL_SOURCE_TYPE_JOURNAL;
+
+ if (!e_cal_get_sources (&source_list, source_type, NULL)) {
+ g_warning ("Could not get memo sources from GConf!");
+ return;
+ }
+
+ uid = calendar_config_get_primary_memos ();
+
+ if (uid != NULL) {
+ ESource *source;
+
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ if (source != NULL)
+ cal = auth_new_cal_from_source (source, source_type);
+ g_free (uid);
+ }
+
+ if (cal == NULL)
+ cal = auth_new_cal_from_default (source_type);
+
+ g_return_if_fail (cal != NULL);
+
+ g_signal_connect (
+ cal, "cal-opened",
+ G_CALLBACK (memo_module_cal_opened_cb), action);
+
+ e_cal_open_async (cal, FALSE);
+}
+
+static void
+action_memo_list_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ calendar_setup_new_memo_list (GTK_WINDOW (shell_window));
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "memo-new",
+ "stock_insert-note",
+ NC_("New", "Mem_o"),
+ "<Shift><Control>o",
+ N_("Create a new memo"),
+ G_CALLBACK (action_memo_new_cb) },
+
+ { "memo-shared-new",
+ "stock_insert-note",
+ N_("_Shared Memo"),
+ "<Shift><Control>h",
+ 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
+memo_module_handle_uri_cb (EShellBackend *shell_backend,
+ const gchar *uri)
+{
+ EShell *shell;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECal *client;
+ ECalComponent *comp;
+ ESource *source;
+ ESourceList *source_list;
+ ECalSourceType source_type;
+ EUri *euri;
+ icalcomponent *icalcomp;
+ const gchar *cp;
+ gchar *source_uid = NULL;
+ gchar *comp_uid = NULL;
+ gchar *comp_rid = NULL;
+ gboolean handled = FALSE;
+ GError *error = NULL;
+
+ source_type = E_CAL_SOURCE_TYPE_JOURNAL;
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ if (strncmp (uri, "memo:", 5) != 0)
+ return FALSE;
+
+ euri = e_uri_new (uri);
+ cp = euri->query;
+ if (cp == NULL)
+ goto exit;
+
+ while (*cp != '\0') {
+ gchar *header;
+ gchar *content;
+ gsize header_len;
+ gsize content_len;
+
+ header_len = strcspn (cp, "=&");
+
+ /* If it's malformed, give up. */
+ if (cp[header_len] != '=')
+ break;
+
+ header = (gchar *) cp;
+ header[header_len] = '\0';
+ cp += header_len + 1;
+
+ content_len = strcspn (cp, "&");
+
+ content = g_strndup (cp, content_len);
+ if (g_ascii_strcasecmp (header, "source-uid") == 0)
+ source_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
+ comp_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
+ comp_rid = g_strdup (content);
+ g_free (content);
+
+ cp += content_len;
+ if (*cp == '&') {
+ cp++;
+ if (strcmp (cp, "amp;") == 0)
+ cp += 4;
+ }
+ }
+
+ if (source_uid == NULL || comp_uid == NULL)
+ goto exit;
+
+ /* URI is valid, so consider it handled. Whether
+ * we successfully open it is another matter... */
+ handled = TRUE;
+
+ if (!e_cal_get_sources (&source_list, source_type, NULL)) {
+ g_printerr ("Could not get memo sources from GConf!\n");
+ goto exit;
+ }
+
+ source = e_source_list_peek_source_by_uid (source_list, source_uid);
+ if (source == NULL) {
+ g_printerr ("No source for UID `%s'\n", source_uid);
+ g_object_unref (source_list);
+ goto exit;
+ }
+
+ client = auth_new_cal_from_source (source, source_type);
+ if (client == NULL || !e_cal_open (client, TRUE, &error)) {
+ g_printerr ("%s\n", error->message);
+ g_object_unref (source_list);
+ g_error_free (error);
+ goto exit;
+ }
+
+ /* XXX Copied from e_memo_shell_view_open_memo().
+ * Clearly a new utility function is needed. */
+
+ editor = comp_editor_find_instance (comp_uid);
+
+ if (editor != NULL)
+ goto present;
+
+ if (!e_cal_get_object (client, comp_uid, comp_rid, &icalcomp, &error)) {
+ g_printerr ("%s\n", error->message);
+ g_object_unref (source_list);
+ g_error_free (error);
+ goto exit;
+ }
+
+ comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (comp, icalcomp);
+
+ if (e_cal_component_has_organizer (comp))
+ flags |= COMP_EDITOR_IS_SHARED;
+
+ if (itip_organizer_is_user (comp, client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = memo_editor_new (client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+present:
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (source_list);
+ g_object_unref (client);
+
+exit:
+ g_free (source_uid);
+ g_free (comp_uid);
+ g_free (comp_rid);
+
+ e_uri_free (euri);
+
+ return handled;
+}
+
+static void
+memo_module_window_created_cb (EShellBackend *shell_backend,
+ GtkWindow *window)
+{
+ const gchar *module_name;
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ module_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), module_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), module_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+}
+
+static void
+memo_shell_backend_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE_LIST:
+ g_value_set_object (
+ value,
+ e_memo_shell_backend_get_source_list (
+ E_MEMO_SHELL_BACKEND (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_shell_backend_dispose (GObject *object)
+{
+ EMemoShellBackendPrivate *priv;
+
+ priv = E_MEMO_SHELL_BACKEND_GET_PRIVATE (object);
+
+ if (priv->source_list != NULL) {
+ g_object_unref (priv->source_list);
+ priv->source_list = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+memo_shell_backend_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ memo_module_ensure_sources (shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "handle-uri",
+ G_CALLBACK (memo_module_handle_uri_cb), shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-created",
+ G_CALLBACK (memo_module_window_created_cb), shell_backend);
+}
+
+static void
+memo_shell_backend_class_init (EMemoShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMemoShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = memo_shell_backend_get_property;
+ object_class->dispose = memo_shell_backend_dispose;
+ object_class->constructed = memo_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_MEMO_SHELL_VIEW;
+ shell_backend_class->name = "memos";
+ shell_backend_class->aliases = "";
+ shell_backend_class->schemes = "memo";
+ shell_backend_class->sort_order = 500;
+ shell_backend_class->start = NULL;
+ shell_backend_class->is_busy = NULL;
+ shell_backend_class->shutdown = NULL;
+ shell_backend_class->migrate = e_memo_shell_backend_migrate;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SOURCE_LIST,
+ g_param_spec_object (
+ "source-list",
+ _("Source List"),
+ _("The registry of memo lists"),
+ E_TYPE_SOURCE_LIST,
+ G_PARAM_READABLE));
+}
+
+static void
+memo_shell_backend_init (EMemoShellBackend *memo_shell_backend)
+{
+ memo_shell_backend->priv =
+ E_MEMO_SHELL_BACKEND_GET_PRIVATE (memo_shell_backend);
+}
+
+GType
+e_memo_shell_backend_get_type (void)
+{
+ return memo_shell_backend_type;
+}
+
+void
+e_memo_shell_backend_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EMemoShellBackendClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) memo_shell_backend_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMemoShellBackend),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) memo_shell_backend_init,
+ NULL /* value_table */
+ };
+
+ memo_shell_backend_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_BACKEND,
+ "EMemoShellBackend", &type_info, 0);
+}
+
+ESourceList *
+e_memo_shell_backend_get_source_list (EMemoShellBackend *memo_shell_backend)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_BACKEND (memo_shell_backend), NULL);
+
+ return memo_shell_backend->priv->source_list;
+}
diff --cc calendar/module/e-memo-shell-backend.h
index 0ffc222,0000000..37fe41a
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-backend.h
+++ b/calendar/module/e-memo-shell-backend.h
@@@ -1,70 -1,0 +1,70 @@@
+/*
+ * e-memo-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_BACKEND_H
+#define E_MEMO_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+#include <libedataserver/e-source-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MEMO_SHELL_BACKEND \
+ (e_memo_shell_backend_get_type ())
+#define E_MEMO_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackend))
+#define E_MEMO_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendClass))
+#define E_IS_MEMO_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND))
+#define E_IS_MEMO_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MEMO_SHELL_BACKEND))
+#define E_MEMO_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MEMO_SHELL_BACKEND, EMemoShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMemoShellBackend EMemoShellBackend;
+typedef struct _EMemoShellBackendClass EMemoShellBackendClass;
+typedef struct _EMemoShellBackendPrivate EMemoShellBackendPrivate;
+
+struct _EMemoShellBackend {
+ EShellBackend parent;
+ EMemoShellBackendPrivate *priv;
+};
+
+struct _EMemoShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+GType e_memo_shell_backend_get_type (void);
+void e_memo_shell_backend_register_type
+ (GTypeModule *type_module);
+ESourceList * e_memo_shell_backend_get_source_list
+ (EMemoShellBackend *memo_shell_backend);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_BACKEND_H */
diff --cc calendar/module/e-memo-shell-content.c
index 4e06448,0000000..ce02015
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-content.c
+++ b/calendar/module/e-memo-shell-content.c
@@@ -1,676 -1,0 +1,676 @@@
+/*
+ * e-memo-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-memo-shell-content.h"
+
+#include <glib/gi18n.h>
+
+#include "e-util/gconf-bridge.h"
+
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-model-memos.h"
+#include "calendar/gui/e-memo-table.h"
+#include "calendar/gui/e-memo-table-config.h"
+
+#include "widgets/menus/gal-view-etable.h"
+
+#define E_MEMO_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentPrivate))
+
+#define E_MEMO_TABLE_DEFAULT_STATE \
+ "<?xml version=\"1.0\"?>" \
+ "<ETableState>" \
+ " <column source=\"1\"/>" \
+ " <column source=\"0\"/>" \
+ " <column source=\"2\"/>" \
+ " <grouping/>" \
+ "</ETableState>"
+
+struct _EMemoShellContentPrivate {
+ GtkWidget *paned;
+ GtkWidget *memo_table;
+ GtkWidget *memo_preview;
+
+ ECalModel *memo_model;
+ EMemoTableConfig *table_config;
+ GalViewInstance *view_instance;
+
+ gchar *current_uid;
+};
+
+enum {
+ PROP_0,
+ PROP_MODEL,
+ PROP_PREVIEW_VISIBLE
+};
+
+enum {
+ TARGET_VCALENDAR
+};
+
+static GtkTargetEntry drag_types[] = {
- { "text/calendar", 0, TARGET_VCALENDAR },
- { "text/x-calendar", 0, TARGET_VCALENDAR }
++ { (gchar *) "text/calendar", 0, TARGET_VCALENDAR },
++ { (gchar *) "text/x-calendar", 0, TARGET_VCALENDAR }
+};
+
+static gpointer parent_class;
+static GType memo_shell_content_type;
+
+static void
+memo_shell_content_display_view_cb (EMemoShellContent *memo_shell_content,
+ GalView *gal_view)
+{
+ EMemoTable *memo_table;
+ ETable *table;
+
+ if (!GAL_IS_VIEW_ETABLE (gal_view))
+ return;
+
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ table = e_memo_table_get_table (memo_table);
+
+ gal_view_etable_attach_table (GAL_VIEW_ETABLE (gal_view), table);
+}
+
+static void
+memo_shell_content_table_foreach_cb (gint model_row,
+ gpointer user_data)
+{
+ ECalModelComponent *comp_data;
+ icalcomponent *clone;
+ icalcomponent *vcal;
+ gchar *string;
+
+ struct {
+ ECalModel *model;
+ GSList *list;
+ } *foreach_data = user_data;
+
+ comp_data = e_cal_model_get_component_at (
+ foreach_data->model, model_row);
+
+ vcal = e_cal_util_new_top_level ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp);
+ icalcomponent_add_component (vcal, clone);
+
+ /* String is owned by libical; do not free. */
+ string = icalcomponent_as_ical_string (vcal);
+ if (string != NULL) {
+ ESource *source;
+ const gchar *source_uid;
+
+ source = e_cal_get_source (comp_data->client);
+ source_uid = e_source_peek_uid (source);
+
+ foreach_data->list = g_slist_prepend (
+ foreach_data->list,
+ g_strdup_printf ("%s\n%s", source_uid, string));
+ }
+
+ icalcomponent_free (vcal);
+}
+
+static void
+memo_shell_content_table_drag_data_get_cb (EMemoShellContent *memo_shell_content,
+ gint row,
+ gint col,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ EMemoTable *memo_table;
+ ETable *table;
+
+ struct {
+ ECalModel *model;
+ GSList *list;
+ } foreach_data;
+
+ if (info != TARGET_VCALENDAR)
+ return;
+
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ table = e_memo_table_get_table (memo_table);
+
+ foreach_data.model = e_memo_table_get_model (memo_table);
+ foreach_data.list = NULL;
+
+ e_table_selected_row_foreach (
+ table, memo_shell_content_table_foreach_cb,
+ &foreach_data);
+
+ if (foreach_data.list != NULL) {
+ cal_comp_selection_set_string_list (
+ selection_data, foreach_data.list);
+ g_slist_foreach (foreach_data.list, (GFunc) g_free, NULL);
+ g_slist_free (foreach_data.list);
+ }
+}
+
+static void
+memo_shell_content_table_drag_data_delete_cb (EMemoShellContent *memo_shell_content,
+ gint row,
+ gint col,
+ GdkDragContext *context)
+{
+ /* Moved components are deleted from source immediately when moved,
+ * because some of them can be part of destination source, and we
+ * don't want to delete not-moved memos. There is no such information
+ * which event has been moved and which not, so skip this method. */
+}
+
+static void
+memo_shell_content_cursor_change_cb (EMemoShellContent *memo_shell_content,
+ gint row,
+ ETable *table)
+{
+ ECalComponentPreview *memo_preview;
+ EMemoTable *memo_table;
+ ECalModel *memo_model;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ const gchar *uid;
+
+ memo_model = e_memo_shell_content_get_memo_model (memo_shell_content);
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content);
+
+ if (e_table_selected_count (table) != 1) {
+ e_cal_component_preview_clear (memo_preview);
+ return;
+ }
+
+ row = e_table_get_cursor_row (table);
+ comp_data = e_cal_model_get_component_at (memo_model, row);
+
+ comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (
+ comp, icalcomponent_new_clone (comp_data->icalcomp));
+ e_cal_component_preview_display (
+ memo_preview, comp_data->client, comp);
+
+ e_cal_component_get_uid (comp, &uid);
+ g_free (memo_shell_content->priv->current_uid);
+ memo_shell_content->priv->current_uid = g_strdup (uid);
+
+ g_object_unref (comp);
+}
+
+static void
+memo_shell_content_selection_change_cb (EMemoShellContent *memo_shell_content,
+ ETable *table)
+{
+ ECalComponentPreview *memo_preview;
+
+ memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content);
+
+ /* XXX Old code emits a "selection-changed" signal here. */
+
+ if (e_table_selected_count (table) != 1)
+ e_cal_component_preview_clear (memo_preview);
+}
+
+static void
+memo_shell_content_model_row_changed_cb (EMemoShellContent *memo_shell_content,
+ gint row,
+ ETableModel *model)
+{
+ ECalModelComponent *comp_data;
+ EMemoTable *memo_table;
+ ETable *table;
+ const gchar *current_uid;
+ const gchar *uid;
+
+ current_uid = memo_shell_content->priv->current_uid;
+ if (current_uid == NULL)
+ return;
+
+ comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
+ if (comp_data == NULL)
+ return;
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ if (g_strcmp0 (uid, current_uid) != 0)
+ return;
+
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ table = e_memo_table_get_table (memo_table);
+
+ memo_shell_content_cursor_change_cb (memo_shell_content, 0, table);
+}
+
+static void
+memo_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_PREVIEW_VISIBLE:
+ e_memo_shell_content_set_preview_visible (
+ E_MEMO_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MODEL:
+ g_value_set_object (
+ value, e_memo_shell_content_get_memo_model (
+ E_MEMO_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_PREVIEW_VISIBLE:
+ g_value_set_boolean (
+ value, e_memo_shell_content_get_preview_visible (
+ E_MEMO_SHELL_CONTENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_shell_content_dispose (GObject *object)
+{
+ EMemoShellContentPrivate *priv;
+
+ priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->memo_table != NULL) {
+ g_object_unref (priv->memo_table);
+ priv->memo_table = NULL;
+ }
+
+ if (priv->memo_preview != NULL) {
+ g_object_unref (priv->memo_preview);
+ priv->memo_preview = NULL;
+ }
+
+ if (priv->memo_model != NULL) {
+ g_object_unref (priv->memo_model);
+ priv->memo_model = NULL;
+ }
+
+ if (priv->table_config != NULL) {
+ g_object_unref (priv->table_config);
+ priv->table_config = NULL;
+ }
+
+ if (priv->view_instance != NULL) {
+ g_object_unref (priv->view_instance);
+ priv->view_instance = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+memo_shell_content_finalize (GObject *object)
+{
+ EMemoShellContentPrivate *priv;
+
+ priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
+
+ g_free (priv->current_uid);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+memo_shell_content_constructed (GObject *object)
+{
+ EMemoShellContentPrivate *priv;
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GalViewInstance *view_instance;
+ ETable *table;
+ GConfBridge *bridge;
+ GtkWidget *container;
+ GtkWidget *widget;
+ const gchar *key;
+
+ priv = E_MEMO_SHELL_CONTENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+
+ /* Build content widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = gtk_vpaned_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_memo_table_new (shell_view, priv->memo_model);
+ gtk_paned_add1 (GTK_PANED (container), widget);
+ priv->memo_table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_paned_add2 (GTK_PANED (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_cal_component_preview_new ();
+ e_cal_component_preview_set_default_timezone (
+ E_CAL_COMPONENT_PREVIEW (widget),
+ calendar_config_get_icaltimezone ());
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->memo_preview = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Configure the memo table. */
+
+ widget = E_MEMO_TABLE (priv->memo_table)->etable;
+ table = e_table_scrolled_get_table (E_TABLE_SCROLLED (widget));
+
+ priv->table_config = e_memo_table_config_new (
+ E_MEMO_TABLE (priv->memo_table));
+
+ e_table_set_state (table, E_MEMO_TABLE_DEFAULT_STATE);
+
+ e_table_drag_source_set (
+ table, GDK_BUTTON1_MASK,
+ drag_types, G_N_ELEMENTS (drag_types),
+ GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
+
+ g_signal_connect_swapped (
+ table, "table-drag-data-get",
+ G_CALLBACK (memo_shell_content_table_drag_data_get_cb),
+ object);
+
+ g_signal_connect_swapped (
+ table, "table-drag-data-delete",
+ G_CALLBACK (memo_shell_content_table_drag_data_delete_cb),
+ object);
+
+ g_signal_connect_swapped (
+ table, "cursor-change",
+ G_CALLBACK (memo_shell_content_cursor_change_cb),
+ object);
+
+ g_signal_connect_swapped (
+ table, "selection-change",
+ G_CALLBACK (memo_shell_content_selection_change_cb),
+ object);
+
+ g_signal_connect_swapped (
+ priv->memo_model, "model-row-changed",
+ G_CALLBACK (memo_shell_content_model_row_changed_cb),
+ object);
+
+ /* Load the view instance. */
+
+ view_instance = e_shell_view_new_view_instance (shell_view, NULL);
+ g_signal_connect_swapped (
+ view_instance, "display-view",
+ G_CALLBACK (memo_shell_content_display_view_cb),
+ object);
+ gal_view_instance_load (view_instance);
+ priv->view_instance = view_instance;
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (priv->paned);
+ key = "/apps/evolution/calendar/display/memo_vpane_position";
+ gconf_bridge_bind_property_delayed (bridge, key, object, "position");
+}
+
+static guint32
+memo_shell_content_check_state (EShellContent *shell_content)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ETable *table;
+ GSList *list, *iter;
+ gboolean editable = TRUE;
+ gboolean has_url = FALSE;
+ gint n_selected;
+ guint32 state = 0;
+
+ memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ table = e_memo_table_get_table (memo_table);
+ n_selected = e_table_selected_count (table);
+
+ list = e_memo_table_get_selected (memo_table);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ icalproperty *prop;
+ gboolean read_only;
+
+ e_cal_is_read_only (comp_data->client, &read_only, NULL);
+ editable &= !read_only;
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ has_url |= (prop != NULL);
+ }
+ g_slist_free (list);
+
+ if (n_selected == 1)
+ state |= E_MEMO_SHELL_CONTENT_SELECTION_SINGLE;
+ if (n_selected > 1)
+ state |= E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE;
+ if (editable)
+ state |= E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT;
+ if (has_url)
+ state |= E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL;
+
+ return state;
+}
+
+static void
+memo_shell_content_class_init (EMemoShellContentClass *class)
+{
+ GObjectClass *object_class;
+ EShellContentClass *shell_content_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMemoShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = memo_shell_content_set_property;
+ object_class->get_property = memo_shell_content_get_property;
+ object_class->dispose = memo_shell_content_dispose;
+ object_class->finalize = memo_shell_content_finalize;
+ object_class->constructed = memo_shell_content_constructed;
+
+ shell_content_class = E_SHELL_CONTENT_CLASS (class);
+ shell_content_class->check_state = memo_shell_content_check_state;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MODEL,
+ g_param_spec_object (
+ "model",
+ _("Model"),
+ _("The memo table model"),
+ E_TYPE_CAL_MODEL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW_VISIBLE,
+ g_param_spec_boolean (
+ "preview-visible",
+ _("Preview is Visible"),
+ _("Whether the preview pane is visible"),
+ TRUE,
+ G_PARAM_READWRITE));
+}
+
+static void
+memo_shell_content_init (EMemoShellContent *memo_shell_content)
+{
+ memo_shell_content->priv =
+ E_MEMO_SHELL_CONTENT_GET_PRIVATE (memo_shell_content);
+
+ memo_shell_content->priv->memo_model = e_cal_model_memos_new ();
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_memo_shell_content_get_type (void)
+{
+ return memo_shell_content_type;
+}
+
+void
+e_memo_shell_content_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EMemoShellContentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) memo_shell_content_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMemoShellContent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) memo_shell_content_init,
+ NULL /* value_table */
+ };
+
+ memo_shell_content_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_CONTENT,
+ "EMemoShellContent", &type_info, 0);
+}
+
+GtkWidget *
+e_memo_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_MEMO_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+ECalModel *
+e_memo_shell_content_get_memo_model (EMemoShellContent *memo_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+
+ return memo_shell_content->priv->memo_model;
+}
+
+ECalComponentPreview *
+e_memo_shell_content_get_memo_preview (EMemoShellContent *memo_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+
+ return E_CAL_COMPONENT_PREVIEW (
+ memo_shell_content->priv->memo_preview);
+}
+
+EMemoTable *
+e_memo_shell_content_get_memo_table (EMemoShellContent *memo_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+
+ return E_MEMO_TABLE (memo_shell_content->priv->memo_table);
+}
+
+GalViewInstance *
+e_memo_shell_content_get_view_instance (EMemoShellContent *memo_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), NULL);
+
+ return memo_shell_content->priv->view_instance;
+}
+
+gboolean
+e_memo_shell_content_get_preview_visible (EMemoShellContent *memo_shell_content)
+{
+ GtkPaned *paned;
+ GtkWidget *child;
+
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_CONTENT (memo_shell_content), FALSE);
+
+ paned = GTK_PANED (memo_shell_content->priv->paned);
+ child = gtk_paned_get_child2 (paned);
+
+ return GTK_WIDGET_VISIBLE (child);
+}
+
+void
+e_memo_shell_content_set_preview_visible (EMemoShellContent *memo_shell_content,
+ gboolean preview_visible)
+{
+ GtkPaned *paned;
+ GtkWidget *child;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_CONTENT (memo_shell_content));
+
+ paned = GTK_PANED (memo_shell_content->priv->paned);
+ child = gtk_paned_get_child2 (paned);
+
+ if (preview_visible)
+ gtk_widget_show (child);
+ else
+ gtk_widget_hide (child);
+
+ g_object_notify (G_OBJECT (memo_shell_content), "preview-visible");
+}
diff --cc calendar/module/e-memo-shell-content.h
index ace932c,0000000..84c22d6
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-content.h
+++ b/calendar/module/e-memo-shell-content.h
@@@ -1,96 -1,0 +1,96 @@@
+/*
+ * e-memo-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_CONTENT_H
+#define E_MEMO_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-view.h>
+
+#include <calendar/gui/e-memo-table.h>
+#include <calendar/gui/e-cal-component-preview.h>
+
+#include <menus/gal-view-instance.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MEMO_SHELL_CONTENT \
+ (e_memo_shell_content_get_type ())
+#define E_MEMO_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContent))
+#define E_MEMO_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentClass))
+#define E_IS_MEMO_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MEMO_SHELL_CONTENT))
+#define E_IS_MEMO_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MEMO_SHELL_CONTENT))
+#define E_MEMO_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MEMO_SHELL_CONTENT, EMemoShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMemoShellContent EMemoShellContent;
+typedef struct _EMemoShellContentClass EMemoShellContentClass;
+typedef struct _EMemoShellContentPrivate EMemoShellContentPrivate;
+
+enum {
+ E_MEMO_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
+ E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
+ E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT = 1 << 2,
+ E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL = 1 << 3
+};
+
+struct _EMemoShellContent {
+ EShellContent parent;
+ EMemoShellContentPrivate *priv;
+};
+
+struct _EMemoShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_memo_shell_content_get_type (void);
+void e_memo_shell_content_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_memo_shell_content_new(EShellView *shell_view);
+ECalModel * e_memo_shell_content_get_memo_model
+ (EMemoShellContent *memo_shell_conent);
+ECalComponentPreview *
+ e_memo_shell_content_get_memo_preview
+ (EMemoShellContent *memo_shell_content);
+EMemoTable * e_memo_shell_content_get_memo_table
+ (EMemoShellContent *memo_shell_content);
+GalViewInstance *
+ e_memo_shell_content_get_view_instance
+ (EMemoShellContent *memo_shell_content);
+gboolean e_memo_shell_content_get_preview_visible
+ (EMemoShellContent *memo_shell_content);
+void e_memo_shell_content_set_preview_visible
+ (EMemoShellContent *memo_shell_content,
+ gboolean preview_visible);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_CONTENT_H */
diff --cc calendar/module/e-memo-shell-migrate.c
index 763d366,0000000..de40a7e
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-migrate.c
+++ b/calendar/module/e-memo-shell-migrate.c
@@@ -1,257 -1,0 +1,257 @@@
+/*
+ * e-memo-shell-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-memo-shell-migrate.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <camel/camel-url.h>
+#include <libedataserver/e-account.h>
+#include <libedataserver/e-account-list.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-group.h>
+#include <libedataserver/e-source-list.h>
+
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/calendar-config-keys.h"
+
+#define WEBCAL_BASE_URI "webcal://"
+#define PERSONAL_RELATIVE_URI "system"
+#define GROUPWISE_BASE_URI "groupwise://"
+
+static void
+create_memo_sources (EShellBackend *shell_backend,
+ ESourceList *source_list,
+ ESourceGroup **on_this_computer,
+ ESourceGroup **on_the_web,
+ ESource **personal_source)
+{
+ GSList *groups;
+ ESourceGroup *group;
+ char *base_uri, *base_uri_proto;
+ const gchar *base_dir;
+
+ *on_this_computer = NULL;
+ *on_the_web = NULL;
+ *personal_source = NULL;
+
+ base_dir = e_shell_backend_get_config_dir (shell_backend);
+ base_uri = g_build_filename (base_dir, "local", NULL);
+
+ base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL);
+
+ groups = e_source_list_peek_groups (source_list);
+ if (groups) {
+ /* groups are already there, we need to search for things... */
+ GSList *g;
+
+ for (g = groups; g; g = g->next) {
+
+ group = E_SOURCE_GROUP (g->data);
+
+ if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
+ *on_this_computer = g_object_ref (group);
+ else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group)))
+ *on_the_web = g_object_ref (group);
+ }
+ }
+
+ if (*on_this_computer) {
+ /* make sure "Personal" shows up as a source under
+ this group */
+ GSList *sources = e_source_group_peek_sources (*on_this_computer);
+ GSList *s;
+ for (s = sources; s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (relative_uri == NULL)
+ continue;
+ if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) {
+ *personal_source = g_object_ref (source);
+ break;
+ }
+ }
+ } else {
+ /* create the local source group */
+ group = e_source_group_new (_("On This Computer"), base_uri_proto);
+ e_source_list_add_group (source_list, group, -1);
+
+ *on_this_computer = group;
+ }
+
+ if (!*personal_source) {
+ /* Create the default Person task list */
+ ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
+ e_source_group_add_source (*on_this_computer, source, -1);
+
+ if (!calendar_config_get_primary_memos () && !calendar_config_get_memos_selected ()) {
+ GSList selected;
+
+ calendar_config_set_primary_memos (e_source_peek_uid (source));
+
+ selected.data = (gpointer)e_source_peek_uid (source);
+ selected.next = NULL;
+ calendar_config_set_memos_selected (&selected);
+ }
+
+ e_source_set_color_spec (source, "#BECEDD");
+ *personal_source = source;
+ }
+
+ if (!*on_the_web) {
+ /* Create the Webcal source group */
+ group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI);
+ e_source_list_add_group (source_list, group, -1);
+
+ *on_the_web = group;
+ }
+
+ g_free (base_uri_proto);
+ g_free (base_uri);
+}
+
+static gboolean
+is_groupwise_account (EAccount *account)
+{
+ if (account->source->url != NULL) {
+ return g_str_has_prefix (account->source->url, GROUPWISE_BASE_URI);
+ } else {
+ return FALSE;
+ }
+}
+
+static void
+add_gw_esource (ESourceList *source_list, const char *group_name, const char *source_name, CamelURL *url, GConfClient *client)
+{
+ ESourceGroup *group;
+ ESource *source;
+ GSList *ids, *temp ;
+ GError *error = NULL;
+ char *relative_uri;
+ const char *soap_port;
+ const char * use_ssl;
+ const char *poa_address;
+ const char *offline_sync;
+
+
+ poa_address = url->host;
+ if (!poa_address || strlen (poa_address) ==0)
+ return;
+ soap_port = camel_url_get_param (url, "soap_port");
+
+ if (!soap_port || strlen (soap_port) == 0)
+ soap_port = "7191";
+
+ use_ssl = camel_url_get_param (url, "use_ssl");
+ offline_sync = camel_url_get_param (url, "offline_sync");
+
+ group = e_source_group_new (group_name, GROUPWISE_BASE_URI);
+ if (!e_source_list_add_group (source_list, group, -1))
+ return;
+ relative_uri = g_strdup_printf ("%s %s/", url->user, poa_address);
+
+ source = e_source_new (source_name, relative_uri);
+ e_source_set_property (source, "auth", "1");
+ e_source_set_property (source, "username", url->user);
+ e_source_set_property (source, "port", camel_url_get_param (url, "soap_port"));
+ e_source_set_property (source, "auth-domain", "Groupwise");
+ e_source_set_property (source, "use_ssl", use_ssl);
+ e_source_set_property (source, "offline_sync", offline_sync ? "1" : "0" );
+
+ e_source_set_color_spec (source, "#EEBC60");
+ e_source_group_add_source (group, source, -1);
+
+ ids = gconf_client_get_list (client, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, &error);
+ if ( error != NULL ) {
+ g_warning("%s (%s) %s\n", G_STRLOC, G_STRFUNC, error->message);
+ g_error_free(error);
+ }
+ ids = g_slist_append (ids, g_strdup (e_source_peek_uid (source)));
+ gconf_client_set_list (client, CALENDAR_CONFIG_MEMOS_SELECTED_MEMOS, GCONF_VALUE_STRING, ids, NULL);
+ temp = ids;
+ for (; temp != NULL; temp = g_slist_next (temp))
+ g_free (temp->data);
+
+ g_slist_free (ids);
+ g_object_unref (source);
+ g_object_unref (group);
+ g_free (relative_uri);
+}
+
+gboolean
+e_memo_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint revision,
+ GError **error)
+{
+ ESourceGroup *on_this_computer = NULL;
+ ESourceGroup *on_the_web = NULL;
+ ESource *personal_source = NULL;
+ ESourceList *source_list = NULL;
+ gboolean retval = FALSE;
+
+ source_list = g_object_get_data (
+ G_OBJECT (shell_backend), "source-list");
+
+ /* we call this unconditionally now - create_groups either
+ creates the groups/sources or it finds the necessary
+ groups/sources. */
+ create_memo_sources (
+ shell_backend, source_list, &on_this_computer,
+ &on_the_web, &personal_source);
+
+ /* Migration for Gw accounts between versions < 2.8 */
+ if (major == 2 && minor < 8) {
+ EAccountList *al;
+ EAccount *a;
+ CamelURL *url;
+ EIterator *it;
+ GConfClient *gconf_client = gconf_client_get_default ();
+ al = e_account_list_new (gconf_client);
+ for (it = e_list_get_iterator((EList *)al);
+ e_iterator_is_valid(it);
+ e_iterator_next(it)) {
+ a = (EAccount *) e_iterator_get(it);
+ if (!a->enabled || !is_groupwise_account (a))
+ continue;
+ url = camel_url_new (a->source->url, NULL);
+ add_gw_esource (source_list, a->name, _("Notes"), url, gconf_client);
+ camel_url_free (url);
+ }
+ g_object_unref (al);
+ g_object_unref (gconf_client);
+ }
+
+ e_source_list_sync (source_list, NULL);
+ retval = TRUE;
+
+ if (on_this_computer)
+ g_object_unref (on_this_computer);
+ if (on_the_web)
+ g_object_unref (on_the_web);
+ if (personal_source)
+ g_object_unref (personal_source);
+
+ return retval;
+}
diff --cc calendar/module/e-memo-shell-migrate.h
index 26139ed,0000000..ba163c6
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-migrate.h
+++ b/calendar/module/e-memo-shell-migrate.h
@@@ -1,38 -1,0 +1,38 @@@
+/*
+ * e-memo-shell-backend-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_BACKEND_MIGRATE_H
+#define E_MEMO_SHELL_BACKEND_MIGRATE_H
+
+#include <glib.h>
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_memo_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_BACKEND_MIGRATE_H */
diff --cc calendar/module/e-memo-shell-sidebar.c
index 5d5c6a7,0000000..ca5d05c
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-sidebar.c
+++ b/calendar/module/e-memo-shell-sidebar.c
@@@ -1,718 -1,0 +1,718 @@@
+/*
+ * e-memo-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-memo-shell-sidebar.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/e-cal.h>
+
+#include "e-util/e-error.h"
+#include "e-util/e-util.h"
+#include "calendar/common/authentication.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/e-memo-list-selector.h"
+#include "calendar/gui/misc.h"
+
+#include "e-memo-shell-view.h"
+#include "e-memo-shell-backend.h"
+
+#define E_MEMO_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarPrivate))
+
+struct _EMemoShellSidebarPrivate {
+ GtkWidget *selector;
+
+ /* UID -> Client */
+ GHashTable *client_table;
+};
+
+enum {
+ PROP_0,
+ PROP_SELECTOR
+};
+
+enum {
+ CLIENT_ADDED,
+ CLIENT_REMOVED,
+ STATUS_MESSAGE,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+static GType memo_shell_sidebar_type;
+
+static void
+memo_shell_sidebar_emit_client_added (EMemoShellSidebar *memo_shell_sidebar,
+ ECal *client)
+{
+ guint signal_id = signals[CLIENT_ADDED];
+
+ g_signal_emit (memo_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+memo_shell_sidebar_emit_client_removed (EMemoShellSidebar *memo_shell_sidebar,
+ ECal *client)
+{
+ guint signal_id = signals[CLIENT_REMOVED];
+
+ g_signal_emit (memo_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+memo_shell_sidebar_emit_status_message (EMemoShellSidebar *memo_shell_sidebar,
+ const gchar *status_message)
+{
+ guint signal_id = signals[STATUS_MESSAGE];
+
+ g_signal_emit (memo_shell_sidebar, signal_id, 0, status_message, -1.0);
+}
+
+static void
+memo_shell_sidebar_update_timezone (EMemoShellSidebar *memo_shell_sidebar)
+{
+ GHashTable *client_table;
+ icaltimezone *zone;
+ GList *values;
+
+ zone = calendar_config_get_icaltimezone ();
+ client_table = memo_shell_sidebar->priv->client_table;
+ values = g_hash_table_get_values (client_table);
+
+ while (values != NULL) {
+ ECal *client = values->data;
+
+ if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED)
+ e_cal_set_default_timezone (client, zone, NULL);
+
+ values = g_list_delete_link (values, values);
+ }
+
+ /* XXX Need to call e_cal_component_preview_set_default_timezone()
+ * here but the sidebar is not really supposed to access content
+ * stuff. I guess we could emit an "update-timezone" signal
+ * here, but that feels wrong. Maybe this whole thing should
+ * be in EMemoShellView instead. */
+}
+
+static void
+memo_shell_sidebar_backend_died_cb (EMemoShellSidebar *memo_shell_sidebar,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ GHashTable *client_table;
+ ESource *source;
+ const gchar *uid;
+
+ client_table = memo_shell_sidebar->priv->client_table;
+
+ shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ source = e_cal_get_source (client);
+ uid = e_source_peek_uid (source);
+
+ g_object_ref (source);
+
+ g_hash_table_remove (client_table, uid);
+ memo_shell_sidebar_emit_status_message (memo_shell_sidebar, NULL);
+
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:memos-crashed", NULL);
+
+ g_object_unref (source);
+}
+
+static void
+memo_shell_sidebar_backend_error_cb (EMemoShellSidebar *memo_shell_sidebar,
+ const gchar *message,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ GtkWidget *dialog;
+ const gchar *uri;
+ gchar *uri_no_passwd;
+
+ shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ uri = e_cal_get_uri (client);
+ uri_no_passwd = get_uri_without_password (uri);
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("Error on %s\n%s"),
+ uri_no_passwd, message);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_free (uri_no_passwd);
+}
+
+static void
+memo_shell_sidebar_client_opened_cb (EMemoShellSidebar *memo_shell_sidebar,
+ ECalendarStatus status,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ ESource *source;
+
+ source = e_cal_get_source (client);
+
+ shell_sidebar = E_SHELL_SIDEBAR (memo_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
+ status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
+ auth_cal_forget_password (client);
+
+ switch (status) {
+ case E_CALENDAR_STATUS_OK:
+ g_signal_handlers_disconnect_matched (
+ client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+ memo_shell_sidebar_client_opened_cb, NULL);
+
+ memo_shell_sidebar_emit_status_message (
+ memo_shell_sidebar, _("Loading memos"));
+ memo_shell_sidebar_emit_client_added (
+ memo_shell_sidebar, client);
+ memo_shell_sidebar_emit_status_message (
+ memo_shell_sidebar, NULL);
+ break;
+
+ case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
+ e_cal_open_async (client, FALSE);
+ break;
+
+ case E_CALENDAR_STATUS_BUSY:
+ break;
+
+ case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-no-contents-offline-memos",
+ NULL);
+ break;
+
+ default:
+ memo_shell_sidebar_emit_client_removed (
+ memo_shell_sidebar, client);
+ break;
+ }
+}
+
+static void
+memo_shell_sidebar_row_changed_cb (EMemoShellSidebar *memo_shell_sidebar,
+ GtkTreePath *tree_path,
+ GtkTreeIter *tree_iter,
+ GtkTreeModel *tree_model)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ /* XXX ESourceSelector's underlying tree store has only one
+ * column: ESource objects. While we're not supposed to
+ * know this, listening for "row-changed" signals from
+ * the model is easier to deal with than the selector's
+ * "selection-changed" signal, which doesn't tell you
+ * _which_ row changed. */
+
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ gtk_tree_model_get (tree_model, tree_iter, 0, &source, -1);
+
+ /* XXX This signal gets emitted a lot while the model is being
+ * rebuilt, during which time we won't get a valid ESource.
+ * ESourceSelector should probably block this signal while
+ * rebuilding the model, but we'll be forgiving and not
+ * emit a warning. */
+ if (!E_IS_SOURCE (source))
+ return;
+
+ if (e_source_selector_source_is_selected (selector, source))
+ e_memo_shell_sidebar_add_source (memo_shell_sidebar, source);
+ else
+ e_memo_shell_sidebar_remove_source (memo_shell_sidebar, source);
+}
+
+static void
+memo_shell_sidebar_selection_changed_cb (EMemoShellSidebar *memo_shell_sidebar,
+ ESourceSelector *selector)
+{
+ GSList *list, *iter;
+
+ /* This signal is emitted less frequently than "row-changed",
+ * especially when the model is being rebuilt. So we'll take
+ * it easy on poor GConf. */
+
+ list = e_source_selector_get_selection (selector);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+
+ iter->data = (gpointer) e_source_peek_uid (source);
+ g_object_unref (source);
+ }
+
+ calendar_config_set_memos_selected (list);
+
+ g_slist_free (list);
+}
+
+static void
+memo_shell_sidebar_primary_selection_changed_cb (EMemoShellSidebar *memo_shell_sidebar,
+ ESourceSelector *selector)
+{
+ ESource *source;
+ const gchar *uid;
+
+ /* XXX ESourceSelector needs a "primary-selection-uid" property
+ * so we can just bind the property with GConfBridge. */
+
+ source = e_source_selector_peek_primary_selection (selector);
+ if (source == NULL)
+ return;
+
+ uid = e_source_peek_uid (source);
+ calendar_config_set_primary_memos (uid);
+}
+
+static void
+memo_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SELECTOR:
+ g_value_set_object (
+ value, e_memo_shell_sidebar_get_selector (
+ E_MEMO_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+memo_shell_sidebar_dispose (GObject *object)
+{
+ EMemoShellSidebarPrivate *priv;
+
+ priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->selector != NULL) {
+ g_object_unref (priv->selector);
+ priv->selector = NULL;
+ }
+
+ g_hash_table_remove_all (priv->client_table);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+memo_shell_sidebar_finalize (GObject *object)
+{
+ EMemoShellSidebarPrivate *priv;
+
+ priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->client_table);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+memo_shell_sidebar_constructed (GObject *object)
+{
+ EMemoShellSidebarPrivate *priv;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellSidebar *shell_sidebar;
+ ESourceSelector *selector;
+ ESourceList *source_list;
+ ESource *source;
+ GtkContainer *container;
+ GtkTreeModel *model;
+ GtkWidget *widget;
+ AtkObject *a11y;
+ GSList *list, *iter;
+ gchar *uid;
+
+ priv = E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ source_list = e_memo_shell_backend_get_source_list (
+ E_MEMO_SHELL_BACKEND (shell_backend));
+
+ container = GTK_CONTAINER (shell_sidebar);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (container, widget);
+ gtk_widget_show (widget);
+
+ container = GTK_CONTAINER (widget);
+
+ widget = e_memo_list_selector_new (source_list);
+ e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
+ gtk_container_add (container, widget);
+ a11y = gtk_widget_get_accessible (widget);
+ atk_object_set_name (a11y, _("Memo List Selector"));
+ priv->selector = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Restore the selector state from the last session. */
+
+ selector = E_SOURCE_SELECTOR (priv->selector);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+ g_signal_connect_swapped (
+ model, "row-changed",
+ G_CALLBACK (memo_shell_sidebar_row_changed_cb),
+ object);
+
+ source = NULL;
+ uid = calendar_config_get_primary_memos ();
+ if (uid != NULL)
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ if (source == NULL)
+ source = e_source_list_peek_source_any (source_list);
+ if (source != NULL)
+ e_source_selector_set_primary_selection (selector, source);
+ g_free (uid);
+
+ list = calendar_config_get_memos_selected ();
+ for (iter = list; iter != NULL; iter = iter->next) {
+ uid = iter->data;
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ g_free (uid);
+
+ if (source == NULL)
+ continue;
+
+ e_source_selector_select_source (selector, source);
+ }
+ g_slist_free (list);
+
+ /* Listen for subsequent changes to the selector. */
+
+ g_signal_connect_swapped (
+ widget, "selection-changed",
+ G_CALLBACK (memo_shell_sidebar_selection_changed_cb),
+ object);
+
+ g_signal_connect_swapped (
+ widget, "primary-selection-changed",
+ G_CALLBACK (memo_shell_sidebar_primary_selection_changed_cb),
+ object);
+}
+
+static guint32
+memo_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *source;
+ gboolean is_system = FALSE;
+ guint32 state = 0;
+
+ memo_shell_sidebar = E_MEMO_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+
+ if (source != NULL) {
+ const gchar *uri;
+
+ uri = e_source_peek_relative_uri (source);
+ is_system = (uri == NULL || strcmp (uri, "system") == 0);
+ }
+
+ if (source != NULL)
+ state |= E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
+ if (is_system)
+ state |= E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM;
+
+ return state;
+}
+
+static void
+memo_shell_sidebar_client_added (EMemoShellSidebar *memo_shell_sidebar,
+ ECal *client)
+{
+ memo_shell_sidebar_update_timezone (memo_shell_sidebar);
+}
+
+static void
+memo_shell_sidebar_client_removed (EMemoShellSidebar *memo_shell_sidebar,
+ ECal *client)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ESource *source;
+ const gchar *uid;
+
+ client_table = memo_shell_sidebar->priv->client_table;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ g_signal_handlers_disconnect_matched (
+ client, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, memo_shell_sidebar);
+
+ source = e_cal_get_source (client);
+ e_source_selector_unselect_source (selector, source);
+
+ uid = e_source_peek_uid (source);
+ g_hash_table_remove (client_table, uid);
+
+ memo_shell_sidebar_emit_status_message (memo_shell_sidebar, NULL);
+}
+
+static void
+memo_shell_sidebar_class_init (EMemoShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMemoShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = memo_shell_sidebar_get_property;
+ object_class->dispose = memo_shell_sidebar_dispose;
+ object_class->finalize = memo_shell_sidebar_finalize;
+ object_class->constructed = memo_shell_sidebar_constructed;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = memo_shell_sidebar_check_state;
+
+ class->client_added = memo_shell_sidebar_client_added;
+ class->client_removed = memo_shell_sidebar_client_removed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTOR,
+ g_param_spec_object (
+ "selector",
+ _("Source Selector Widget"),
+ _("This widget displays groups of memo lists"),
+ E_TYPE_SOURCE_SELECTOR,
+ G_PARAM_READABLE));
+
+ signals[CLIENT_ADDED] = g_signal_new (
+ "client-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMemoShellSidebarClass, client_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL);
+
+ signals[CLIENT_REMOVED] = g_signal_new (
+ "client-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMemoShellSidebarClass, client_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL);
+
+ signals[STATUS_MESSAGE] = g_signal_new (
+ "status-message",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EMemoShellSidebarClass, status_message),
+ NULL, NULL,
+ e_marshal_VOID__STRING_DOUBLE,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_DOUBLE);
+}
+
+static void
+memo_shell_sidebar_init (EMemoShellSidebar *memo_shell_sidebar)
+{
+ GHashTable *client_table;
+
+ client_table = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ memo_shell_sidebar->priv =
+ E_MEMO_SHELL_SIDEBAR_GET_PRIVATE (memo_shell_sidebar);
+
+ memo_shell_sidebar->priv->client_table = client_table;
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_memo_shell_sidebar_get_type (void)
+{
+ return memo_shell_sidebar_type;
+}
+
+void
+e_memo_shell_sidebar_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EMemoShellSidebarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) memo_shell_sidebar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMemoShellSidebar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) memo_shell_sidebar_init,
+ NULL /* value_table */
+ };
+
+ memo_shell_sidebar_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_SIDEBAR,
+ "EMemoShellSidebar", &type_info, 0);
+}
+
+GtkWidget *
+e_memo_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_MEMO_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+ESourceSelector *
+e_memo_shell_sidebar_get_selector (EMemoShellSidebar *memo_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar), NULL);
+
+ return E_SOURCE_SELECTOR (memo_shell_sidebar->priv->selector);
+}
+
+void
+e_memo_shell_sidebar_add_source (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ECal *client;
+ const gchar *uid;
+ const gchar *uri;
+ gchar *message;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ client_table = memo_shell_sidebar->priv->client_table;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ uid = e_source_peek_uid (source);
+ client = g_hash_table_lookup (client_table, uid);
+
+ if (client != NULL)
+ return;
+
+ client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_JOURNAL);
+ g_return_if_fail (client != NULL);
+
+ g_signal_connect_swapped (
+ client, "backend-died",
+ G_CALLBACK (memo_shell_sidebar_backend_died_cb),
+ memo_shell_sidebar);
+
+ g_signal_connect_swapped (
+ client, "backend-error",
+ G_CALLBACK (memo_shell_sidebar_backend_error_cb),
+ memo_shell_sidebar);
+
+ g_hash_table_insert (client_table, g_strdup (uid), client);
+ e_source_selector_select_source (selector, source);
+
+ uri = e_cal_get_uri (client);
+ message = g_strdup_printf (_("Opening memos at %s"), uri);
+ memo_shell_sidebar_emit_status_message (memo_shell_sidebar, message);
+ g_free (message);
+
+ g_signal_connect_swapped (
+ client, "cal-opened",
+ G_CALLBACK (memo_shell_sidebar_client_opened_cb),
+ memo_shell_sidebar);
+
+ e_cal_open_async (client, FALSE);
+}
+
+void
+e_memo_shell_sidebar_remove_source (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ECal *client;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_SIDEBAR (memo_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ client_table = memo_shell_sidebar->priv->client_table;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ uid = e_source_peek_uid (source);
+ client = g_hash_table_lookup (client_table, uid);
+
+ if (client == NULL)
+ return;
+
+ memo_shell_sidebar_emit_client_removed (memo_shell_sidebar, client);
+}
diff --cc calendar/module/e-memo-shell-sidebar.h
index 9a30b91,0000000..665c8f2
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-sidebar.h
+++ b/calendar/module/e-memo-shell-sidebar.h
@@@ -1,95 -1,0 +1,95 @@@
+/*
+ * e-memo-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_SIDEBAR_H
+#define E_MEMO_SHELL_SIDEBAR_H
+
+#include <libecal/e-cal.h>
+#include <libedataserverui/e-source-selector.h>
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MEMO_SHELL_SIDEBAR \
+ (e_memo_shell_sidebar_get_type ())
+#define E_MEMO_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebar))
+#define E_MEMO_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarClass))
+#define E_IS_MEMO_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MEMO_SHELL_SIDEBAR))
+#define E_IS_MEMO_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MEMO_SHELL_SIDEBAR))
+#define E_MEMO_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MEMO_SHELL_SIDEBAR, EMemoShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMemoShellSidebar EMemoShellSidebar;
+typedef struct _EMemoShellSidebarClass EMemoShellSidebarClass;
+typedef struct _EMemoShellSidebarPrivate EMemoShellSidebarPrivate;
+
+enum {
+ E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
+ E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM = 1 << 1
+};
+
+struct _EMemoShellSidebar {
+ EShellSidebar parent;
+ EMemoShellSidebarPrivate *priv;
+};
+
+struct _EMemoShellSidebarClass {
+ EShellSidebarClass parent_class;
+
+ /* Signals */
+ void (*client_added) (EMemoShellSidebar *memo_shell_sidebar,
+ ECal *client);
+ void (*client_removed) (EMemoShellSidebar *memo_shell_sidebar,
+ ECal *client);
+ void (*status_message) (EMemoShellSidebar *memo_shell_sidebar,
+ const gchar *status_message,
+ gdouble percent);
+};
+
+GType e_memo_shell_sidebar_get_type (void);
+void e_memo_shell_sidebar_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_memo_shell_sidebar_new(EShellView *shell_view);
+ESourceSelector *
+ e_memo_shell_sidebar_get_selector
+ (EMemoShellSidebar *memo_shell_sidebar);
+void e_memo_shell_sidebar_add_source
+ (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source);
+void e_memo_shell_sidebar_remove_source
+ (EMemoShellSidebar *memo_shell_sidebar,
+ ESource *source);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_SIDEBAR_H */
diff --cc calendar/module/e-memo-shell-view-actions.c
index 30dfde6,0000000..ab0b9f0
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view-actions.c
+++ b/calendar/module/e-memo-shell-view-actions.c
@@@ -1,920 -1,0 +1,920 @@@
+/*
+ * e-memo-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-memo-shell-view-private.h"
+
+static void
+action_gal_save_custom_view_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EShellView *shell_view;
+ GalViewInstance *view_instance;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with saving the custom view. */
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ view_instance = e_memo_shell_content_get_view_instance (memo_shell_content);
+ gal_view_instance_save_as (view_instance);
+}
+
+static void
+action_memo_clipboard_copy_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ e_memo_table_copy_clipboard (memo_table);
+}
+
+static void
+action_memo_clipboard_cut_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ e_memo_table_cut_clipboard (memo_table);
+}
+
+static void
+action_memo_clipboard_paste_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ e_memo_table_paste_clipboard (memo_table);
+}
+
+static void
+action_memo_delete_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ ECalComponentPreview *memo_preview;
+ EMemoTable *memo_table;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content);
+
+ e_memo_shell_view_set_status_message (
+ memo_shell_view, _("Deleting selected memos..."), -1.0);
+ e_memo_table_delete_selected (memo_table);
+ e_memo_shell_view_set_status_message (memo_shell_view, NULL, -1.0);
+
+ e_cal_component_preview_clear (memo_preview);
+}
+
+static void
+action_memo_forward_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GSList *list;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only forward the first selected memo. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+ itip_send_comp (
+ E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+ comp_data->client, NULL, NULL, NULL, TRUE);
+ g_object_unref (comp);
+}
+
+static void
+action_memo_list_copy_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ESourceSelector *selector;
+ ESource *source;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ copy_source_dialog (
+ GTK_WINDOW (shell_window),
+ source, E_CAL_SOURCE_TYPE_JOURNAL);
+}
+
+static void
+action_memo_list_delete_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellBackend *memo_shell_backend;
+ EMemoShellContent *memo_shell_content;
+ EMemoShellSidebar *memo_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EMemoTable *memo_table;
+ ECal *client;
+ ECalModel *model;
+ ESourceSelector *selector;
+ ESourceGroup *source_group;
+ ESourceList *source_list;
+ ESource *source;
+ gint response;
+ gchar *uri;
+ GError *error = NULL;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ memo_shell_backend = memo_shell_view->priv->memo_shell_backend;
+ source_list = e_memo_shell_backend_get_source_list (memo_shell_backend);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ /* Ask for confirmation. */
+ response = e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-memo-list",
+ e_source_peek_name (source));
+ if (response != GTK_RESPONSE_YES)
+ return;
+
+ uri = e_source_get_uri (source);
+ client = e_cal_model_get_client_for_uri (model, uri);
+ if (client == NULL)
+ client = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_JOURNAL);
+ g_free (uri);
+
+ g_return_if_fail (client != NULL);
+
+ if (!e_cal_remove (client, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (e_source_selector_source_is_selected (selector, source)) {
+ e_memo_shell_sidebar_remove_source (
+ memo_shell_sidebar, source);
+ e_source_selector_unselect_source (selector, source);
+ }
+
+ source_group = e_source_peek_group (source);
+ e_source_group_remove_source (source_group, source);
+
+ if (!e_source_list_sync (source_list, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+action_memo_list_new_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ calendar_setup_new_memo_list (GTK_WINDOW (shell_window));
+}
+
+static void
+action_memo_list_print_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ETable *table;
+ GtkPrintOperationAction print_action;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ table = e_memo_table_get_table (memo_table);
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ print_table (table, _("Print Memos"), _("Memos"), print_action);
+}
+
+static void
+action_memo_list_print_preview_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ETable *table;
+ GtkPrintOperationAction print_action;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ table = e_memo_table_get_table (memo_table);
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
+ print_table (table, _("Print Memos"), _("Memos"), print_action);
+}
+
+static void
+action_memo_list_properties_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESource *source;
+ ESourceSelector *selector;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ calendar_setup_edit_memo_list (GTK_WINDOW (shell_window), source);
+}
+
+static void
+action_memo_list_rename_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ESourceSelector *selector;
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ e_source_selector_edit_primary_selection (selector);
+}
+
+static void
+action_memo_list_select_one_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *primary;
+ GSList *list, *iter;
+
+ /* XXX ESourceSelector should provide a function for this. */
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+ primary = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (primary != NULL);
+
+ list = e_source_selector_get_selection (selector);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+
+ if (source == primary)
+ continue;
+
+ e_source_selector_unselect_source (selector, source);
+ }
+ e_source_selector_free_selection (list);
+
+ e_source_selector_select_source (selector, primary);
+}
+
+static void
+action_memo_new_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECal *client;
+ ECalComponent *comp;
+ CompEditor *editor;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ client = comp_data->client;
+ editor = memo_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
+ comp = cal_comp_memo_new_with_defaults (client);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+ g_object_unref (client);
+}
+
+static void
+action_memo_open_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected memo. */
+ e_memo_shell_view_open_memo (memo_shell_view, comp_data);
+}
+
+static void
+action_memo_open_url_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ icalproperty *prop;
+ const gchar *uri;
+ GSList *list;
+
+ 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;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the URI of the first selected memo. */
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ g_return_if_fail (prop == NULL);
+
+ uri = icalproperty_get_url (prop);
+ e_show_uri (GTK_WINDOW (shell_window), uri);
+}
+
+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)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GtkPrintOperationAction print_action;
+ GSList *list;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only print the first selected memo. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ e_cal_component_set_icalcomponent (comp, clone);
+ print_comp (comp, comp_data->client, print_action);
+ g_object_unref (comp);
+}
+
+static void
+action_memo_save_as_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+ gchar *filename;
+ gchar *string;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ list = e_memo_table_get_selected (memo_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ filename = e_file_dialog_save (_("Save as..."), NULL);
+ if (filename == NULL)
+ return;
+
+ /* XXX We only save the first selected memo. */
+ string = e_cal_get_component_as_string (
+ comp_data->client, comp_data->icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert memo to a string");
+ return;
+ }
+
+ e_write_file_uri (filename, string);
+
+ g_free (filename);
+ g_free (string);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+ EMemoShellView *memo_shell_view)
+{
+ EShellView *shell_view;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with executing the search. */
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ e_memo_shell_view_execute_search (memo_shell_view);
+}
+
+static void
+action_search_filter_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMemoShellView *memo_shell_view)
+{
+ e_memo_shell_view_execute_search (memo_shell_view);
+}
+
+static GtkActionEntry memo_entries[] = {
+
+ { "memo-clipboard-copy",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy selected memo"),
+ G_CALLBACK (action_memo_clipboard_copy_cb) },
+
+ { "memo-clipboard-cut",
+ GTK_STOCK_CUT,
+ NULL,
+ NULL,
+ N_("Cut selected memo"),
+ G_CALLBACK (action_memo_clipboard_cut_cb) },
+
+ { "memo-clipboard-paste",
+ GTK_STOCK_PASTE,
+ NULL,
+ NULL,
+ N_("Paste memo from the clipboard"),
+ G_CALLBACK (action_memo_clipboard_paste_cb) },
+
+ { "memo-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete Memo"),
+ NULL,
+ N_("Delete selected memos"),
+ G_CALLBACK (action_memo_delete_cb) },
+
+ { "memo-forward",
+ "mail-forward",
+ N_("_Forward as iCalendar..."),
+ "<Control>f",
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_forward_cb) },
+
+ { "memo-list-copy",
+ GTK_STOCK_COPY,
+ N_("_Copy..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_list_copy_cb) },
+
+ { "memo-list-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_list_delete_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",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_list_properties_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-new",
+ "stock_insert-note",
+ N_("New _Memo"),
+ NULL,
+ N_("Create a new memo"),
+ G_CALLBACK (action_memo_new_cb) },
+
+ { "memo-open",
+ GTK_STOCK_OPEN,
+ N_("_Open Memo"),
+ "<Control>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) },
+
+ { "memo-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_memo_save_as_cb) }
+};
+
+static EPopupActionEntry memo_popup_entries[] = {
+
+ { "memo-list-popup-copy",
+ NULL,
+ "memo-list-copy" },
+
+ { "memo-list-popup-delete",
+ NULL,
+ "memo-list-delete" },
+
+ { "memo-list-popup-properties",
+ NULL,
+ "memo-list-properties" },
+
+ { "memo-list-popup-rename",
+ NULL,
+ "memo-list-rename" },
+
+ { "memo-list-popup-select-one",
+ NULL,
+ "memo-list-select-one" },
+
+ { "memo-popup-clipboard-copy",
+ NULL,
+ "memo-clipboard-copy" },
+
+ { "memo-popup-clipboard-cut",
+ NULL,
+ "memo-clipboard-cut" },
+
+ { "memo-popup-clipboard-paste",
+ NULL,
+ "memo-clipboard-paste" },
+
+ { "memo-popup-delete",
+ NULL,
+ "memo-delete" },
+
+ { "memo-popup-forward",
+ NULL,
+ "memo-forward" },
+
+ { "memo-popup-open",
+ NULL,
+ "memo-open" },
+
+ { "memo-popup-open-url",
+ NULL,
+ "memo-open-url" },
+
+ { "memo-popup-save-as",
+ NULL,
+ "memo-save-as" }
+};
+
+static GtkToggleActionEntry memo_toggle_entries[] = {
+
+ { "memo-preview",
+ NULL,
+ N_("Memo _Preview"),
+ "<Control>m",
+ N_("Show memo preview pane"),
+ G_CALLBACK (action_memo_preview_cb),
+ TRUE }
+};
+
+static GtkRadioActionEntry memo_filter_entries[] = {
+
+ { "memo-filter-any-category",
+ NULL,
+ N_("Any Category"),
+ NULL,
+ NULL,
+ MEMO_FILTER_ANY_CATEGORY },
+
+ { "memo-filter-unmatched",
+ NULL,
+ N_("Unmatched"),
+ NULL,
+ NULL,
+ MEMO_FILTER_UNMATCHED }
+};
+
+static GtkRadioActionEntry memo_search_entries[] = {
+
+ { "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",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print the list of memos"),
+ G_CALLBACK (action_memo_list_print_cb) },
+
+ { "memo-list-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ NULL,
+ N_("Preview the list of memos to be printed"),
+ G_CALLBACK (action_memo_list_print_preview_cb) },
+
+ { "memo-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ N_("Print the selected memo"),
+ G_CALLBACK (action_memo_print_cb) }
+};
+
+static EPopupActionEntry lockdown_printing_popup_entries[] = {
+
+ { "memo-popup-print",
+ NULL,
+ "memo-print" }
+};
+
+void
+e_memo_shell_view_actions_init (EMemoShellView *memo_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+ GConfBridge *bridge;
+ GtkAction *action;
+ GObject *object;
+ const gchar *key;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (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_search_entries,
+ G_N_ELEMENTS (memo_search_entries),
+ MEMO_SEARCH_SUMMARY_CONTAINS,
+ NULL, NULL);
+
+ /* 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));
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (ACTION (MEMO_PREVIEW));
+ key = "/apps/evolution/calendar/display/show_memo_preview";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ /* Fine tuning. */
+
+ action = ACTION (MEMO_DELETE);
+ g_object_set (action, "short-label", _("Delete"), NULL);
+
+ g_signal_connect (
+ ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
+ G_CALLBACK (action_gal_save_custom_view_cb), memo_shell_view);
+
+ g_signal_connect (
+ ACTION (SEARCH_EXECUTE), "activate",
+ G_CALLBACK (action_search_execute_cb), memo_shell_view);
+}
+
+void
+e_memo_shell_view_update_search_filter (EMemoShellView *memo_shell_view)
+{
+ EShellContent *shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GList *list, *iter;
+ GSList *group;
+ gint ii;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_content = e_shell_view_get_shell_content (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);
+
+ /* Add the standard filter actions. */
+ gtk_action_group_add_radio_actions (
+ action_group, memo_filter_entries,
+ G_N_ELEMENTS (memo_filter_entries),
+ MEMO_FILTER_ANY_CATEGORY,
+ G_CALLBACK (action_search_filter_cb),
+ memo_shell_view);
+
+ /* 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);
+
+ /* Build the category actions. */
+
+ list = e_categories_get_list ();
+ for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+ const gchar *category_name = iter->data;
+ const gchar *filename;
+ GtkAction *action;
+ gchar *action_name;
+
+ 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);
+
+ /* Convert the category icon file to a themed icon name. */
+ filename = e_categories_get_icon_file_for (category_name);
+ if (filename != NULL && *filename != '\0') {
+ gchar *basename;
+ gchar *cp;
+
+ basename = g_path_get_basename (filename);
+
+ /* Lose the file extension. */
+ if ((cp = strrchr (basename, '.')) != NULL)
+ *cp = '\0';
+
+ g_object_set (
+ radio_action, "icon-name", basename, NULL);
+
+ g_free (basename);
+ }
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_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_list_free (list);
+
+ /* Use any action in the group; doesn't matter which. */
+ e_shell_content_set_filter_action (shell_content, radio_action);
+
+ ii = MEMO_FILTER_UNMATCHED;
+ e_shell_content_add_filter_separator_after (shell_content, ii);
+}
diff --cc calendar/module/e-memo-shell-view-actions.h
index 97fd9a6,0000000..d6fd3ca
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view-actions.h
+++ b/calendar/module/e-memo-shell-view-actions.h
@@@ -1,87 -1,0 +1,87 @@@
+/*
+ * e-memo-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_VIEW_ACTIONS_H
+#define E_MEMO_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* Memo Actions */
+#define E_SHELL_WINDOW_ACTION_MEMO_CLIPBOARD_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-clipboard-copy")
+#define E_SHELL_WINDOW_ACTION_MEMO_CLIPBOARD_CUT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-clipboard-cut")
+#define E_SHELL_WINDOW_ACTION_MEMO_CLIPBOARD_PASTE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-clipboard-paste")
+#define E_SHELL_WINDOW_ACTION_MEMO_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-delete")
+#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")
+
+/* 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_RENAME(window) \
+ E_SHELL_WINDOW_ACTION ((window), "memo-list-rename")
+#define E_SHELL_WINDOW_ACTION_MEMO_LIST_SELECT_ONE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "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_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")
+
+#endif /* E_MEMO_SHELL_VIEW_ACTIONS_H */
diff --cc calendar/module/e-memo-shell-view-private.c
index dbb474a,0000000..69d6c0a
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view-private.c
+++ b/calendar/module/e-memo-shell-view-private.c
@@@ -1,524 -1,0 +1,524 @@@
+/*
+ * e-memo-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-memo-shell-view-private.h"
+
+#include "widgets/menus/gal-view-factory-etable.h"
+
+static void
+memo_shell_view_table_popup_event_cb (EShellView *shell_view,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/memo-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+}
+
+static void
+memo_shell_view_table_user_created_cb (EMemoShellView *memo_shell_view,
+ EMemoTable *memo_table)
+{
+ EMemoShellSidebar *memo_shell_sidebar;
+ ECalModel *model;
+ ECal *client;
+ ESource *source;
+
+ /* This is the "Click to Add" handler. */
+
+ model = e_memo_table_get_model (memo_table);
+ client = e_cal_model_get_default_client (model);
+ source = e_cal_get_source (client);
+
+ memo_shell_sidebar = memo_shell_view->priv->memo_shell_sidebar;
+ e_memo_shell_sidebar_add_source (memo_shell_sidebar, source);
+
+ e_cal_model_add_client (model, client);
+}
+
+static void
+memo_shell_view_selector_client_added_cb (EMemoShellView *memo_shell_view,
+ ECal *client)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModel *model;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+
+ e_cal_model_add_client (model, client);
+}
+
+static void
+memo_shell_view_selector_client_removed_cb (EMemoShellView *memo_shell_view,
+ ECal *client)
+{
+ EMemoShellContent *memo_shell_content;
+ EMemoTable *memo_table;
+ ECalModel *model;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+
+ e_cal_model_remove_client (model, client);
+}
+
+static gboolean
+memo_shell_view_selector_popup_event_cb (EShellView *shell_view,
+ ESource *primary_source,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/memo-list-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+
+ return TRUE;
+}
+
+static void
+memo_shell_view_load_view_collection (EShellViewClass *shell_view_class)
+{
+ GalViewCollection *collection;
+ GalViewFactory *factory;
+ ETableSpecification *spec;
+ const gchar *base_dir;
+ gchar *filename;
+
+ collection = shell_view_class->view_collection;
+
+ base_dir = EVOLUTION_ETSPECDIR;
+ spec = e_table_specification_new ();
+ filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
+ if (!e_table_specification_load_from_file (spec, filename))
+ g_critical ("Unable to load ETable specification file "
+ "for memos");
+ g_free (filename);
+
+ factory = gal_view_factory_etable_new (spec);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+ g_object_unref (spec);
+
+ gal_view_collection_load (collection);
+}
+
+static void
+memo_shell_view_notify_view_id_cb (EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ view_instance =
+ e_memo_shell_content_get_view_instance (memo_shell_content);
+ view_id = e_shell_view_get_view_id (E_SHELL_VIEW (memo_shell_view));
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_memo_shell_view_private_init (EMemoShellView *memo_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ if (!gal_view_collection_loaded (shell_view_class->view_collection))
+ memo_shell_view_load_view_collection (shell_view_class);
+
+ g_signal_connect (
+ memo_shell_view, "notify::view-id",
+ G_CALLBACK (memo_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view)
+{
+ EMemoShellViewPrivate *priv = memo_shell_view->priv;
+ EMemoShellContent *memo_shell_content;
+ EMemoShellSidebar *memo_shell_sidebar;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EMemoTable *memo_table;
+ ECalModel *model;
+ ETable *table;
+ ESourceSelector *selector;
+
+ shell_view = E_SHELL_VIEW (memo_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);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ e_shell_window_add_action_group (shell_window, "memos");
+ e_shell_window_add_action_group (shell_window, "memos-filter");
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->memo_shell_backend = g_object_ref (shell_backend);
+ priv->memo_shell_content = g_object_ref (shell_content);
+ priv->memo_shell_sidebar = g_object_ref (shell_sidebar);
+
+ memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content);
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+ table = e_memo_table_get_table (memo_table);
+
+ memo_shell_sidebar = E_MEMO_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_memo_shell_sidebar_get_selector (memo_shell_sidebar);
+
+ g_signal_connect_swapped (
+ memo_table, "open-component",
+ G_CALLBACK (e_memo_shell_view_open_memo),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ memo_table, "popup-event",
+ G_CALLBACK (memo_shell_view_table_popup_event_cb),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ memo_table, "status-message",
+ G_CALLBACK (e_memo_shell_view_set_status_message),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ memo_table, "user-created",
+ G_CALLBACK (memo_shell_view_table_user_created_cb),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ model, "model-changed",
+ G_CALLBACK (e_memo_shell_view_update_sidebar),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ model, "model-rows-deleted",
+ G_CALLBACK (e_memo_shell_view_update_sidebar),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ model, "model-rows-inserted",
+ G_CALLBACK (e_memo_shell_view_update_sidebar),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ table, "selection-change",
+ G_CALLBACK (e_memo_shell_view_update_sidebar),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ memo_shell_sidebar, "client-added",
+ G_CALLBACK (memo_shell_view_selector_client_added_cb),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ memo_shell_sidebar, "client-removed",
+ G_CALLBACK (memo_shell_view_selector_client_removed_cb),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ memo_shell_sidebar, "status-message",
+ G_CALLBACK (e_memo_shell_view_set_status_message),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "popup-event",
+ G_CALLBACK (memo_shell_view_selector_popup_event_cb),
+ memo_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "primary-selection-changed",
+ G_CALLBACK (e_shell_view_update_actions),
+ memo_shell_view);
+
+ e_categories_register_change_listener (
+ G_CALLBACK (e_memo_shell_view_update_search_filter),
+ memo_shell_view);
+
+ e_memo_shell_view_actions_init (memo_shell_view);
+ e_memo_shell_view_update_sidebar (memo_shell_view);
+ e_memo_shell_view_update_search_filter (memo_shell_view);
+
+ e_memo_shell_view_execute_search (memo_shell_view);
+}
+
+void
+e_memo_shell_view_private_dispose (EMemoShellView *memo_shell_view)
+{
+ EMemoShellViewPrivate *priv = memo_shell_view->priv;
+
+ DISPOSE (priv->memo_shell_backend);
+ DISPOSE (priv->memo_shell_content);
+ DISPOSE (priv->memo_shell_sidebar);
+
+ if (memo_shell_view->priv->activity != NULL) {
+ /* XXX Activity is not cancellable. */
+ e_activity_complete (memo_shell_view->priv->activity);
+ g_object_unref (memo_shell_view->priv->activity);
+ memo_shell_view->priv->activity = NULL;
+ }
+}
+
+void
+e_memo_shell_view_private_finalize (EMemoShellView *memo_shell_view)
+{
+ /* XXX Nothing to do? */
+}
+
+void
+e_memo_shell_view_execute_search (EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ GtkAction *action;
+ GString *string;
+ ECalComponentPreview *memo_preview;
+ EMemoTable *memo_table;
+ ECalModel *model;
+ FilterRule *rule;
+ const gchar *format;
+ const gchar *text;
+ gchar *query;
+ gchar *temp;
+ gint value;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ text = e_shell_content_get_search_text (shell_content);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ action = ACTION (MEMO_SEARCH_ANY_FIELD_CONTAINS);
+ value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+
+ if (text == NULL || *text == '\0') {
+ text = "";
+ value = MEMO_SEARCH_SUMMARY_CONTAINS;
+ }
+
+ switch (value) {
+ default:
+ text = "";
+ /* fall through */
+
+ case MEMO_SEARCH_SUMMARY_CONTAINS:
+ format = "(contains? \"summary\" %s)";
+ break;
+
+ case MEMO_SEARCH_DESCRIPTION_CONTAINS:
+ format = "(contains? \"description\" %s)";
+ break;
+
+ case MEMO_SEARCH_ANY_FIELD_CONTAINS:
+ format = "(contains? \"any\" %s)";
+ break;
+ }
+
+ /* Build the query. */
+ string = g_string_new ("");
+ e_sexp_encode_string (string, text);
+ query = g_strdup_printf (format, string->str);
+ g_string_free (string, TRUE);
+
+ /* Apply selected filter. */
+ value = e_shell_content_get_filter_value (shell_content);
+ switch (value) {
+ case MEMO_FILTER_ANY_CATEGORY:
+ break;
+
+ case MEMO_FILTER_UNMATCHED:
+ temp = g_strdup_printf (
+ "(and (has-categories? #f) %s", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ {
+ GList *categories;
+ const gchar *category_name;
+
+ categories = e_categories_get_list ();
+ category_name = g_list_nth_data (categories, value);
+ g_list_free (categories);
+
+ temp = g_strdup_printf (
+ "(and (has-categories? \"%s\") %s)",
+ category_name, query);
+ g_free (query);
+ query = temp;
+ }
+ }
+
+ /* XXX This is wrong. We need to programmatically construct a
+ * FilterRule, tell it to build code, and pass the resulting
+ * expression string to ECalModel. */
+ rule = filter_rule_new ();
+ e_shell_content_set_search_rule (shell_content, rule);
+ g_object_unref (rule);
+
+ /* Submit the query. */
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+ model = e_memo_table_get_model (memo_table);
+ e_cal_model_set_search_query (model, query);
+ g_free (query);
+
+ memo_preview =
+ e_memo_shell_content_get_memo_preview (memo_shell_content);
+ e_cal_component_preview_clear (memo_preview);
+}
+
+void
+e_memo_shell_view_open_memo (EMemoShellView *memo_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_VIEW (memo_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ if (e_cal_component_has_organizer (comp))
+ flags |= COMP_EDITOR_IS_SHARED;
+
+ if (itip_organizer_is_user (comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = memo_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_memo_shell_view_set_status_message (EMemoShellView *memo_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_MEMO_SHELL_VIEW (memo_shell_view));
+
+ activity = memo_shell_view->priv->activity;
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_complete (activity);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new (status_message);
+ e_activity_set_percent (activity, percent);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_primary_text (activity, status_message);
+ }
+
+ memo_shell_view->priv->activity = activity;
+}
+
+void
+e_memo_shell_view_update_sidebar (EMemoShellView *memo_shell_view)
+{
+ EMemoShellContent *memo_shell_content;
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ EMemoTable *memo_table;
+ ECalModel *model;
+ ETable *table;
+ GString *string;
+ const gchar *format;
+ gint n_rows;
+ gint n_selected;
+
+ shell_view = E_SHELL_VIEW (memo_shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ memo_shell_content = memo_shell_view->priv->memo_shell_content;
+ memo_table = e_memo_shell_content_get_memo_table (memo_shell_content);
+
+ model = e_memo_table_get_model (memo_table);
+ table = e_memo_table_get_table (memo_table);
+
+ n_rows = e_table_model_row_count (E_TABLE_MODEL (model));
+ n_selected = e_table_selected_count (table);
+
+ string = g_string_sized_new (64);
+
+ format = ngettext ("%d memo", "%d memos", n_rows);
+ g_string_append_printf (string, format, n_rows);
+
+ if (n_selected > 0) {
+ format = _("%d selected");
+ g_string_append_len (string, ", ", 2);
+ g_string_append_printf (string, format, n_selected);
+ }
+
+ e_shell_sidebar_set_secondary_text (shell_sidebar, string->str);
+
+ g_string_free (string, TRUE);
+}
diff --cc calendar/module/e-memo-shell-view-private.h
index 04857ef,0000000..c41eaed
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view-private.h
+++ b/calendar/module/e-memo-shell-view-private.h
@@@ -1,126 -1,0 +1,126 @@@
+/*
+ * e-memo-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_VIEW_PRIVATE_H
+#define E_MEMO_SHELL_VIEW_PRIVATE_H
+
+#include "e-memo-shell-view.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libedataserver/e-categories.h>
+#include <libedataserver/e-sexp.h>
+
+#include "e-util/e-dialog-utils.h"
+#include "e-util/e-error.h"
+#include "e-util/e-util.h"
+#include "e-util/gconf-bridge.h"
+#include "widgets/misc/e-popup-action.h"
+
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-component-preview.h"
+#include "calendar/gui/e-calendar-selector.h"
+#include "calendar/gui/print.h"
+#include "calendar/gui/dialogs/calendar-setup.h"
+#include "calendar/gui/dialogs/copy-source-dialog.h"
+#include "calendar/gui/dialogs/memo-editor.h"
+
+#include "e-memo-shell-backend.h"
+#include "e-memo-shell-content.h"
+#include "e-memo-shell-sidebar.h"
+#include "e-memo-shell-view-actions.h"
+
+#define E_MEMO_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* For use in dispose() methods. */
+#define DISPOSE(obj) \
+ G_STMT_START { \
+ if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
+ } G_STMT_END
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "e-memo-table.etspec"
+
+G_BEGIN_DECLS
+
+/* Filter items are displayed in ascending order.
+ * Non-negative values are reserved for categories. */
+enum {
+ MEMO_FILTER_ANY_CATEGORY = -2,
+ MEMO_FILTER_UNMATCHED = -1
+};
+
+/* Search items are displayed in ascending order. */
+enum {
+ MEMO_SEARCH_SUMMARY_CONTAINS,
+ MEMO_SEARCH_DESCRIPTION_CONTAINS,
+ MEMO_SEARCH_ANY_FIELD_CONTAINS
+};
+
+struct _EMemoShellViewPrivate {
+
+ /* These are just for convenience. */
+ EMemoShellBackend *memo_shell_backend;
+ EMemoShellContent *memo_shell_content;
+ EMemoShellSidebar *memo_shell_sidebar;
+
+ EActivity *activity;
+};
+
+void e_memo_shell_view_private_init
+ (EMemoShellView *memo_shell_view,
+ EShellViewClass *shell_view_class);
+void e_memo_shell_view_private_constructed
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_private_dispose
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_private_finalize
+ (EMemoShellView *memo_shell_view);
+
+/* Private Utilities */
+
+void e_memo_shell_view_actions_init
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_execute_search
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_open_memo
+ (EMemoShellView *memo_shell_view,
+ ECalModelComponent *comp_data);
+void e_memo_shell_view_set_status_message
+ (EMemoShellView *memo_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+void e_memo_shell_view_update_sidebar
+ (EMemoShellView *memo_shell_view);
+void e_memo_shell_view_update_search_filter
+ (EMemoShellView *memo_shell_view);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_VIEW_PRIVATE_H */
diff --cc calendar/module/e-memo-shell-view.c
index 22c4472,0000000..e2964b0
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view.c
+++ b/calendar/module/e-memo-shell-view.c
@@@ -1,222 -1,0 +1,222 @@@
+/*
+ * e-memo-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-memo-shell-view-private.h"
+
+static gpointer parent_class;
+static GType memo_shell_view_type;
+
+static void
+memo_shell_view_dispose (GObject *object)
+{
+ e_memo_shell_view_private_dispose (E_MEMO_SHELL_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+memo_shell_view_finalize (GObject *object)
+{
+ e_memo_shell_view_private_finalize (E_MEMO_SHELL_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+memo_shell_view_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ e_memo_shell_view_private_constructed (E_MEMO_SHELL_VIEW (object));
+}
+
+static void
+memo_shell_view_update_actions (EShellView *shell_view)
+{
+ EMemoShellViewPrivate *priv;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ const gchar *label;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean any_memos_selected;
+ gboolean has_primary_source;
+ gboolean multiple_memos_selected;
+ gboolean primary_source_is_system;
+ gboolean selection_has_url;
+ gboolean single_memo_selected;
+ gboolean sources_are_editable;
+
+ priv = E_MEMO_SHELL_VIEW_GET_PRIVATE (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);
+
+ single_memo_selected =
+ (state & E_MEMO_SHELL_CONTENT_SELECTION_SINGLE);
+ multiple_memos_selected =
+ (state & E_MEMO_SHELL_CONTENT_SELECTION_MULTIPLE);
+ sources_are_editable =
+ (state & E_MEMO_SHELL_CONTENT_SELECTION_CAN_EDIT);
+ selection_has_url =
+ (state & E_MEMO_SHELL_CONTENT_SELECTION_HAS_URL);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ state = e_shell_sidebar_check_state (shell_sidebar);
+
+ has_primary_source =
+ (state & E_MEMO_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+ primary_source_is_system =
+ (state & E_MEMO_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM);
+
+ any_memos_selected =
+ (single_memo_selected || multiple_memos_selected);
+
+ action = ACTION (MEMO_CLIPBOARD_COPY);
+ sensitive = any_memos_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_CLIPBOARD_CUT);
+ sensitive = any_memos_selected && sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_CLIPBOARD_PASTE);
+ sensitive = sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_DELETE);
+ sensitive = any_memos_selected && sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+ if (multiple_memos_selected)
+ label = _("Delete Memos");
+ else
+ label = _("Delete Memo");
+ g_object_set (action, "label", label, NULL);
+
+ action = ACTION (MEMO_FORWARD);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_COPY);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_DELETE);
+ sensitive = has_primary_source && !primary_source_is_system;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_PROPERTIES);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_LIST_RENAME);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_OPEN);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_OPEN_URL);
+ sensitive = single_memo_selected && selection_has_url;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_PRINT);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MEMO_SAVE_AS);
+ sensitive = single_memo_selected;
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+memo_shell_view_class_init (EMemoShellViewClass *class,
+ GTypeModule *type_module)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMemoShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = memo_shell_view_dispose;
+ object_class->finalize = memo_shell_view_finalize;
+ object_class->constructed = memo_shell_view_constructed;
+
+ 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_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_memo_shell_sidebar_new;
+ shell_view_class->update_actions = memo_shell_view_update_actions;
+}
+
+static void
+memo_shell_view_init (EMemoShellView *memo_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ memo_shell_view->priv =
+ E_MEMO_SHELL_VIEW_GET_PRIVATE (memo_shell_view);
+
+ e_memo_shell_view_private_init (memo_shell_view, shell_view_class);
+}
+
+GType
+e_memo_shell_view_get_type (void)
+{
+ return memo_shell_view_type;
+}
+
+void
+e_memo_shell_view_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EMemoShellViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) memo_shell_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ type_module,
+ sizeof (EMemoShellView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) memo_shell_view_init,
+ NULL /* value_table */
+ };
+
+ memo_shell_view_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_VIEW,
+ "EMemoShellView", &type_info, 0);
+}
diff --cc calendar/module/e-memo-shell-view.h
index 0cbaa7b,0000000..686ae73
mode 100644,000000..100644
--- a/calendar/module/e-memo-shell-view.h
+++ b/calendar/module/e-memo-shell-view.h
@@@ -1,67 -1,0 +1,67 @@@
+/*
+ * e-memo-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MEMO_SHELL_VIEW_H
+#define E_MEMO_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+#include <libedataserver/e-source-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MEMO_SHELL_VIEW \
+ (e_memo_shell_view_get_type ())
+#define E_MEMO_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellView))
+#define E_MEMO_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewClass))
+#define E_IS_MEMO_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MEMO_SHELL_VIEW))
+#define E_IS_MEMO_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MEMO_SHELL_VIEW))
+#define E_MEMO_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MEMO_SHELL_VIEW, EMemoShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMemoShellView EMemoShellView;
+typedef struct _EMemoShellViewClass EMemoShellViewClass;
+typedef struct _EMemoShellViewPrivate EMemoShellViewPrivate;
+
+struct _EMemoShellView {
+ EShellView parent;
+ EMemoShellViewPrivate *priv;
+};
+
+struct _EMemoShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_memo_shell_view_get_type (void);
+void e_memo_shell_view_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_MEMO_SHELL_VIEW_H */
diff --cc calendar/module/e-task-shell-backend.c
index 9e35b47,0000000..6bded3e
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-backend.c
+++ b/calendar/module/e-task-shell-backend.c
@@@ -1,621 -1,0 +1,621 @@@
+/*
+ * e-task-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-task-shell-backend.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/e-cal.h>
+#include <libedataserver/e-url.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-source-group.h>
+
+#include "shell/e-shell.h"
+#include "shell/e-shell-backend.h"
+#include "shell/e-shell-window.h"
+
+#include "calendar/common/authentication.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/dialogs/calendar-setup.h"
+#include "calendar/gui/dialogs/task-editor.h"
+
+#include "e-task-shell-content.h"
+#include "e-task-shell-migrate.h"
+#include "e-task-shell-sidebar.h"
+#include "e-task-shell-view.h"
+
+#define E_TASK_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendPrivate))
+
+#define WEB_BASE_URI "webcal://"
+#define PERSONAL_RELATIVE_URI "system"
+
+struct _ETaskShellBackendPrivate {
+ ESourceList *source_list;
+};
+
+enum {
+ PROP_0,
+ PROP_SOURCE_LIST
+};
+
+static gpointer parent_class;
+static GType task_shell_backend_type;
+
+static void
+task_module_ensure_sources (EShellBackend *shell_backend)
+{
+ /* XXX This is basically the same algorithm across all modules.
+ * Maybe we could somehow integrate this into EShellBackend? */
+
+ ETaskShellBackendPrivate *priv;
+ ESourceGroup *on_this_computer;
+ ESourceGroup *on_the_web;
+ ESource *personal;
+ GSList *groups, *iter;
+ const gchar *data_dir;
+ const gchar *name;
+ gchar *base_uri;
+ gchar *filename;
+
+ on_this_computer = NULL;
+ on_the_web = NULL;
+ personal = NULL;
+
+ priv = E_TASK_SHELL_BACKEND_GET_PRIVATE (shell_backend);
+
+ if (!e_cal_get_sources (&priv->source_list, E_CAL_SOURCE_TYPE_TODO, NULL)) {
+ g_warning ("Could not get task sources from GConf!");
+ return;
+ }
+
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ filename = g_build_filename (data_dir, "local", NULL);
+ base_uri = g_filename_to_uri (filename, NULL, NULL);
+ g_free (filename);
+
+ groups = e_source_list_peek_groups (priv->source_list);
+ for (iter = groups; iter != NULL; iter = iter->next) {
+ ESourceGroup *source_group = iter->data;
+ const gchar *group_base_uri;
+
+ group_base_uri = e_source_group_peek_base_uri (source_group);
+
+ /* Compare only "file://" part. If the user's home
+ * changes, we do not want to create another group. */
+ if (on_this_computer == NULL &&
+ strncmp (base_uri, group_base_uri, 7) == 0)
+ on_this_computer = source_group;
+
+ else if (on_the_web == NULL &&
+ strcmp (WEB_BASE_URI, group_base_uri) == 0)
+ on_the_web = source_group;
+ }
+
+ name = _("On This Computer");
+
+ if (on_this_computer != NULL) {
+ GSList *sources;
+ const gchar *group_base_uri;
+
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (on_this_computer, name);
+
+ sources = e_source_group_peek_sources (on_this_computer);
+ group_base_uri = e_source_group_peek_base_uri (on_this_computer);
+
+ /* Make sure this group includes a "Personal" source. */
+ for (iter = sources; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (relative_uri == NULL)
+ continue;
+
+ if (strcmp (PERSONAL_RELATIVE_URI, relative_uri) != 0)
+ continue;
+
+ personal = source;
+ break;
+ }
+
+ /* Make sure we have the correct base URI. This can
+ * change when the user's home directory changes. */
+ if (strcmp (base_uri, group_base_uri) != 0) {
+ e_source_group_set_base_uri (
+ on_this_computer, base_uri);
+
+ /* XXX We shouldn't need this sync call here as
+ * set_base_uri() results in synching to GConf,
+ * but that happens in an idle loop and too late
+ * to prevent the user from seeing a "Cannot
+ * Open ... because of invalid URI" error. */
+ e_source_list_sync (priv->source_list, NULL);
+ }
+
+ } else {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, base_uri);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ }
+
+ name = _("Personal");
+
+ if (personal == NULL) {
+ ESource *source;
+ GSList *selected;
+ gchar *primary;
+
+ source = e_source_new (name, PERSONAL_RELATIVE_URI);
+ e_source_group_add_source (on_this_computer, source, -1);
+ g_object_unref (source);
+
+ primary = calendar_config_get_primary_tasks ();
+ selected = calendar_config_get_tasks_selected ();
+
+ if (primary == NULL && selected == NULL) {
+ const gchar *uid;
+
+ uid = e_source_peek_uid (source);
+ selected = g_slist_prepend (NULL, g_strdup (uid));
+
+ calendar_config_set_primary_tasks (uid);
+ calendar_config_set_tasks_selected (selected);
+ }
+
+ g_slist_foreach (selected, (GFunc) g_free, NULL);
+ g_slist_free (selected);
+ g_free (primary);
+ } else {
+ /* Force the source name to the current locale. */
+ e_source_set_name (personal, name);
+ }
+
+ name = _("On The Web");
+
+ if (on_the_web == NULL) {
+ ESourceGroup *source_group;
+
+ source_group = e_source_group_new (name, WEB_BASE_URI);
+ e_source_list_add_group (priv->source_list, source_group, -1);
+ g_object_unref (source_group);
+ } else {
+ /* Force the group name to the current locale. */
+ e_source_group_set_name (on_the_web, name);
+ }
+
+ g_free (base_uri);
+}
+
+static void
+task_module_cal_opened_cb (ECal *cal,
+ ECalendarStatus status,
+ GtkAction *action)
+{
+ EShell *shell;
+ ECalComponent *comp;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ const gchar *action_name;
+
+ /* FIXME Pass this in. */
+ shell = e_shell_get_default ();
+
+ /* XXX Handle errors better. */
+ if (status != E_CALENDAR_STATUS_OK)
+ return;
+
+ action_name = gtk_action_get_name (action);
+
+ flags |= COMP_EDITOR_NEW_ITEM;
+ if (strcmp (action_name, "task-assigned-new") == 0) {
+ flags |= COMP_EDITOR_IS_ASSIGNED;
+ flags |= COMP_EDITOR_USER_ORG;
+ }
+
+ editor = task_editor_new (cal, shell, flags);
+ comp = cal_comp_task_new_with_defaults (cal);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (comp);
+ g_object_unref (cal);
+}
+
+static void
+action_task_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ ECal *cal = NULL;
+ ECalSourceType source_type;
+ ESourceList *source_list;
+ gchar *uid;
+
+ /* This callback is used for both tasks and assigned tasks. */
+
+ source_type = E_CAL_SOURCE_TYPE_TODO;
+
+ if (!e_cal_get_sources (&source_list, source_type, NULL)) {
+ g_warning ("Could not get task sources from GConf!");
+ return;
+ }
+
+ uid = calendar_config_get_primary_tasks ();
+
+ if (uid != NULL) {
+ ESource *source;
+
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ if (source != NULL)
+ cal = auth_new_cal_from_source (source, source_type);
+ g_free (uid);
+ }
+
+ if (cal == NULL)
+ cal = auth_new_cal_from_default (source_type);
+
+ g_return_if_fail (cal != NULL);
+
+ g_signal_connect (
+ cal, "cal-opened",
+ G_CALLBACK (task_module_cal_opened_cb), action);
+
+ e_cal_open_async (cal, FALSE);
+}
+
+static void
+action_task_list_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ calendar_setup_new_task_list (GTK_WINDOW (shell_window));
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "task-new",
+ "stock_task",
+ NC_("New", "_Task"),
+ "<Shift><Control>t",
+ N_("Create a new task"),
+ G_CALLBACK (action_task_new_cb) },
+
+ { "task-assigned-new",
+ "stock_task",
+ N_("Assigne_d Task"),
+ NULL,
+ 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
+task_module_handle_uri_cb (EShellBackend *shell_backend,
+ const gchar *uri)
+{
+ EShell *shell;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECal *client;
+ ECalComponent *comp;
+ ESource *source;
+ ESourceList *source_list;
+ ECalSourceType source_type;
+ EUri *euri;
+ icalcomponent *icalcomp;
+ icalproperty *icalprop;
+ const gchar *cp;
+ gchar *source_uid = NULL;
+ gchar *comp_uid = NULL;
+ gchar *comp_rid = NULL;
+ gboolean handled = FALSE;
+ GError *error = NULL;
+
+ source_type = E_CAL_SOURCE_TYPE_TODO;
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ if (strncmp (uri, "task:", 5) != 0)
+ return FALSE;
+
+ euri = e_uri_new (uri);
+ cp = euri->query;
+ if (cp == NULL)
+ goto exit;
+
+ while (*cp != '\0') {
+ gchar *header;
+ gchar *content;
+ gsize header_len;
+ gsize content_len;
+
+ header_len = strcspn (cp, "=&");
+
+ /* If it's malformed, give up. */
+ if (cp[header_len] != '=')
+ break;
+
+ header = (gchar *) cp;
+ header[header_len] = '\0';
+ cp += header_len + 1;
+
+ content_len = strcspn (cp, "&");
+
+ content = g_strndup (cp, content_len);
+ if (g_ascii_strcasecmp (header, "source-uid") == 0)
+ source_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-uid") == 0)
+ comp_uid = g_strdup (content);
+ else if (g_ascii_strcasecmp (header, "comp-rid") == 0)
+ comp_rid = g_strdup (content);
+ g_free (content);
+
+ cp += content_len;
+ if (*cp == '&') {
+ cp++;
+ if (strcmp (cp, "amp;") == 0)
+ cp += 4;
+ }
+ }
+
+ if (source_uid != NULL || comp_uid != NULL)
+ goto exit;
+
+ /* URI is valid, so consider it handled. Whether
+ * we successfully open it is another matter... */
+ handled = TRUE;
+
+ if (!e_cal_get_sources (&source_list, source_type, NULL)) {
+ g_printerr ("Could not get task sources from GConf!\n");
+ goto exit;
+ }
+
+ source = e_source_list_peek_source_by_uid (source_list, source_uid);
+ if (source == NULL) {
+ g_printerr ("No source for UID `%s'\n", source_uid);
+ g_object_unref (source_list);
+ goto exit;
+ }
+
+ client = auth_new_cal_from_source (source, source_type);
+ if (client == NULL || !e_cal_open (client, TRUE, &error)) {
+ g_printerr ("%s\n", error->message);
+ g_object_unref (source_list);
+ g_error_free (error);
+ goto exit;
+ }
+
+ /* XXX Copied from e_task_shell_view_open_task().
+ * Clearly a new utility function is needed. */
+
+ editor = comp_editor_find_instance (comp_uid);
+
+ if (editor != NULL)
+ goto present;
+
+ if (!e_cal_get_object (client, comp_uid, comp_rid, &icalcomp, &error)) {
+ g_printerr ("%s\n", error->message);
+ g_object_unref (source_list);
+ g_error_free (error);
+ goto exit;
+ }
+
+ comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (comp, icalcomp);
+
+ icalprop = icalcomponent_get_first_property (
+ icalcomp, ICAL_ATTENDEE_PROPERTY);
+ if (icalprop != NULL)
+ flags |= COMP_EDITOR_IS_ASSIGNED;
+
+ if (itip_organizer_is_user (comp, client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = task_editor_new (client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_unref (comp);
+
+present:
+ gtk_window_present (GTK_WINDOW (editor));
+
+ g_object_unref (source_list);
+ g_object_unref (client);
+
+exit:
+ g_free (source_uid);
+ g_free (comp_uid);
+ g_free (comp_rid);
+
+ e_uri_free (euri);
+
+ return handled;
+}
+
+static void
+task_module_window_created_cb (EShellBackend *shell_backend,
+ GtkWindow *window)
+{
+ const gchar *module_name;
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ module_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), module_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), module_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+}
+
+static void
+task_shell_backend_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE_LIST:
+ g_value_set_object (
+ value,
+ e_task_shell_backend_get_source_list (
+ E_TASK_SHELL_BACKEND (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_backend_dispose (GObject *object)
+{
+ ETaskShellBackendPrivate *priv;
+
+ priv = E_TASK_SHELL_BACKEND_GET_PRIVATE (object);
+
+ if (priv->source_list != NULL) {
+ g_object_unref (priv->source_list);
+ priv->source_list = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+task_shell_backend_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ task_module_ensure_sources (shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "handle-uri",
+ G_CALLBACK (task_module_handle_uri_cb), shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-created",
+ G_CALLBACK (task_module_window_created_cb), shell_backend);
+}
+
+static void
+task_shell_backend_class_init (ETaskShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETaskShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = task_shell_backend_get_property;
+ object_class->dispose = task_shell_backend_dispose;
+ object_class->constructed = task_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_TASK_SHELL_VIEW;
+ shell_backend_class->name = "tasks";
+ shell_backend_class->aliases = "";
+ shell_backend_class->schemes = "task";
+ shell_backend_class->sort_order = 600;
+ shell_backend_class->start = NULL;
+ shell_backend_class->is_busy = NULL;
+ shell_backend_class->shutdown = NULL;
+ shell_backend_class->migrate = e_task_shell_backend_migrate;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SOURCE_LIST,
+ g_param_spec_object (
+ "source-list",
+ _("Source List"),
+ _("The registry of task lists"),
+ E_TYPE_SOURCE_LIST,
+ G_PARAM_READABLE));
+}
+
+static void
+task_shell_backend_init (ETaskShellBackend *task_shell_backend)
+{
+ task_shell_backend->priv =
+ E_TASK_SHELL_BACKEND_GET_PRIVATE (task_shell_backend);
+}
+
+GType
+e_task_shell_backend_get_type (void)
+{
+ return task_shell_backend_type;
+}
+
+void
+e_task_shell_backend_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (ETaskShellBackendClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) task_shell_backend_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ETaskShellBackend),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) task_shell_backend_init,
+ NULL /* value_table */
+ };
+
+ task_shell_backend_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_BACKEND,
+ "ETaskShellBackend", &type_info, 0);
+}
+
+ESourceList *
+e_task_shell_backend_get_source_list (ETaskShellBackend *task_shell_backend)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_BACKEND (task_shell_backend), NULL);
+
+ return task_shell_backend->priv->source_list;
+}
diff --cc calendar/module/e-task-shell-backend.h
index edb56f2,0000000..63b157a
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-backend.h
+++ b/calendar/module/e-task-shell-backend.h
@@@ -1,70 -1,0 +1,70 @@@
+/*
+ * e-task-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_BACKEND_H
+#define E_TASK_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+#include <libedataserver/e-source-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TASK_SHELL_BACKEND \
+ (e_task_shell_backend_get_type ())
+#define E_TASK_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackend))
+#define E_TASK_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendClass))
+#define E_IS_TASK_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TASK_SHELL_BACKEND))
+#define E_IS_TASK_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TASK_SHELL_BACKEND))
+#define E_TASK_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TASK_SHELL_BACKEND, ETaskShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETaskShellBackend ETaskShellBackend;
+typedef struct _ETaskShellBackendClass ETaskShellBackendClass;
+typedef struct _ETaskShellBackendPrivate ETaskShellBackendPrivate;
+
+struct _ETaskShellBackend {
+ EShellBackend parent;
+ ETaskShellBackendPrivate *priv;
+};
+
+struct _ETaskShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+GType e_task_shell_backend_get_type (void);
+void e_task_shell_backend_register_type
+ (GTypeModule *type_module);
+ESourceList * e_task_shell_backend_get_source_list
+ (ETaskShellBackend *task_shell_backend);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_BACKEND_H */
diff --cc calendar/module/e-task-shell-content.c
index 280bc7c,0000000..0177c6c
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-content.c
+++ b/calendar/module/e-task-shell-content.c
@@@ -1,700 -1,0 +1,700 @@@
+/*
+ * e-task-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-task-shell-content.h"
+
+#include <glib/gi18n.h>
+
+#include "e-util/gconf-bridge.h"
+
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-model-tasks.h"
+#include "calendar/gui/e-calendar-table.h"
+#include "calendar/gui/e-calendar-table-config.h"
+
+#include "widgets/menus/gal-view-etable.h"
+
+#define E_TASK_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentPrivate))
+
+#define E_CALENDAR_TABLE_DEFAULT_STATE \
+ "<?xml version=\"1.0\"?>" \
+ "<ETableState>" \
+ " <column source=\"13\"/>" \
+ " <column source=\"14\"/>" \
+ " <column source=\"9\"/>" \
+ " <column source=\"5\"/>" \
+ " <grouping/>" \
+ "</ETableState>"
+
+struct _ETaskShellContentPrivate {
+ GtkWidget *paned;
+ GtkWidget *task_table;
+ GtkWidget *task_preview;
+
+ ECalModel *task_model;
+ ECalendarTableConfig *table_config;
+ GalViewInstance *view_instance;
+
+ gchar *current_uid;
+};
+
+enum {
+ PROP_0,
+ PROP_MODEL,
+ PROP_PREVIEW_VISIBLE
+};
+
+enum {
+ TARGET_VCALENDAR
+};
+
+static GtkTargetEntry drag_types[] = {
- { "text/calendar", 0, TARGET_VCALENDAR },
- { "text/x-calendar", 0, TARGET_VCALENDAR }
++ { (gchar *) "text/calendar", 0, TARGET_VCALENDAR },
++ { (gchar *) "text/x-calendar", 0, TARGET_VCALENDAR }
+};
+
+static gpointer parent_class;
+static GType task_shell_content_type;
+
+static void
+task_shell_content_display_view_cb (ETaskShellContent *task_shell_content,
+ GalView *gal_view)
+{
+ ECalendarTable *task_table;
+ ETable *table;
+
+ if (!GAL_IS_VIEW_ETABLE (gal_view))
+ return;
+
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ table = e_calendar_table_get_table (task_table);
+
+ gal_view_etable_attach_table (GAL_VIEW_ETABLE (gal_view), table);
+}
+
+static void
+task_shell_content_table_foreach_cb (gint model_row,
+ gpointer user_data)
+{
+ ECalModelComponent *comp_data;
+ icalcomponent *clone;
+ icalcomponent *vcal;
+ gchar *string;
+
+ struct {
+ ECalModel *model;
+ GSList *list;
+ } *foreach_data = user_data;
+
+ comp_data = e_cal_model_get_component_at (
+ foreach_data->model, model_row);
+
+ vcal = e_cal_util_new_top_level ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_util_add_timezones_from_component (vcal, comp_data->icalcomp);
+ icalcomponent_add_component (vcal, clone);
+
+ /* String is owned by libical; do not free. */
+ string = icalcomponent_as_ical_string (vcal);
+ if (string != NULL) {
+ ESource *source;
+ const gchar *source_uid;
+
+ source = e_cal_get_source (comp_data->client);
+ source_uid = e_source_peek_uid (source);
+
+ foreach_data->list = g_slist_prepend (
+ foreach_data->list,
+ g_strdup_printf ("%s\n%s", source_uid, string));
+ }
+
+ icalcomponent_free (vcal);
+}
+
+static void
+task_shell_content_table_drag_data_get_cb (ETaskShellContent *task_shell_content,
+ gint row,
+ gint col,
+ GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info,
+ guint time)
+{
+ ECalendarTable *task_table;
+ ETable *table;
+
+ struct {
+ ECalModel *model;
+ GSList *list;
+ } foreach_data;
+
+ if (info != TARGET_VCALENDAR)
+ return;
+
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ table = e_calendar_table_get_table (task_table);
+
+ foreach_data.model = e_calendar_table_get_model (task_table);
+ foreach_data.list = NULL;
+
+ e_table_selected_row_foreach (
+ table, task_shell_content_table_foreach_cb,
+ &foreach_data);
+
+ if (foreach_data.list != NULL) {
+ cal_comp_selection_set_string_list (
+ selection_data, foreach_data.list);
+ g_slist_foreach (foreach_data.list, (GFunc) g_free, NULL);
+ g_slist_free (foreach_data.list);
+ }
+}
+
+static void
+task_shell_content_table_drag_data_delete_cb (ETaskShellContent *task_shell_content,
+ gint row,
+ gint col,
+ GdkDragContext *context)
+{
+ /* Moved components are deleted from source immediately when moved,
+ * because some of them can be part of destination source, and we
+ * don't want to delete not-moved tasks. There is no such information
+ * which event has been moved and which not, so skip this method. */
+}
+
+static void
+task_shell_content_cursor_change_cb (ETaskShellContent *task_shell_content,
+ gint row,
+ ETable *table)
+{
+ ECalComponentPreview *task_preview;
+ ECalendarTable *task_table;
+ ECalModel *task_model;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ const gchar *uid;
+
+ task_model = e_task_shell_content_get_task_model (task_shell_content);
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ task_preview = e_task_shell_content_get_task_preview (task_shell_content);
+
+ if (e_table_selected_count (table) != 1) {
+ e_cal_component_preview_clear (task_preview);
+ return;
+ }
+
+ row = e_table_get_cursor_row (table);
+ comp_data = e_cal_model_get_component_at (task_model, row);
+
+ comp = e_cal_component_new ();
+ e_cal_component_set_icalcomponent (
+ comp, icalcomponent_new_clone (comp_data->icalcomp));
+ e_cal_component_preview_display (
+ task_preview, comp_data->client, comp);
+
+ e_cal_component_get_uid (comp, &uid);
+ g_free (task_shell_content->priv->current_uid);
+ task_shell_content->priv->current_uid = g_strdup (uid);
+
+ g_object_unref (comp);
+}
+
+static void
+task_shell_content_selection_change_cb (ETaskShellContent *task_shell_content,
+ ETable *table)
+{
+ ECalComponentPreview *task_preview;
+
+ task_preview = e_task_shell_content_get_task_preview (task_shell_content);
+
+ if (e_table_selected_count (table) != 1)
+ e_cal_component_preview_clear (task_preview);
+}
+
+static void
+task_shell_content_model_row_changed_cb (ETaskShellContent *task_shell_content,
+ gint row,
+ ETableModel *model)
+{
+ ECalModelComponent *comp_data;
+ ECalendarTable *task_table;
+ ETable *table;
+ const gchar *current_uid;
+ const gchar *uid;
+
+ current_uid = task_shell_content->priv->current_uid;
+ if (current_uid == NULL)
+ return;
+
+ comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row);
+ if (comp_data == NULL)
+ return;
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ if (g_strcmp0 (uid, current_uid) != 0)
+ return;
+
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ table = e_calendar_table_get_table (task_table);
+
+ task_shell_content_cursor_change_cb (task_shell_content, 0, table);
+}
+
+static void
+task_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_PREVIEW_VISIBLE:
+ e_task_shell_content_set_preview_visible (
+ E_TASK_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MODEL:
+ g_value_set_object (
+ value, e_task_shell_content_get_task_model (
+ E_TASK_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_PREVIEW_VISIBLE:
+ g_value_set_boolean (
+ value, e_task_shell_content_get_preview_visible (
+ E_TASK_SHELL_CONTENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_content_dispose (GObject *object)
+{
+ ETaskShellContentPrivate *priv;
+
+ priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->task_table != NULL) {
+ g_object_unref (priv->task_table);
+ priv->task_table = NULL;
+ }
+
+ if (priv->task_preview != NULL) {
+ g_object_unref (priv->task_preview);
+ priv->task_preview = NULL;
+ }
+
+ if (priv->task_model != NULL) {
+ g_object_unref (priv->task_model);
+ priv->task_model = NULL;
+ }
+
+ if (priv->table_config != NULL) {
+ g_object_unref (priv->table_config);
+ priv->table_config = NULL;
+ }
+
+ if (priv->view_instance != NULL) {
+ g_object_unref (priv->view_instance);
+ priv->view_instance = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+task_shell_content_finalize (GObject *object)
+{
+ ETaskShellContentPrivate *priv;
+
+ priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
+
+ g_free (priv->current_uid);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+task_shell_content_constructed (GObject *object)
+{
+ ETaskShellContentPrivate *priv;
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ GalViewInstance *view_instance;
+ ETable *table;
+ GConfBridge *bridge;
+ GtkWidget *container;
+ GtkWidget *widget;
+ const gchar *key;
+
+ priv = E_TASK_SHELL_CONTENT_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+
+ /* Build content widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = gtk_vpaned_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_calendar_table_new (shell_view, priv->task_model);
+ gtk_paned_add1 (GTK_PANED (container), widget);
+ priv->task_table = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_paned_add2 (GTK_PANED (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_cal_component_preview_new ();
+ e_cal_component_preview_set_default_timezone (
+ E_CAL_COMPONENT_PREVIEW (widget),
+ calendar_config_get_icaltimezone ());
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->task_preview = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Configure the task table. */
+
+ widget = E_CALENDAR_TABLE (priv->task_table)->etable;
+ table = e_table_scrolled_get_table (E_TABLE_SCROLLED (widget));
+
+ priv->table_config = e_calendar_table_config_new (
+ E_CALENDAR_TABLE (priv->task_table));
+
+ e_table_set_state (table, E_CALENDAR_TABLE_DEFAULT_STATE);
+
+ e_table_drag_source_set (
+ table, GDK_BUTTON1_MASK,
+ drag_types, G_N_ELEMENTS (drag_types),
+ GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_ASK);
+
+ g_signal_connect_swapped (
+ table, "table-drag-data-get",
+ G_CALLBACK (task_shell_content_table_drag_data_get_cb),
+ object);
+
+ g_signal_connect_swapped (
+ table, "table-drag-data-delete",
+ G_CALLBACK (task_shell_content_table_drag_data_delete_cb),
+ object);
+
+ g_signal_connect_swapped (
+ table, "cursor-change",
+ G_CALLBACK (task_shell_content_cursor_change_cb),
+ object);
+
+ g_signal_connect_swapped (
+ table, "selection-change",
+ G_CALLBACK (task_shell_content_selection_change_cb),
+ object);
+
+ g_signal_connect_swapped (
+ priv->task_model, "model-row-changed",
+ G_CALLBACK (task_shell_content_model_row_changed_cb),
+ object);
+
+ /* Load the view instance. */
+
+ view_instance = e_shell_view_new_view_instance (shell_view, NULL);
+ g_signal_connect_swapped (
+ view_instance, "display-view",
+ G_CALLBACK (task_shell_content_display_view_cb),
+ object);
+ gal_view_instance_load (view_instance);
+ priv->view_instance = view_instance;
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (priv->paned);
+ key = "/apps/evolution/calendar/display/task_vpane_position";
+ gconf_bridge_bind_property_delayed (bridge, key, object, "position");
+}
+
+static guint32
+task_shell_content_check_state (EShellContent *shell_content)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ETable *table;
+ GSList *list, *iter;
+ gboolean assignable = TRUE;
+ gboolean editable = TRUE;
+ gboolean has_url = FALSE;
+ gint n_selected;
+ gint n_complete = 0;
+ gint n_incomplete = 0;
+ guint32 state = 0;
+
+ task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ table = e_calendar_table_get_table (task_table);
+ n_selected = e_table_selected_count (table);
+
+ list = e_calendar_table_get_selected (task_table);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ icalproperty *prop;
+ const gchar *cap;
+ gboolean read_only;
+
+ e_cal_is_read_only (comp_data->client, &read_only, NULL);
+ editable &= !read_only;
+
+ cap = CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT;
+ if (e_cal_get_static_capability (comp_data->client, cap))
+ assignable = FALSE;
+
+ cap = CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK;
+ if (e_cal_get_static_capability (comp_data->client, cap))
+ assignable = FALSE;
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ has_url |= (prop != NULL);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_COMPLETED_PROPERTY);
+ if (prop != NULL)
+ n_complete++;
+ else
+ n_incomplete++;
+ }
+ g_slist_free (list);
+
+ if (n_selected == 1)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_SINGLE;
+ if (n_selected > 1)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE;
+ if (assignable)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN;
+ if (editable)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT;
+ if (n_complete > 0)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE;
+ if (n_incomplete > 0)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE;
+ if (has_url)
+ state |= E_TASK_SHELL_CONTENT_SELECTION_HAS_URL;
+
+ return state;
+}
+
+static void
+task_shell_content_class_init (ETaskShellContentClass *class)
+{
+ GObjectClass *object_class;
+ EShellContentClass *shell_content_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETaskShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = task_shell_content_set_property;
+ object_class->get_property = task_shell_content_get_property;
+ object_class->dispose = task_shell_content_dispose;
+ object_class->finalize = task_shell_content_finalize;
+ object_class->constructed = task_shell_content_constructed;
+
+ shell_content_class = E_SHELL_CONTENT_CLASS (class);
+ shell_content_class->check_state = task_shell_content_check_state;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MODEL,
+ g_param_spec_object (
+ "model",
+ _("Model"),
+ _("The task table model"),
+ E_TYPE_CAL_MODEL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW_VISIBLE,
+ g_param_spec_boolean (
+ "preview-visible",
+ _("Preview is Visible"),
+ _("Whether the preview pane is visible"),
+ TRUE,
+ G_PARAM_READWRITE));
+}
+
+static void
+task_shell_content_init (ETaskShellContent *task_shell_content)
+{
+ task_shell_content->priv =
+ E_TASK_SHELL_CONTENT_GET_PRIVATE (task_shell_content);
+
+ task_shell_content->priv->task_model = e_cal_model_tasks_new ();
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_task_shell_content_get_type (void)
+{
+ return task_shell_content_type;
+}
+
+void
+e_task_shell_content_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (ETaskShellContentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) task_shell_content_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ETaskShellContent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) task_shell_content_init,
+ NULL /* value_table */
+ };
+
+ task_shell_content_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_CONTENT,
+ "ETaskShellContent", &type_info, 0);
+}
+
+GtkWidget *
+e_task_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_TASK_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+ECalModel *
+e_task_shell_content_get_task_model (ETaskShellContent *task_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+
+ return task_shell_content->priv->task_model;
+}
+
+ECalComponentPreview *
+e_task_shell_content_get_task_preview (ETaskShellContent *task_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+
+ return E_CAL_COMPONENT_PREVIEW (
+ task_shell_content->priv->task_preview);
+}
+
+ECalendarTable *
+e_task_shell_content_get_task_table (ETaskShellContent *task_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+
+ return E_CALENDAR_TABLE (task_shell_content->priv->task_table);
+}
+
+GalViewInstance *
+e_task_shell_content_get_view_instance (ETaskShellContent *task_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), NULL);
+
+ return task_shell_content->priv->view_instance;
+}
+
+gboolean
+e_task_shell_content_get_preview_visible (ETaskShellContent *task_shell_content)
+{
+ GtkPaned *paned;
+ GtkWidget *child;
+
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_CONTENT (task_shell_content), FALSE);
+
+ paned = GTK_PANED (task_shell_content->priv->paned);
+ child = gtk_paned_get_child2 (paned);
+
+ return GTK_WIDGET_VISIBLE (child);
+}
+
+void
+e_task_shell_content_set_preview_visible (ETaskShellContent *task_shell_content,
+ gboolean preview_visible)
+{
+ GtkPaned *paned;
+ GtkWidget *child;
+
+ g_return_if_fail (E_IS_TASK_SHELL_CONTENT (task_shell_content));
+
+ paned = GTK_PANED (task_shell_content->priv->paned);
+ child = gtk_paned_get_child2 (paned);
+
+ if (preview_visible)
+ gtk_widget_show (child);
+ else
+ gtk_widget_hide (child);
+
+ g_object_notify (G_OBJECT (task_shell_content), "preview-visible");
+}
diff --cc calendar/module/e-task-shell-content.h
index e749d61,0000000..7e0b212
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-content.h
+++ b/calendar/module/e-task-shell-content.h
@@@ -1,100 -1,0 +1,100 @@@
+/*
+ * e-task-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_CONTENT_H
+#define E_TASK_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-view.h>
+
+#include <calendar/gui/e-cal-model.h>
+#include <calendar/gui/e-calendar-table.h>
+#include <calendar/gui/e-cal-component-preview.h>
+
+#include <menus/gal-view-instance.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TASK_SHELL_CONTENT \
+ (e_task_shell_content_get_type ())
+#define E_TASK_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContent))
+#define E_TASK_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentClass))
+#define E_IS_TASK_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TASK_SHELL_CONTENT))
+#define E_IS_TASK_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TASK_SHELL_CONTENT))
+#define E_TASK_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TASK_SHELL_CONTENT, ETaskShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETaskShellContent ETaskShellContent;
+typedef struct _ETaskShellContentClass ETaskShellContentClass;
+typedef struct _ETaskShellContentPrivate ETaskShellContentPrivate;
+
+enum {
+ E_TASK_SHELL_CONTENT_SELECTION_SINGLE = 1 << 0,
+ E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE = 1 << 1,
+ E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN = 1 << 2,
+ E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT = 1 << 3,
+ E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE = 1 << 4,
+ E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE = 1 << 5,
- E_TASK_SHELL_CONTENT_SELECTION_HAS_URL = 1 << 6
++ E_TASK_SHELL_CONTENT_SELECTION_HAS_URL = 1 << 6
+};
+
+struct _ETaskShellContent {
+ EShellContent parent;
+ ETaskShellContentPrivate *priv;
+};
+
+struct _ETaskShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_task_shell_content_get_type (void);
+void e_task_shell_content_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_task_shell_content_new(EShellView *shell_view);
+ECalModel * e_task_shell_content_get_task_model
+ (ETaskShellContent *task_shell_content);
+ECalComponentPreview *
+ e_task_shell_content_get_task_preview
+ (ETaskShellContent *task_shell_content);
+ECalendarTable *e_task_shell_content_get_task_table
+ (ETaskShellContent *task_shell_content);
+GalViewInstance *
+ e_task_shell_content_get_view_instance
+ (ETaskShellContent *task_shell_content);
+gboolean e_task_shell_content_get_preview_visible
+ (ETaskShellContent *task_shell_content);
+void e_task_shell_content_set_preview_visible
+ (ETaskShellContent *task_shell_content,
+ gboolean preview_visible);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_CONTENT_H */
diff --cc calendar/module/e-task-shell-migrate.c
index 76e53f7,0000000..9653fb9
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-migrate.c
+++ b/calendar/module/e-task-shell-migrate.c
@@@ -1,664 -1,0 +1,664 @@@
+/*
+ * e-task-shell-backend-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-task-shell-migrate.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <libebackend/e-dbhash.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-group.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserver/e-xml-hash-utils.h>
+#include <libedataserver/e-xml-utils.h>
+
+#include "e-util/e-bconf-map.h"
+#include "e-util/e-folder-map.h"
+#include "e-util/e-util-private.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/calendar-config-keys.h"
+
+#define WEBCAL_BASE_URI "webcal://"
+#define PERSONAL_RELATIVE_URI "system"
+
+static e_gconf_map_t calendar_tasks_map[] = {
+ /* /Calendar/Tasks */
+ { "HideCompletedTasks", "calendar/tasks/hide_completed", E_GCONF_MAP_BOOL },
+ { "HideCompletedTasksUnits", "calendar/tasks/hide_completed_units", E_GCONF_MAP_STRING },
+ { "HideCompletedTasksValue", "calendar/tasks/hide_completed_value", E_GCONF_MAP_INT },
+ { NULL },
+};
+
+static e_gconf_map_t calendar_tasks_colours_map[] = {
+ /* /Calendar/Tasks/Colors */
+ { "TasksDueToday", "calendar/tasks/colors/due_today", E_GCONF_MAP_STRING },
+ { "TasksOverDue", "calendar/tasks/colors/overdue", E_GCONF_MAP_STRING },
+ { "TasksDueToday", "calendar/tasks/colors/due_today", E_GCONF_MAP_STRING },
+ { NULL },
+};
+
+static e_gconf_map_list_t task_remap_list[] = {
+
+ { "/Calendar/Tasks", calendar_tasks_map },
+ { "/Calendar/Tasks/Colors", calendar_tasks_colours_map },
+
+ { NULL },
+};
+
+static GtkWidget *window;
+static GtkLabel *label;
+static GtkProgressBar *progress;
+
+#ifndef G_OS_WIN32
+
+/* No previous versions have been available on Win32, so don't
+ * bother with upgrade support from 1.x on Win32.
+ */
+
+static void
+setup_progress_dialog (void)
+{
+ GtkWidget *vbox, *hbox, *w;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title ((GtkWindow *) window, _("Migrating..."));
+ gtk_window_set_modal ((GtkWindow *) window, TRUE);
+ gtk_container_set_border_width ((GtkContainer *) window, 6);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_container_add ((GtkContainer *) window, vbox);
+
+ w = gtk_label_new (_("The location and hierarchy of the Evolution task "
+ "folders has changed since Evolution 1.x.\n\nPlease be "
+ "patient while Evolution migrates your folders..."));
+
+ gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+ gtk_widget_show (w);
+ gtk_box_pack_start_defaults ((GtkBox *) vbox, w);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start_defaults ((GtkBox *) vbox, hbox);
+
+ label = (GtkLabel *) gtk_label_new ("");
+ gtk_widget_show ((GtkWidget *) label);
+ gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) label);
+
+ progress = (GtkProgressBar *) gtk_progress_bar_new ();
+ gtk_widget_show ((GtkWidget *) progress);
+ gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) progress);
+
+ gtk_widget_show (window);
+}
+
+static void
+dialog_close (void)
+{
+ gtk_widget_destroy ((GtkWidget *) window);
+}
+
+static void
+dialog_set_folder_name (const char *folder_name)
+{
+ char *text;
+
+ text = g_strdup_printf (_("Migrating '%s':"), folder_name);
+ gtk_label_set_text (label, text);
+ g_free (text);
+
+ gtk_progress_bar_set_fraction (progress, 0.0);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+static void
+dialog_set_progress (double percent)
+{
+ char text[5];
+
+ snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f));
+
+ gtk_progress_bar_set_fraction (progress, percent);
+ gtk_progress_bar_set_text (progress, text);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+static gboolean
+check_for_conflict (ESourceGroup *group, char *name)
+{
+ GSList *sources;
+ GSList *s;
+
+ sources = e_source_group_peek_sources (group);
+
+ for (s = sources; s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+
+ if (!strcmp (e_source_peek_name (source), name))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static char *
+get_source_name (ESourceGroup *group, const char *path)
+{
+ char **p = g_strsplit (path, "/", 0);
+ int i, j, starting_index;
+ int num_elements;
+ gboolean conflict;
+ GString *s = g_string_new (NULL);
+
+ for (i = 0; p[i]; i ++) ;
+
+ num_elements = i;
+ i--;
+
+ /* p[i] is now the last path element */
+
+ /* check if it conflicts */
+ starting_index = i;
+ do {
+ for (j = starting_index; j < num_elements; j += 2) {
+ if (j != starting_index)
+ g_string_append_c (s, '_');
+ g_string_append (s, p[j]);
+ }
+
+ conflict = check_for_conflict (group, s->str);
+
+
+ /* if there was a conflict back up 2 levels (skipping the /subfolder/ element) */
+ if (conflict)
+ starting_index -= 2;
+
+ /* we always break out if we can't go any further,
+ regardless of whether or not we conflict. */
+ if (starting_index < 0)
+ break;
+
+ } while (conflict);
+ g_strfreev (p);
+
+ return g_string_free (s, FALSE);
+}
+
+static gboolean
+migrate_ical (ECal *old_ecal, ECal *new_ecal)
+{
+ GList *l, *objects;
+ int num_added = 0;
+ int num_objects;
+ gboolean retval = TRUE;
+
+ /* both ecals are loaded, start the actual migration */
+ if (!e_cal_get_object_list (old_ecal, "#t", &objects, NULL))
+ return FALSE;
+
+ num_objects = g_list_length (objects);
+ for (l = objects; l; l = l->next) {
+ icalcomponent *ical_comp = l->data;
+ GError *error = NULL;
+
+ if (!e_cal_create_object (new_ecal, ical_comp, NULL, &error)) {
+ g_warning ("Migration of object failed: %s", error->message);
+ retval = FALSE;
+ }
+
+ g_clear_error (&error);
+
+ num_added ++;
+ dialog_set_progress ((double)num_added / num_objects);
+ }
+
+ g_list_foreach (objects, (GFunc) icalcomponent_free, NULL);
+ g_list_free (objects);
+
+ return retval;
+}
+
+static gboolean
+migrate_ical_folder_to_source (char *old_path, ESource *new_source, ECalSourceType type)
+{
+ ECal *old_ecal = NULL, *new_ecal = NULL;
+ ESource *old_source;
+ ESourceGroup *group;
+ char *old_uri = g_strdup_printf ("file://%s", old_path);
+ GError *error = NULL;
+ gboolean retval = FALSE;
+
+ group = e_source_group_new ("", old_uri);
+ old_source = e_source_new ("", "");
+ e_source_group_add_source (group, old_source, -1);
+
+ dialog_set_folder_name (e_source_peek_name (new_source));
+
+ if (!(old_ecal = e_cal_new (old_source, type))) {
+ g_warning ("could not find a backend for '%s'", e_source_get_uri (old_source));
+ goto finish;
+ }
+ if (!e_cal_open (old_ecal, FALSE, &error)) {
+ g_warning ("failed to load source ecal for migration: '%s' (%s)", error->message,
+ e_source_get_uri (old_source));
+ goto finish;
+ }
+
+ if (!(new_ecal = e_cal_new (new_source, type))) {
+ g_warning ("could not find a backend for '%s'", e_source_get_uri (new_source));
+ goto finish;
+ }
+ if (!e_cal_open (new_ecal, FALSE, &error)) {
+ g_warning ("failed to load destination ecal for migration: '%s' (%s)", error->message,
+ e_source_get_uri (new_source));
+ goto finish;
+ }
+
+ retval = migrate_ical (old_ecal, new_ecal);
+
+finish:
+ g_clear_error (&error);
+ if (old_ecal)
+ g_object_unref (old_ecal);
+ g_object_unref (group);
+ if (new_ecal)
+ g_object_unref (new_ecal);
+ g_free (old_uri);
+
+ return retval;
+}
+
+static gboolean
+migrate_ical_folder (char *old_path, ESourceGroup *dest_group, char *source_name, ECalSourceType type)
+{
+ ESource *new_source;
+ gboolean retval;
+
+ new_source = e_source_new (source_name, source_name);
+ e_source_set_relative_uri (new_source, e_source_peek_uid (new_source));
+ e_source_group_add_source (dest_group, new_source, -1);
+
+ retval = migrate_ical_folder_to_source (old_path, new_source, type);
+
+ g_object_unref (new_source);
+
+ return retval;
+}
+
+#endif /* !G_OS_WIN32 */
+
+#ifndef G_OS_WIN32
+
+static void
+migrate_pilot_db_key (const char *key, gpointer user_data)
+{
+ EXmlHash *xmlhash = user_data;
+
+ e_xmlhash_add (xmlhash, key, "");
+}
+
+static void
+migrate_pilot_data (const char *component, const char *conduit, const char *old_path, const char *new_path)
+{
+ char *changelog, *map;
+ const char *dent;
+ const char *ext;
+ char *filename;
+ GDir *dir;
+
+ if (!(dir = g_dir_open (old_path, 0, NULL)))
+ return;
+
+ map = g_alloca (12 + strlen (conduit));
+ sprintf (map, "pilot-map-%s-", conduit);
+
+ changelog = g_alloca (24 + strlen (conduit));
+ sprintf (changelog, "pilot-sync-evolution-%s-", conduit);
+
+ while ((dent = g_dir_read_name (dir))) {
+ if (!strncmp (dent, map, strlen (map)) &&
+ ((ext = strrchr (dent, '.')) && !strcmp (ext, ".xml"))) {
+ /* pilot map file - src and dest file formats are identical */
+ unsigned char inbuf[4096];
+ size_t nread, nwritten;
+ int fd0, fd1;
+ ssize_t n;
+
+ filename = g_build_filename (old_path, dent, NULL);
+ if ((fd0 = g_open (filename, O_RDONLY|O_BINARY, 0)) == -1) {
+ g_free (filename);
+ continue;
+ }
+
+ g_free (filename);
+ filename = g_build_filename (new_path, dent, NULL);
+ if ((fd1 = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) == -1) {
+ g_free (filename);
+ close (fd0);
+ continue;
+ }
+
+ do {
+ do {
+ n = read (fd0, inbuf, sizeof (inbuf));
+ } while (n == -1 && errno == EINTR);
+
+ if (n < 1)
+ break;
+
+ nread = n;
+ nwritten = 0;
+ do {
+ do {
+ n = write (fd1, inbuf + nwritten, nread - nwritten);
+ } while (n == -1 && errno == EINTR);
+
+ if (n > 0)
+ nwritten += n;
+ } while (nwritten < nread && n != -1);
+
+ if (n == -1)
+ break;
+ } while (1);
+
+ if (n != -1)
+ n = fsync (fd1);
+
+ if (n == -1) {
+ g_warning ("Failed to migrate %s: %s", dent, strerror (errno));
+ g_unlink (filename);
+ }
+
+ close (fd0);
+ close (fd1);
+ g_free (filename);
+ } else if (!strncmp (dent, changelog, strlen (changelog)) &&
+ ((ext = strrchr (dent, '.')) && !strcmp (ext, ".db"))) {
+ /* src and dest formats differ, src format is db3 while dest format is xml */
+ EXmlHash *xmlhash;
+ EDbHash *dbhash;
+ struct stat st;
+
+ filename = g_build_filename (old_path, dent, NULL);
+ if (g_stat (filename, &st) == -1) {
+ g_free (filename);
+ continue;
+ }
+
+ dbhash = e_dbhash_new (filename);
+ g_free (filename);
+
+ filename = g_strdup_printf ("%s/%s.ics-%s", new_path, component, dent);
+ if (g_stat (filename, &st) != -1)
+ g_unlink (filename);
+ xmlhash = e_xmlhash_new (filename);
+ g_free (filename);
+
+ e_dbhash_foreach_key (dbhash, migrate_pilot_db_key, xmlhash);
+
+ e_dbhash_destroy (dbhash);
+
+ e_xmlhash_write (xmlhash);
+ e_xmlhash_destroy (xmlhash);
+ }
+ }
+
+ g_dir_close (dir);
+}
+
+#endif
+
+static void
+create_task_sources (EShellBackend *shell_backend,
+ ESourceList *source_list,
+ ESourceGroup **on_this_computer,
+ ESourceGroup **on_the_web,
+ ESource **personal_source)
+{
+ GSList *groups;
+ ESourceGroup *group;
+ char *base_uri, *base_uri_proto;
+ const gchar *base_dir;
+
+ *on_this_computer = NULL;
+ *on_the_web = NULL;
+ *personal_source = NULL;
+
+ base_dir = e_shell_backend_get_config_dir (shell_backend);
+ base_uri = g_build_filename (base_dir, "local", NULL);
+
+ base_uri_proto = g_filename_to_uri (base_uri, NULL, NULL);
+
+ groups = e_source_list_peek_groups (source_list);
+ if (groups) {
+ /* groups are already there, we need to search for things... */
+ GSList *g;
+
+ for (g = groups; g; g = g->next) {
+
+ group = E_SOURCE_GROUP (g->data);
+
+ if (!*on_this_computer && !strcmp (base_uri_proto, e_source_group_peek_base_uri (group)))
+ *on_this_computer = g_object_ref (group);
+ else if (!*on_the_web && !strcmp (WEBCAL_BASE_URI, e_source_group_peek_base_uri (group)))
+ *on_the_web = g_object_ref (group);
+ }
+ }
+
+ if (*on_this_computer) {
+ /* make sure "Personal" shows up as a source under
+ this group */
+ GSList *sources = e_source_group_peek_sources (*on_this_computer);
+ GSList *s;
+ for (s = sources; s; s = s->next) {
+ ESource *source = E_SOURCE (s->data);
+ const gchar *relative_uri;
+
+ relative_uri = e_source_peek_relative_uri (source);
+ if (relative_uri == NULL)
+ continue;
+ if (!strcmp (PERSONAL_RELATIVE_URI, relative_uri)) {
+ *personal_source = g_object_ref (source);
+ break;
+ }
+ }
+ } else {
+ /* create the local source group */
+ group = e_source_group_new (_("On This Computer"), base_uri_proto);
+ e_source_list_add_group (source_list, group, -1);
+
+ *on_this_computer = group;
+ }
+
+ if (!*personal_source) {
+ /* Create the default Person task list */
+ ESource *source = e_source_new (_("Personal"), PERSONAL_RELATIVE_URI);
+ e_source_group_add_source (*on_this_computer, source, -1);
+
+ if (!calendar_config_get_primary_tasks () && !calendar_config_get_tasks_selected ()) {
+ GSList selected;
+
+ calendar_config_set_primary_tasks (e_source_peek_uid (source));
+
+ selected.data = (gpointer)e_source_peek_uid (source);
+ selected.next = NULL;
+ calendar_config_set_tasks_selected (&selected);
+ }
+
+ e_source_set_color_spec (source, "#BECEDD");
+ *personal_source = source;
+ }
+
+ if (!*on_the_web) {
+ /* Create the Webcal source group */
+ group = e_source_group_new (_("On The Web"), WEBCAL_BASE_URI);
+ e_source_list_add_group (source_list, group, -1);
+
+ *on_the_web = group;
+ }
+
+ g_free (base_uri_proto);
+ g_free (base_uri);
+}
+
+gboolean
+e_task_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ ESourceGroup *on_this_computer = NULL;
+ ESourceGroup *on_the_web = NULL;
+ ESource *personal_source = NULL;
+ ESourceList *source_list;
+ gboolean retval = FALSE;
+
+ source_list = g_object_get_data (
+ G_OBJECT (source_list), "source-list");
+
+ /* we call this unconditionally now - create_groups either
+ creates the groups/sources or it finds the necessary
+ groups/sources. */
+ create_task_sources (
+ shell_backend, source_list, &on_this_computer,
+ &on_the_web, &personal_source);
+
+#ifndef G_OS_WIN32
+ if (major == 1) {
+ xmlDocPtr config_doc = NULL;
+ char *conf_file;
+
+ conf_file = g_build_filename (g_get_home_dir (), "evolution", "config.xmldb", NULL);
+ if (g_file_test (conf_file, G_FILE_TEST_IS_REGULAR))
+ config_doc = e_xml_parse_file (conf_file);
+ g_free (conf_file);
+
+ if (config_doc && minor <= 2) {
+ GConfClient *gconf;
+ int res = 0;
+
+ /* move bonobo config to gconf */
+ gconf = gconf_client_get_default ();
+
+ res = e_bconf_import (gconf, config_doc, task_remap_list);
+
+ g_object_unref (gconf);
+
+ xmlFreeDoc(config_doc);
+
+ if (res != 0) {
+ g_set_error(error, 0, 0, _("Unable to migrate old settings from evolution/config.xmldb"));
+ goto fail;
+ }
+ }
+
+ if (minor <= 4) {
+ GSList *migration_dirs, *l;
+ char *path, *local_task_folder;
+
+ setup_progress_dialog ();
+
+ path = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+ migration_dirs = e_folder_map_local_folders (path, "tasks");
+ local_task_folder = g_build_filename (path, "Tasks", NULL);
+ g_free (path);
+
+ if (personal_source)
+ migrate_ical_folder_to_source (local_task_folder, personal_source, E_CAL_SOURCE_TYPE_TODO);
+
+ for (l = migration_dirs; l; l = l->next) {
+ char *source_name;
+
+ if (personal_source && !strcmp ((char*)l->data, local_task_folder))
+ continue;
+
+ source_name = get_source_name (on_this_computer, (char*)l->data);
+
+ if (!migrate_ical_folder (l->data, on_this_computer, source_name, E_CAL_SOURCE_TYPE_TODO)) {
+ /* FIXME: domain/code */
+ g_set_error(error, 0, 0, _("Unable to migrate tasks `%s'"), source_name);
+ g_free(source_name);
+ goto fail;
+ }
+
+ g_free (source_name);
+ }
+
+ g_free (local_task_folder);
+
+ dialog_close ();
+ }
+
+ if (minor < 5 || (minor == 5 && micro <= 10)) {
+ char *old_path, *new_path;
+
+ old_path = g_build_filename (g_get_home_dir (), "evolution", "local", "Tasks", NULL);
+ new_path = g_build_filename (e_shell_backend_get_config_dir (shell_backend),
+ "local", "system", NULL);
+ migrate_pilot_data ("tasks", "todo", old_path, new_path);
+ g_free (new_path);
+ g_free (old_path);
+ }
+
+ /* we only need to do this next step if people ran
+ older versions of 1.5. We need to clear out the
+ absolute URI's that were assigned to ESources
+ during one phase of development, as they take
+ precedent over relative uris (but aren't updated
+ when editing an ESource). */
+ if (minor == 5 && micro <= 11) {
+ GSList *g;
+ for (g = e_source_list_peek_groups (source_list); g; g = g->next) {
+ ESourceGroup *group = g->data;
+ GSList *s;
+
+ for (s = e_source_group_peek_sources (group); s; s = s->next) {
+ ESource *source = s->data;
+ e_source_set_absolute_uri (source, NULL);
+ }
+ }
+ }
+ }
+#endif /* !G_OS_WIN32 */
+ e_source_list_sync (source_list, NULL);
+ retval = TRUE;
+fail:
+ if (on_this_computer)
+ g_object_unref (on_this_computer);
+ if (on_the_web)
+ g_object_unref (on_the_web);
+ if (personal_source)
+ g_object_unref (personal_source);
+
+ return retval;
+}
diff --cc calendar/module/e-task-shell-migrate.h
index 6853dd8,0000000..4cb91c9
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-migrate.h
+++ b/calendar/module/e-task-shell-migrate.h
@@@ -1,38 -1,0 +1,38 @@@
+/*
+ * e-task-shell-backend-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_BACKEND_MIGRATE_H
+#define E_TASK_SHELL_BACKEND_MIGRATE_H
+
+#include <glib.h>
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_task_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_BACKEND_MIGRATE_H */
diff --cc calendar/module/e-task-shell-sidebar.c
index f23a2be,0000000..827a0a0
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-sidebar.c
+++ b/calendar/module/e-task-shell-sidebar.c
@@@ -1,696 -1,0 +1,696 @@@
+/*
+ * e-task-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-task-shell-sidebar.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/e-cal.h>
+
+#include "e-util/e-error.h"
+#include "e-util/e-util.h"
+#include "calendar/common/authentication.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/e-task-list-selector.h"
+#include "calendar/gui/misc.h"
+
+#include "e-task-shell-backend.h"
+#include "e-task-shell-view.h"
+
+#define E_TASK_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarPrivate))
+
+struct _ETaskShellSidebarPrivate {
+ GtkWidget *selector;
+
+ /* UID -> Client */
+ GHashTable *client_table;
+};
+
+enum {
+ PROP_0,
+ PROP_SELECTOR
+};
+
+enum {
+ CLIENT_ADDED,
+ CLIENT_REMOVED,
+ STATUS_MESSAGE,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+static GType task_shell_sidebar_type;
+
+static void
+task_shell_sidebar_emit_client_added (ETaskShellSidebar *task_shell_sidebar,
+ ECal *client)
+{
+ guint signal_id = signals[CLIENT_ADDED];
+
+ g_signal_emit (task_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+task_shell_sidebar_emit_client_removed (ETaskShellSidebar *task_shell_sidebar,
+ ECal *client)
+{
+ guint signal_id = signals[CLIENT_REMOVED];
+
+ g_signal_emit (task_shell_sidebar, signal_id, 0, client);
+}
+
+static void
+task_shell_sidebar_emit_status_message (ETaskShellSidebar *task_shell_sidebar,
+ const gchar *status_message)
+{
+ guint signal_id = signals[STATUS_MESSAGE];
+
+ g_signal_emit (task_shell_sidebar, signal_id, 0, status_message, -1.0);
+}
+
+static void
+task_shell_sidebar_backend_died_cb (ETaskShellSidebar *task_shell_sidebar,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ GHashTable *client_table;
+ ESource *source;
+ const gchar *uid;
+
+ client_table = task_shell_sidebar->priv->client_table;
+
+ shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ source = e_cal_get_source (client);
+ uid = e_source_peek_uid (source);
+
+ g_object_ref (source);
+
+ g_hash_table_remove (client_table, uid);
+ task_shell_sidebar_emit_status_message (task_shell_sidebar, NULL);
+
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:tasks-crashed", NULL);
+
+ g_object_unref (source);
+}
+
+static void
+task_shell_sidebar_backend_error_cb (ETaskShellSidebar *task_shell_sidebar,
+ const gchar *message,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ GtkWidget *dialog;
+ const gchar *uri;
+ gchar *uri_no_passwd;
+
+ shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ uri = e_cal_get_uri (client);
+ uri_no_passwd = get_uri_without_password (uri);
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("Error on %s\n%s"),
+ uri_no_passwd, message);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_free (uri_no_passwd);
+}
+
+static void
+task_shell_sidebar_client_opened_cb (ETaskShellSidebar *task_shell_sidebar,
+ ECalendarStatus status,
+ ECal *client)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSidebar *shell_sidebar;
+ ESource *source;
+
+ source = e_cal_get_source (client);
+
+ shell_sidebar = E_SHELL_SIDEBAR (task_shell_sidebar);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (status == E_CALENDAR_STATUS_AUTHENTICATION_FAILED ||
+ status == E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED)
+ auth_cal_forget_password (client);
+
+ switch (status) {
+ case E_CALENDAR_STATUS_OK:
+ g_signal_handlers_disconnect_matched (
+ client, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+ task_shell_sidebar_client_opened_cb, NULL);
+
+ task_shell_sidebar_emit_status_message (
+ task_shell_sidebar, _("Loading tasks"));
+ task_shell_sidebar_emit_client_added (
+ task_shell_sidebar, client);
+ task_shell_sidebar_emit_status_message (
+ task_shell_sidebar, NULL);
+ break;
+
+ case E_CALENDAR_STATUS_AUTHENTICATION_FAILED:
+ e_cal_open_async (client, FALSE);
+ break;
+
+ case E_CALENDAR_STATUS_BUSY:
+ break;
+
+ case E_CALENDAR_STATUS_REPOSITORY_OFFLINE:
+ e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-no-contents-offline-tasks",
+ NULL);
+ break;
+
+ default:
+ task_shell_sidebar_emit_client_removed (
+ task_shell_sidebar, client);
+ break;
+ }
+}
+
+static void
+task_shell_sidebar_row_changed_cb (ETaskShellSidebar *task_shell_sidebar,
+ GtkTreePath *tree_path,
+ GtkTreeIter *tree_iter,
+ GtkTreeModel *tree_model)
+{
+ ESourceSelector *selector;
+ ESource *source;
+
+ /* XXX ESourceSelector's underlying tree store has only one
+ * column: ESource objects. While we're not supposed to
+ * know this, listening for "row-changed" signals from
+ * the model is easier to deal with than the selector's
+ * "selection-changed" signal, which doesn't tell you
+ * _which_ row changed. */
+
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ gtk_tree_model_get (tree_model, tree_iter, 0, &source, -1);
+
+ /* XXX This signal gets emitted a lot while the model is being
+ * rebuilt, during which time we won't get a valid ESource.
+ * ESourceSelector should probably block this signal while
+ * rebuilding the model, but we'll be forgiving and not
+ * emit a warning. */
+ if (!E_IS_SOURCE (source))
+ return;
+
+ if (e_source_selector_source_is_selected (selector, source))
+ e_task_shell_sidebar_add_source (task_shell_sidebar, source);
+ else
+ e_task_shell_sidebar_remove_source (task_shell_sidebar, source);
+}
+
+static void
+task_shell_sidebar_selection_changed_cb (ETaskShellSidebar *task_shell_sidebar,
+ ESourceSelector *selector)
+{
+ GSList *list, *iter;
+
+ /* This signal is emitted less frequently than "row-changed",
+ * especially when the model is being rebuilt. So we'll take
+ * it easy on poor GConf. */
+
+ list = e_source_selector_get_selection (selector);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+
+ iter->data = (gpointer) e_source_peek_uid (source);
+ g_object_unref (source);
+ }
+
+ calendar_config_set_tasks_selected (list);
+
+ g_slist_free (list);
+}
+
+static void
+task_shell_sidebar_primary_selection_changed_cb (ETaskShellSidebar *task_shell_sidebar,
+ ESourceSelector *selector)
+{
+ ESource *source;
+ const gchar *uid;
+
+ /* XXX ESourceSelector needs a "primary-selection-uid" property
+ * so we can just bind the property with GConfBridge. */
+
+ source = e_source_selector_peek_primary_selection (selector);
+ if (source == NULL)
+ return;
+
+ uid = e_source_peek_uid (source);
+ calendar_config_set_primary_tasks (uid);
+}
+
+static void
+task_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SELECTOR:
+ g_value_set_object (
+ value, e_task_shell_sidebar_get_selector (
+ E_TASK_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+task_shell_sidebar_dispose (GObject *object)
+{
+ ETaskShellSidebarPrivate *priv;
+
+ priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->selector != NULL) {
+ g_object_unref (priv->selector);
+ priv->selector = NULL;
+ }
+
+ g_hash_table_remove_all (priv->client_table);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+task_shell_sidebar_finalize (GObject *object)
+{
+ ETaskShellSidebarPrivate *priv;
+
+ priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->client_table);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+task_shell_sidebar_constructed (GObject *object)
+{
+ ETaskShellSidebarPrivate *priv;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellSidebar *shell_sidebar;
+ ESourceSelector *selector;
+ ESourceList *source_list;
+ ESource *source;
+ GtkContainer *container;
+ GtkTreeModel *model;
+ GtkWidget *widget;
+ AtkObject *a11y;
+ GSList *list, *iter;
+ gchar *uid;
+
+ priv = E_TASK_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ source_list = e_task_shell_backend_get_source_list (
+ E_TASK_SHELL_BACKEND (shell_backend));
+
+ container = GTK_CONTAINER (shell_sidebar);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (container, widget);
+ gtk_widget_show (widget);
+
+ container = GTK_CONTAINER (widget);
+
+ widget = e_task_list_selector_new (source_list);
+ e_source_selector_set_select_new (E_SOURCE_SELECTOR (widget), TRUE);
+ gtk_container_add (container, widget);
+ a11y = gtk_widget_get_accessible (widget);
+ atk_object_set_name (a11y, _("Task List Selector"));
+ priv->selector = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Restore the selector state from the last session. */
+
+ selector = E_SOURCE_SELECTOR (priv->selector);
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
+
+ g_signal_connect_swapped (
+ model, "row-changed",
+ G_CALLBACK (task_shell_sidebar_row_changed_cb),
+ object);
+
+ source = NULL;
+ uid = calendar_config_get_primary_tasks ();
+ if (uid != NULL)
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ if (source == NULL)
+ source = e_source_list_peek_source_any (source_list);
+ if (source != NULL)
+ e_source_selector_set_primary_selection (selector, source);
+ g_free (uid);
+
+ list = calendar_config_get_tasks_selected ();
+ for (iter = list; iter != NULL; iter = iter->next) {
+ uid = iter->data;
+ source = e_source_list_peek_source_by_uid (source_list, uid);
+ g_free (uid);
+
+ if (source == NULL)
+ continue;
+
+ e_source_selector_select_source (selector, source);
+ }
+ g_slist_free (list);
+
+ /* Listen for subsequent changes to the selector. */
+
+ g_signal_connect_swapped (
+ widget, "selection-changed",
+ G_CALLBACK (task_shell_sidebar_selection_changed_cb),
+ object);
+
+ g_signal_connect_swapped (
+ widget, "primary-selection-changed",
+ G_CALLBACK (task_shell_sidebar_primary_selection_changed_cb),
+ object);
+}
+
+static guint32
+task_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *source;
- gboolean is_system = FALSE;
++ gboolean is_system = FALSE;
+ guint32 state = 0;
+
+ task_shell_sidebar = E_TASK_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+
+ if (source != NULL) {
+ const gchar *uri;
+
+ uri = e_source_peek_relative_uri (source);
+ is_system = (uri == NULL || strcmp (uri, "system") == 0);
+ }
+
+ if (source != NULL)
+ state |= E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE;
+ if (is_system)
+ state |= E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM;
+
+ return state;
+}
+
+static void
+task_shell_sidebar_client_removed (ETaskShellSidebar *task_shell_sidebar,
+ ECal *client)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ESource *source;
+ const gchar *uid;
+
+ client_table = task_shell_sidebar->priv->client_table;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ g_signal_handlers_disconnect_matched (
+ client, G_SIGNAL_MATCH_DATA, 0, 0,
+ NULL, NULL, task_shell_sidebar);
+
+ source = e_cal_get_source (client);
+ e_source_selector_unselect_source (selector, source);
+
+ uid = e_source_peek_uid (source);
+ g_hash_table_remove (client_table, uid);
+
+ task_shell_sidebar_emit_status_message (task_shell_sidebar, NULL);
+}
+
+static void
+task_shell_sidebar_class_init (ETaskShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETaskShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = task_shell_sidebar_get_property;
+ object_class->dispose = task_shell_sidebar_dispose;
+ object_class->finalize = task_shell_sidebar_finalize;
+ object_class->constructed = task_shell_sidebar_constructed;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = task_shell_sidebar_check_state;
+
+ class->client_removed = task_shell_sidebar_client_removed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTOR,
+ g_param_spec_object (
+ "selector",
+ _("Source Selector Widget"),
+ _("This widget displays groups of task lists"),
+ E_TYPE_SOURCE_SELECTOR,
+ G_PARAM_READABLE));
+
+ signals[CLIENT_ADDED] = g_signal_new (
+ "client-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETaskShellSidebarClass, client_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL);
+
+ signals[CLIENT_REMOVED] = g_signal_new (
+ "client-removed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ETaskShellSidebarClass, client_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_CAL);
+
+ signals[STATUS_MESSAGE] = g_signal_new (
+ "status-message",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ETaskShellSidebarClass, status_message),
+ NULL, NULL,
+ e_marshal_VOID__STRING_DOUBLE,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_DOUBLE);
+}
+
+static void
+task_shell_sidebar_init (ETaskShellSidebar *task_shell_sidebar)
+{
+ GHashTable *client_table;
+
+ client_table = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ task_shell_sidebar->priv =
+ E_TASK_SHELL_SIDEBAR_GET_PRIVATE (task_shell_sidebar);
+
+ task_shell_sidebar->priv->client_table = client_table;
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_task_shell_sidebar_get_type (void)
+{
+ return task_shell_sidebar_type;
+}
+
+void
+e_task_shell_sidebar_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (ETaskShellSidebarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) task_shell_sidebar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ETaskShellSidebar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) task_shell_sidebar_init,
+ NULL /* value_table */
+ };
+
+ task_shell_sidebar_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_SIDEBAR,
+ "ETaskShellSidebar", &type_info, 0);
+}
+
+GtkWidget *
+e_task_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_TASK_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+GList *
+e_task_shell_sidebar_get_clients (ETaskShellSidebar *task_shell_sidebar)
+{
+ GHashTable *client_table;
+
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar), NULL);
+
+ client_table = task_shell_sidebar->priv->client_table;
+
+ return g_hash_table_get_values (client_table);
+}
+
+ESourceSelector *
+e_task_shell_sidebar_get_selector (ETaskShellSidebar *task_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar), NULL);
+
+ return E_SOURCE_SELECTOR (task_shell_sidebar->priv->selector);
+}
+
+void
+e_task_shell_sidebar_add_source (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ECal *client;
+ const gchar *uid;
+ const gchar *uri;
+ gchar *message;
+
+ g_return_if_fail (E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ client_table = task_shell_sidebar->priv->client_table;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ uid = e_source_peek_uid (source);
+ client = g_hash_table_lookup (client_table, uid);
+
+ if (client != NULL)
+ return;
+
+ client = auth_new_cal_from_source (source, E_CAL_SOURCE_TYPE_TODO);
+ g_return_if_fail (client != NULL);
+
+ g_signal_connect_swapped (
+ client, "backend-died",
+ G_CALLBACK (task_shell_sidebar_backend_died_cb),
+ task_shell_sidebar);
+
+ g_signal_connect_swapped (
+ client, "backend-error",
+ G_CALLBACK (task_shell_sidebar_backend_error_cb),
+ task_shell_sidebar);
+
+ g_hash_table_insert (client_table, g_strdup (uid), client);
+ e_source_selector_select_source (selector, source);
+
+ uri = e_cal_get_uri (client);
+ message = g_strdup_printf (_("Opening tasks at %s"), uri);
+ task_shell_sidebar_emit_status_message (task_shell_sidebar, message);
+ g_free (message);
+
+ g_signal_connect_swapped (
+ client, "cal-opened",
+ G_CALLBACK (task_shell_sidebar_client_opened_cb),
+ task_shell_sidebar);
+
+ e_cal_open_async (client, FALSE);
+}
+
+void
+e_task_shell_sidebar_remove_source (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source)
+{
+ ESourceSelector *selector;
+ GHashTable *client_table;
+ ECal *client;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_TASK_SHELL_SIDEBAR (task_shell_sidebar));
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ client_table = task_shell_sidebar->priv->client_table;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ uid = e_source_peek_uid (source);
+ client = g_hash_table_lookup (client_table, uid);
+
+ if (client == NULL)
+ return;
+
+ task_shell_sidebar_emit_client_removed (task_shell_sidebar, client);
+}
diff --cc calendar/module/e-task-shell-sidebar.h
index a6d7241,0000000..5d4c74f
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-sidebar.h
+++ b/calendar/module/e-task-shell-sidebar.h
@@@ -1,97 -1,0 +1,97 @@@
+/*
+ * e-task-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_SIDEBAR_H
+#define E_TASK_SHELL_SIDEBAR_H
+
+#include <libecal/e-cal.h>
+#include <libedataserverui/e-source-selector.h>
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TASK_SHELL_SIDEBAR \
+ (e_task_shell_sidebar_get_type ())
+#define E_TASK_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebar))
+#define E_TASK_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarClass))
+#define E_IS_TASK_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TASK_SHELL_SIDEBAR))
+#define E_IS_TASK_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TASK_SHELL_SIDEBAR))
+#define E_TASK_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TASK_SHELL_SIDEBAR, ETaskShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETaskShellSidebar ETaskShellSidebar;
+typedef struct _ETaskShellSidebarClass ETaskShellSidebarClass;
+typedef struct _ETaskShellSidebarPrivate ETaskShellSidebarPrivate;
+
+enum {
+ E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE = 1 << 0,
+ E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM = 1 << 1
+};
+
+struct _ETaskShellSidebar {
+ EShellSidebar parent;
+ ETaskShellSidebarPrivate *priv;
+};
+
+struct _ETaskShellSidebarClass {
+ EShellSidebarClass parent_class;
+
+ /* Signals */
+ void (*client_added) (ETaskShellSidebar *task_shell_sidebar,
+ ECal *client);
+ void (*client_removed) (ETaskShellSidebar *task_shell_sidebar,
+ ECal *client);
+ void (*status_message) (ETaskShellSidebar *task_shell_sidebar,
+ const gchar *status_message,
+ gdouble percent);
+};
+
+GType e_task_shell_sidebar_get_type (void);
+void e_task_shell_sidebar_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_task_shell_sidebar_new(EShellView *shell_view);
+GList * e_task_shell_sidebar_get_clients
+ (ETaskShellSidebar *task_shell_sidebar);
+ESourceSelector *
+ e_task_shell_sidebar_get_selector
+ (ETaskShellSidebar *task_shell_sidebar);
+void e_task_shell_sidebar_add_source
+ (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source);
+void e_task_shell_sidebar_remove_source
+ (ETaskShellSidebar *task_shell_sidebar,
+ ESource *source);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_SIDEBAR_H */
diff --cc calendar/module/e-task-shell-view-actions.c
index 5de630e,0000000..4645ac0
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view-actions.c
+++ b/calendar/module/e-task-shell-view-actions.c
@@@ -1,1125 -1,0 +1,1125 @@@
+/*
+ * e-task-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-task-shell-view-private.h"
+
+static void
+action_gal_save_custom_view_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EShellView *shell_view;
+ GalViewInstance *view_instance;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with saving the custom view. */
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ view_instance = e_task_shell_content_get_view_instance (task_shell_content);
+ gal_view_instance_save_as (view_instance);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShellView *shell_view;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with executing the search. */
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ e_task_shell_view_execute_search (task_shell_view);
+}
+
+static void
+action_search_filter_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ ETaskShellView *task_shell_view)
+{
+ e_task_shell_view_execute_search (task_shell_view);
+}
+
+static void
+action_task_assign_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected task. */
+ e_task_shell_view_open_task (task_shell_view, comp_data);
+
+ /* FIXME Need to actually assign the task. */
+}
+
+static void
+action_task_clipboard_copy_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ e_calendar_table_copy_clipboard (task_table);
+}
+
+static void
+action_task_clipboard_cut_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ e_calendar_table_cut_clipboard (task_table);
+}
+
+static void
+action_task_clipboard_paste_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ e_calendar_table_paste_clipboard (task_table);
+}
+
+static void
+action_task_delete_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalComponentPreview *task_preview;
+ ECalendarTable *task_table;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ task_preview = e_task_shell_content_get_task_preview (task_shell_content);
+
+ e_task_shell_view_set_status_message (
+ task_shell_view, _("Deleting selected tasks..."), -1.0);
+ e_calendar_table_delete_selected (task_table);
+ e_task_shell_view_set_status_message (task_shell_view, NULL, -1.0);
+
+ e_cal_component_preview_clear (task_preview);
+}
+
+static void
+action_task_forward_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GSList *list;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only forward the first selected task. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+ itip_send_comp (
+ E_CAL_COMPONENT_METHOD_PUBLISH, comp,
+ comp_data->client, NULL, NULL, NULL, TRUE);
+ g_object_unref (comp);
+}
+
+static void
+action_task_list_copy_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ESourceSelector *selector;
+ ESource *source;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ copy_source_dialog (
+ GTK_WINDOW (shell_window),
+ source, E_CAL_SOURCE_TYPE_TODO);
+}
+
+static void
+action_task_list_delete_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellBackend *task_shell_backend;
+ ETaskShellContent *task_shell_content;
+ ETaskShellSidebar *task_shell_sidebar;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ ECalendarTable *task_table;
+ ECal *client;
+ ECalModel *model;
+ ESourceSelector *selector;
+ ESourceGroup *source_group;
+ ESourceList *source_list;
+ ESource *source;
+ gint response;
+ gchar *uri;
+ GError *error = NULL;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ task_shell_backend = task_shell_view->priv->task_shell_backend;
+ source_list = e_task_shell_backend_get_source_list (task_shell_backend);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_calendar_table_get_model (task_table);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ /* Ask for confirmation. */
+ response = e_error_run (
+ GTK_WINDOW (shell_window),
+ "calendar:prompt-delete-task-list",
+ e_source_peek_name (source));
+ if (response != GTK_RESPONSE_YES)
+ return;
+
+ uri = e_source_get_uri (source);
+ client = e_cal_model_get_client_for_uri (model, uri);
+ if (client == NULL)
+ client = e_cal_new_from_uri (uri, E_CAL_SOURCE_TYPE_JOURNAL);
+ g_free (uri);
+
+ g_return_if_fail (client != NULL);
+
+ if (!e_cal_remove (client, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (e_source_selector_source_is_selected (selector, source)) {
+ e_task_shell_sidebar_remove_source (
+ task_shell_sidebar, source);
+ e_source_selector_unselect_source (selector, source);
+ }
+
+ source_group = e_source_peek_group (source);
+ e_source_group_remove_source (source_group, source);
+
+ if (!e_source_list_sync (source_list, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+action_task_list_new_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ calendar_setup_new_task_list (GTK_WINDOW (shell_window));
+}
+
+static void
+action_task_list_print_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ETable *table;
+ GtkPrintOperationAction print_action;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ table = e_calendar_table_get_table (task_table);
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ print_table (table, _("Print Tasks"), _("Tasks"), print_action);
+}
+
+static void
+action_task_list_print_preview_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ETable *table;
+ GtkPrintOperationAction print_action;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ table = e_calendar_table_get_table (task_table);
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
+ print_table (table, _("Print Tasks"), _("Tasks"), print_action);
+}
+
+static void
+action_task_list_properties_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESource *source;
+ ESourceSelector *selector;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ source = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (E_IS_SOURCE (source));
+
+ calendar_setup_edit_task_list (GTK_WINDOW (shell_window), source);
+}
+
+static void
+action_task_list_rename_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ESourceSelector *selector;
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ e_source_selector_edit_primary_selection (selector);
+}
+
+static void
+action_task_list_select_one_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ESourceSelector *selector;
+ ESource *primary;
+ GSList *list, *iter;
+
+ /* XXX ESourceSelector should provide a function for this. */
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+ primary = e_source_selector_peek_primary_selection (selector);
+ g_return_if_fail (primary != NULL);
+
+ list = e_source_selector_get_selection (selector);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ESource *source = iter->data;
+
+ if (source == primary)
+ continue;
+
+ e_source_selector_unselect_source (selector, source);
+ }
+ e_source_selector_free_selection (list);
+
+ e_source_selector_select_source (selector, primary);
+}
+
+static void
+action_task_mark_complete_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModel *model;
+ GSList *list, *iter;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ list = e_calendar_table_get_selected (task_table);
+ model = e_calendar_table_get_model (task_table);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ e_cal_model_tasks_mark_comp_complete (
+ E_CAL_MODEL_TASKS (model), comp_data);
+ }
+
+ g_slist_free (list);
+}
+
+static void
+action_task_mark_incomplete_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModel *model;
+ GSList *list, *iter;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ list = e_calendar_table_get_selected (task_table);
+ model = e_calendar_table_get_model (task_table);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ ECalModelComponent *comp_data = iter->data;
+ e_cal_model_tasks_mark_comp_incomplete (
+ E_CAL_MODEL_TASKS (model), comp_data);
+ }
+
+ g_slist_free (list);
+}
+
+static void
+action_task_new_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ ECal *client;
+ ECalComponent *comp;
+ CompEditor *editor;
+ GSList *list;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ client = comp_data->client;
+ editor = task_editor_new (client, shell, COMP_EDITOR_NEW_ITEM);
+ comp = cal_comp_task_new_with_defaults (client);
+ comp_editor_edit_comp (editor, comp);
+
+ gtk_window_present (GTK_WINDOW (editor));
+
- g_object_unref (comp);
++ g_object_unref (comp);
+ g_object_unref (client);
+}
+
+static void
+action_task_open_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only open the first selected task. */
+ e_task_shell_view_open_task (task_shell_view, comp_data);
+}
+
+static void
+action_task_open_url_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ icalproperty *prop;
+ const gchar *uri;
+ GSList *list;
+
+ 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;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+
+ /* XXX We only open the URI of the first selected task. */
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_URL_PROPERTY);
+ g_return_if_fail (prop == NULL);
+
+ uri = icalproperty_get_url (prop);
+ e_show_uri (GTK_WINDOW (shell_window), uri);
+}
+
+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)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ GtkPrintOperationAction print_action;
+ GSList *list;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ /* XXX We only print the first selected task. */
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ e_cal_component_set_icalcomponent (comp, clone);
+ print_comp (comp, comp_data->client, print_action);
+ g_object_unref (comp);
+}
+
+static void
+action_task_purge_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkWidget *dialog;
+ GtkWidget *widget;
+ gboolean active;
+ gint response;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (!calendar_config_get_confirm_purge ())
+ goto purge;
+
+ /* XXX This needs reworked. The dialog looks like ass. */
+
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_YES_NO,
+ "%s", _("This operation will permanently erase all tasks "
+ "marked as completed. If you continue, you will not be able "
+ "to recover these tasks.\n\nReally erase these tasks?"));
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_NO);
+
+ widget = gtk_check_button_new_with_label (_("Do not ask me again"));
+ gtk_box_pack_start (
+ GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 6);
+ gtk_widget_show (widget);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ gtk_widget_destroy (dialog);
+
+ if (response != GTK_RESPONSE_YES)
+ return;
+
+ if (active)
+ calendar_config_set_confirm_purge (FALSE);
+
+purge:
+
+ /* FIXME */
+ ;
+}
+
+static void
+action_task_save_as_cb (GtkAction *action,
+ ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModelComponent *comp_data;
+ GSList *list;
+ gchar *filename;
+ gchar *string;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ list = e_calendar_table_get_selected (task_table);
+ g_return_if_fail (list != NULL);
+ comp_data = list->data;
+ g_slist_free (list);
+
+ filename = e_file_dialog_save (_("Save as..."), NULL);
+ if (filename == NULL)
+ return;
+
+ string = e_cal_get_component_as_string (
+ comp_data->client, comp_data->icalcomp);
+ if (string == NULL) {
+ g_warning ("Could not convert task to a string");
+ return;
+ }
+
+ e_write_file_uri (filename, string);
+
+ g_free (filename);
+ g_free (string);
+}
+
+static GtkActionEntry task_entries[] = {
+
+ { "task-assign",
+ NULL,
+ N_("_Assign Task"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_assign_cb) },
+
+ { "task-clipboard-copy",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy selected tasks"),
+ G_CALLBACK (action_task_clipboard_copy_cb) },
+
+ { "task-clipboard-cut",
+ GTK_STOCK_CUT,
+ NULL,
+ NULL,
+ N_("Cut selected tasks"),
+ G_CALLBACK (action_task_clipboard_cut_cb) },
+
+ { "task-clipboard-paste",
+ GTK_STOCK_PASTE,
+ NULL,
+ NULL,
+ N_("Paste tasks from the clipboard"),
+ G_CALLBACK (action_task_clipboard_paste_cb) },
+
+ { "task-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete Task"),
+ NULL,
+ N_("Delete selected tasks"),
+ G_CALLBACK (action_task_delete_cb) },
+
+ { "task-forward",
+ "mail-forward",
+ N_("_Forward as iCalendar..."),
+ "<Control>f",
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_forward_cb) },
+
+ { "task-list-copy",
+ GTK_STOCK_COPY,
+ N_("Copy..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_list_copy_cb) },
+
+ { "task-list-delete",
+ GTK_STOCK_DELETE,
+ N_("_Delete"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_list_delete_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",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_list_properties_cb) },
+
+ { "task-list-rename",
+ NULL,
+ N_("_Rename..."),
+ "F2",
+ N_("Rename the selected task list"),
+ G_CALLBACK (action_task_list_rename_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"),
+ "<Control>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",
+ GTK_STOCK_OPEN,
+ N_("_Open Task"),
+ "<Control>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"),
+ "<Control>e",
+ N_("Delete completed tasks"),
+ G_CALLBACK (action_task_purge_cb) },
+
+ { "task-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as iCalendar..."),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_task_save_as_cb) },
+
+ /*** Menus ***/
+
+ { "task-actions-menu",
+ NULL,
+ N_("_Actions"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry task_popup_entries[] = {
+
+ { "task-list-popup-copy",
+ NULL,
+ "task-list-copy" },
+
+ { "task-list-popup-delete",
+ NULL,
+ "task-list-delete" },
+
+ { "task-list-popup-properties",
+ NULL,
+ "task-list-properties" },
+
+ { "task-list-popup-rename",
+ NULL,
+ "task-list-rename" },
+
+ { "task-list-popup-select-one",
+ NULL,
+ "task-list-select-one" },
+
+ { "task-popup-assign",
+ NULL,
+ "task-assign" },
+
+ { "task-popup-clipboard-copy",
+ NULL,
+ "task-clipboard-copy" },
+
+ { "task-popup-clipboard-cut",
+ NULL,
+ "task-clipboard-cut" },
+
+ { "task-popup-clipboard-paste",
+ NULL,
+ "task-clipboard-paste" },
+
+ { "task-popup-delete",
+ NULL,
+ "task-delete" },
+
+ { "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" },
+
+ { "task-popup-save-as",
+ NULL,
+ "task-save-as" },
+};
+
+static GtkToggleActionEntry task_toggle_entries[] = {
+
+ { "task-preview",
+ NULL,
+ N_("Task _Preview"),
+ "<Control>m",
+ N_("Show task preview pane"),
+ G_CALLBACK (action_task_preview_cb),
+ TRUE }
+};
+
+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-completed-tasks",
+ NULL,
+ N_("Completed Tasks"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_COMPLETED_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_("Unmatched"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ TASK_FILTER_UNMATCHED }
+};
+
+static GtkRadioActionEntry task_search_entries[] = {
+
+ { "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",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print the list of tasks"),
+ G_CALLBACK (action_task_list_print_cb) },
+
+ { "task-list-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ NULL,
+ N_("Preview the list of tasks to be printed"),
+ G_CALLBACK (action_task_list_print_preview_cb) },
+
+ { "task-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ NULL,
+ N_("Print the selected task"),
+ G_CALLBACK (action_task_print_cb) }
+};
+
+static EPopupActionEntry lockdown_printing_popup_entries[] = {
+
+ { "task-popup-print",
+ NULL,
+ "task-print" }
+};
+
+void
+e_task_shell_view_actions_init (ETaskShellView *task_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkActionGroup *action_group;
+ GConfBridge *bridge;
+ GtkAction *action;
+ GObject *object;
+ const gchar *key;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (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_search_entries,
+ G_N_ELEMENTS (task_search_entries),
+ TASK_SEARCH_SUMMARY_CONTAINS,
+ NULL, NULL);
+
+ /* 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));
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (ACTION (TASK_PREVIEW));
+ key = "/apps/evolution/calendar/display/show_task_preview";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ /* Fine tuning. */
+
+ action = ACTION (TASK_DELETE);
+ g_object_set (action, "short-label", _("Delete"), NULL);
+
+ g_signal_connect (
+ ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
+ G_CALLBACK (action_gal_save_custom_view_cb), task_shell_view);
+
+ g_signal_connect (
+ ACTION (SEARCH_EXECUTE), "activate",
+ G_CALLBACK (action_search_execute_cb), task_shell_view);
+}
+
+void
+e_task_shell_view_update_search_filter (ETaskShellView *task_shell_view)
+{
+ EShellContent *shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GList *list, *iter;
+ GSList *group;
+ gint ii;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_content = e_shell_view_get_shell_content (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);
+
+ /* Add the standard filter actions. */
+ gtk_action_group_add_radio_actions (
+ action_group, task_filter_entries,
+ G_N_ELEMENTS (task_filter_entries),
+ TASK_FILTER_ANY_CATEGORY,
+ G_CALLBACK (action_search_filter_cb),
+ task_shell_view);
+
+ /* 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);
+
+ /* Build the category actions. */
+
+ list = e_categories_get_list ();
+ for (iter = list, ii = 0; iter != NULL; iter = iter->next, ii++) {
+ const gchar *category_name = iter->data;
+ const gchar *filename;
+ GtkAction *action;
+ gchar *action_name;
+
+ 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);
+
+ /* Convert the category icon file to a themed icon name. */
+ filename = e_categories_get_icon_file_for (category_name);
+ if (filename != NULL && *filename != '\0') {
+ gchar *basename;
+ gchar *cp;
+
+ basename = g_path_get_basename (filename);
+
+ /* Lose the file extension. */
+ if ((cp = strrchr (basename, '.')) != NULL)
+ *cp = '\0';
+
+ g_object_set (
+ radio_action, "icon-name", basename, NULL);
+
+ g_free (basename);
+ }
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_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_list_free (list);
+
+ /* Use any action in the group; doesn't matter which. */
+ e_shell_content_set_filter_action (shell_content, radio_action);
+
+ ii = TASK_FILTER_UNMATCHED;
+ e_shell_content_add_filter_separator_after (shell_content, ii);
+
+ ii = TASK_FILTER_TASKS_WITH_ATTACHMENTS;
+ e_shell_content_add_filter_separator_after (shell_content, ii);
+}
diff --cc calendar/module/e-task-shell-view-actions.h
index 163a640,0000000..d7db39b
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view-actions.h
+++ b/calendar/module/e-task-shell-view-actions.h
@@@ -1,105 -1,0 +1,105 @@@
+/*
+ * e-task-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_VIEW_ACTIONS_H
+#define E_TASK_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* Task Actions */
+#define E_SHELL_WINDOW_ACTION_TASK_ASSIGN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-assign")
+#define E_SHELL_WINDOW_ACTION_TASK_CLIPBOARD_COPY(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-clipboard-copy")
+#define E_SHELL_WINDOW_ACTION_TASK_CLIPBOARD_CUT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-clipboard-cut")
+#define E_SHELL_WINDOW_ACTION_TASK_CLIPBOARD_PASTE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-clipboard-paste")
+#define E_SHELL_WINDOW_ACTION_TASK_DELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-delete")
+#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")
+
+/* 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_RENAME(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-list-rename")
+#define E_SHELL_WINDOW_ACTION_TASK_LIST_SELECT_ONE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "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_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_TASKS_WITH_ATTACHMENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-tasks-with-attachments")
+#define E_SHELL_WINDOW_ACTION_TASK_FILTER_UNMATCHED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "task-filter-unmatched")
+#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")
+
+#endif /* E_TASK_SHELL_VIEW_ACTIONS_H */
diff --cc calendar/module/e-task-shell-view-private.c
index 58bda3d,0000000..d6fd8e3
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view-private.c
+++ b/calendar/module/e-task-shell-view-private.c
@@@ -1,744 -1,0 +1,744 @@@
+/*
+ * e-task-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-task-shell-view-private.h"
+
+#include "widgets/menus/gal-view-factory-etable.h"
+
+static void
+task_shell_view_config_hide_completed_tasks_changed_cb (GConfClient *client,
+ guint id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ ETaskShellView *task_shell_view = user_data;
+ ETaskShellContent *task_shell_content;
+ ETaskShellSidebar *task_shell_sidebar;
+ ECalendarTable *task_table;
+ GList *clients;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ clients = e_task_shell_sidebar_get_clients (task_shell_sidebar);
+
+ e_calendar_table_process_completed_tasks (task_table, clients, TRUE);
+
+ /* Search query takes whether to show completed tasks into account,
+ * so if the preference has changed we need to update the query. */
+ e_task_shell_view_execute_search (task_shell_view);
+
+ g_list_free (clients);
+}
+
+static void
+task_shell_view_config_timezone_changed_cb (GConfClient *client,
+ guint id,
+ GConfEntry *entry,
+ gpointer user_data)
+{
+ ETaskShellView *task_shell_view = user_data;
+
+ e_task_shell_view_update_timezone (task_shell_view);
+}
+
+static void
+task_shell_view_table_popup_event_cb (EShellView *shell_view,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/task-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+}
+
+static void
+task_shell_view_table_user_created_cb (ETaskShellView *task_shell_view,
+ ECalendarTable *task_table)
+{
+ ETaskShellSidebar *task_shell_sidebar;
+ ECalModel *model;
+ ECal *client;
+ ESource *source;
+
+ /* This is the "Click to Add" handler. */
+
+ model = e_calendar_table_get_model (task_table);
+ client = e_cal_model_get_default_client (model);
+ source = e_cal_get_source (client);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ e_task_shell_sidebar_add_source (task_shell_sidebar, source);
+
+ e_cal_model_add_client (model, client);
+}
+
+static void
+task_shell_view_selector_client_added_cb (ETaskShellView *task_shell_view,
+ ECal *client)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModel *model;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_calendar_table_get_model (task_table);
+
+ e_cal_model_add_client (model, client);
+ e_task_shell_view_update_timezone (task_shell_view);
+}
+
+static void
+task_shell_view_selector_client_removed_cb (ETaskShellView *task_shell_view,
+ ECal *client)
+{
+ ETaskShellContent *task_shell_content;
+ ECalendarTable *task_table;
+ ECalModel *model;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_calendar_table_get_model (task_table);
+
+ e_cal_model_remove_client (model, client);
+}
+
+static gboolean
+task_shell_view_selector_popup_event_cb (EShellView *shell_view,
+ ESource *primary_source,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/task-list-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+
+ return TRUE;
+}
+
+static gboolean
+task_shell_view_update_timeout_cb (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskShellSidebar *task_shell_sidebar;
+ ECalendarTable *task_table;
+ ECalModel *model;
+ GList *clients;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_calendar_table_get_model (task_table);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ clients = e_task_shell_sidebar_get_clients (task_shell_sidebar);
+
+ e_calendar_table_process_completed_tasks (task_table, clients, FALSE);
+ e_cal_model_tasks_update_due_tasks (E_CAL_MODEL_TASKS (model));
+
+ g_list_free (clients);
+
+ return TRUE;
+}
+
+static void
+task_shell_view_load_view_collection (EShellViewClass *shell_view_class)
+{
+ GalViewCollection *collection;
+ GalViewFactory *factory;
+ ETableSpecification *spec;
+ const gchar *base_dir;
+ gchar *filename;
+
+ collection = shell_view_class->view_collection;
+
+ base_dir = EVOLUTION_ETSPECDIR;
+ spec = e_table_specification_new ();
+ filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
+ if (!e_table_specification_load_from_file (spec, filename))
+ g_critical ("Unable to load ETable specification file "
+ "for tasks");
+ g_free (filename);
+
+ factory = gal_view_factory_etable_new (spec);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+ g_object_unref (spec);
+
+ gal_view_collection_load (collection);
+}
+
+static void
+task_shell_view_notify_view_id_cb (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ view_instance =
+ e_task_shell_content_get_view_instance (task_shell_content);
+ view_id = e_shell_view_get_view_id (E_SHELL_VIEW (task_shell_view));
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_task_shell_view_private_init (ETaskShellView *task_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ if (!gal_view_collection_loaded (shell_view_class->view_collection))
+ task_shell_view_load_view_collection (shell_view_class);
+
+ g_signal_connect (
+ task_shell_view, "notify::view-id",
+ G_CALLBACK (task_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_task_shell_view_private_constructed (ETaskShellView *task_shell_view)
+{
+ ETaskShellViewPrivate *priv = task_shell_view->priv;
+ ETaskShellContent *task_shell_content;
+ ETaskShellSidebar *task_shell_sidebar;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ ECalendarTable *task_table;
+ ECalModel *model;
+ ETable *table;
+ ESourceSelector *selector;
+ guint id;
+
+ shell_view = E_SHELL_VIEW (task_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);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ e_shell_window_add_action_group (shell_window, "tasks");
+ e_shell_window_add_action_group (shell_window, "tasks-filter");
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->task_shell_backend = g_object_ref (shell_backend);
+ priv->task_shell_content = g_object_ref (shell_content);
+ priv->task_shell_sidebar = g_object_ref (shell_sidebar);
+
+ task_shell_content = E_TASK_SHELL_CONTENT (shell_content);
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_calendar_table_get_model (task_table);
+ table = e_calendar_table_get_table (task_table);
+
+ task_shell_sidebar = E_TASK_SHELL_SIDEBAR (shell_sidebar);
+ selector = e_task_shell_sidebar_get_selector (task_shell_sidebar);
+
+ g_signal_connect_swapped (
+ task_table, "open-component",
+ G_CALLBACK (e_task_shell_view_open_task),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ task_table, "popup-event",
+ G_CALLBACK (task_shell_view_table_popup_event_cb),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ task_table, "status-message",
+ G_CALLBACK (e_task_shell_view_set_status_message),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ task_table, "user-created",
+ G_CALLBACK (task_shell_view_table_user_created_cb),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ model, "model-changed",
+ G_CALLBACK (e_task_shell_view_update_sidebar),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ model, "model-rows-deleted",
+ G_CALLBACK (e_task_shell_view_update_sidebar),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ model, "model-rows-inserted",
+ G_CALLBACK (e_task_shell_view_update_sidebar),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ table, "selection-change",
+ G_CALLBACK (e_task_shell_view_update_sidebar),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ task_shell_sidebar, "client-added",
+ G_CALLBACK (task_shell_view_selector_client_added_cb),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ task_shell_sidebar, "client-removed",
+ G_CALLBACK (task_shell_view_selector_client_removed_cb),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ task_shell_sidebar, "status-message",
+ G_CALLBACK (e_task_shell_view_set_status_message),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "popup-event",
+ G_CALLBACK (task_shell_view_selector_popup_event_cb),
+ task_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "primary-selection-changed",
+ G_CALLBACK (e_shell_view_update_actions),
+ task_shell_view);
+
+ e_categories_register_change_listener (
+ G_CALLBACK (e_task_shell_view_update_search_filter),
+ task_shell_view);
+
+ task_shell_view_update_timeout_cb (task_shell_view);
+ priv->update_timeout = g_timeout_add_full (
+ G_PRIORITY_LOW, 60000, (GSourceFunc)
+ task_shell_view_update_timeout_cb,
+ task_shell_view, NULL);
+
+ /* Listen for configuration changes. */
+
+ /* Timezone */
+ id = calendar_config_add_notification_timezone (
+ task_shell_view_config_timezone_changed_cb, task_shell_view);
+ priv->notifications = g_list_prepend (
+ priv->notifications, GUINT_TO_POINTER (id));
+
+ /* Hide Completed Tasks (enable/units/value) */
+ id = calendar_config_add_notification_hide_completed_tasks (
+ task_shell_view_config_hide_completed_tasks_changed_cb,
+ task_shell_view);
+ priv->notifications = g_list_prepend (
+ priv->notifications, GUINT_TO_POINTER (id));
+ id = calendar_config_add_notification_hide_completed_tasks_units (
+ task_shell_view_config_hide_completed_tasks_changed_cb,
+ task_shell_view);
+ priv->notifications = g_list_prepend (
+ priv->notifications, GUINT_TO_POINTER (id));
+ id = calendar_config_add_notification_hide_completed_tasks_value (
+ task_shell_view_config_hide_completed_tasks_changed_cb,
+ task_shell_view);
+ priv->notifications = g_list_prepend (
+ priv->notifications, GUINT_TO_POINTER (id));
+
+ e_task_shell_view_actions_init (task_shell_view);
+ e_task_shell_view_update_sidebar (task_shell_view);
+ e_task_shell_view_update_search_filter (task_shell_view);
+ e_task_shell_view_update_timezone (task_shell_view);
+
+ e_task_shell_view_execute_search (task_shell_view);
+}
+
+void
+e_task_shell_view_private_dispose (ETaskShellView *task_shell_view)
+{
+ ETaskShellViewPrivate *priv = task_shell_view->priv;
+ GList *iter;
+
+ DISPOSE (priv->task_shell_backend);
+ DISPOSE (priv->task_shell_content);
+ DISPOSE (priv->task_shell_sidebar);
+
+ if (task_shell_view->priv->activity != NULL) {
+ /* XXX Activity is no cancellable. */
+ e_activity_complete (task_shell_view->priv->activity);
+ g_object_unref (task_shell_view->priv->activity);
+ task_shell_view->priv->activity = NULL;
+ }
+
+ if (priv->update_timeout > 0) {
+ g_source_remove (priv->update_timeout);
+ priv->update_timeout = 0;
+ }
+
+ for (iter = priv->notifications; iter != NULL; iter = iter->next) {
+ guint notification_id = GPOINTER_TO_UINT (iter->data);
+ calendar_config_remove_notification (notification_id);
+ }
+ g_list_free (priv->notifications);
+ priv->notifications = NULL;
+}
+
+void
+e_task_shell_view_private_finalize (ETaskShellView *task_shell_view)
+{
+ /* XXX Nothing to do? */
+}
+
+void
+e_task_shell_view_execute_search (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ GtkAction *action;
+ GString *string;
+ ECalComponentPreview *task_preview;
+ ECalendarTable *task_table;
+ ECalModel *model;
+ FilterRule *rule;
+ const gchar *format;
+ const gchar *text;
+ time_t start_range;
+ time_t end_range;
+ gchar *start, *end;
+ gchar *query;
+ gchar *temp;
+ gint value;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ text = e_shell_content_get_search_text (shell_content);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ action = ACTION (TASK_SEARCH_ANY_FIELD_CONTAINS);
+ value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+
+ if (text == NULL || *text == '\0') {
+ text = "";
+ value = TASK_SEARCH_SUMMARY_CONTAINS;
+ }
+
+ switch (value) {
+ default:
+ text = "";
+ /* fall through */
+
+ case TASK_SEARCH_SUMMARY_CONTAINS:
+ format = "(contains? \"summary\" %s)";
+ break;
+
+ case TASK_SEARCH_DESCRIPTION_CONTAINS:
+ format = "(contains? \"description\" %s)";
+ break;
+
+ case TASK_SEARCH_ANY_FIELD_CONTAINS:
+ format = "(contains? \"any\" %s)";
+ break;
+ }
+
+ /* Build the query. */
+ string = g_string_new ("");
+ e_sexp_encode_string (string, text);
+ query = g_strdup_printf (format, string->str);
+ g_string_free (string, TRUE);
+
+ /* Apply selected filter. */
+ value = e_shell_content_get_filter_value (shell_content);
+ switch (value) {
+ case TASK_FILTER_ANY_CATEGORY:
+ break;
+
+ case TASK_FILTER_UNMATCHED:
+ temp = g_strdup_printf (
+ "(and (has-categories? #f) %s)", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_NEXT_7_DAYS_TASKS:
+ start_range = time (NULL);
+ end_range = time_add_day (start_range, 7);
+ start = isodate_from_time_t (start_range);
+ end = isodate_from_time_t (end_range);
+
+ temp = g_strdup_printf (
+ "(and %s (due-in-time-range? "
+ "(make-time \"%s\") (make-time \"%s\")))",
+ query, start, end);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_ACTIVE_TASKS:
+ start_range = time (NULL);
+ end_range = time_add_day (start_range, 365);
+ start = isodate_from_time_t (start_range);
+ end = isodate_from_time_t (end_range);
+
+ temp = g_strdup_printf (
+ "(and %s (due-in-time-range? "
+ "(make-time \"%s\") (make-time \"%s\")) "
+ "(not (is-completed?)))",
+ query, start, end);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_OVERDUE_TASKS:
+ start_range = 0;
+ end_range = time (NULL);
+ start = isodate_from_time_t (start_range);
+ end = isodate_from_time_t (end_range);
+
+ temp = g_strdup_printf (
+ "(and %s (due-in-time-range? "
+ "(make-time \"%s\") (make-time \"%s\")) "
+ "(not (is-completed?)))",
+ query, start, end);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_COMPLETED_TASKS:
+ temp = g_strdup_printf (
+ "(and (is-completed?) %s)", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case TASK_FILTER_TASKS_WITH_ATTACHMENTS:
+ temp = g_strdup_printf (
+ "(and (has-attachments?) %s)", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ {
+ GList *categories;
+ const gchar *category_name;
+
+ categories = e_categories_get_list ();
+ category_name = g_list_nth_data (categories, value);
+ g_list_free (categories);
+
+ temp = g_strdup_printf (
+ "(and (has-categories? \"%s\") %s)",
+ category_name, query);
+ g_free (query);
+ query = temp;
+ break;
+ }
+ }
+
+ /* Honor the user's preference to hide completed tasks. */
+ temp = calendar_config_get_hide_completed_tasks_sexp (FALSE);
+ if (temp != NULL) {
+ gchar *temp2;
+
+ temp2 = g_strdup_printf ("(and %s %s)", temp, query);
+ g_free (query);
+ g_free (temp);
+ query = temp2;
+ }
+
+ /* XXX This is wrong. We need to programmatically construct a
+ * FilterRule, tell it to build code, and pass the resulting
+ * expression string to ECalModel. */
+ rule = filter_rule_new ();
+ e_shell_content_set_search_rule (shell_content, rule);
+ g_object_unref (rule);
+
+ /* Submit the query. */
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+ model = e_calendar_table_get_model (task_table);
+ e_cal_model_set_search_query (model, query);
+ g_free (query);
+
+ task_preview =
+ e_task_shell_content_get_task_preview (task_shell_content);
+ e_cal_component_preview_clear (task_preview);
+}
+
+void
+e_task_shell_view_open_task (ETaskShellView *task_shell_view,
+ ECalModelComponent *comp_data)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ CompEditor *editor;
+ CompEditorFlags flags = 0;
+ ECalComponent *comp;
+ icalcomponent *clone;
+ icalproperty *prop;
+ const gchar *uid;
+
+ g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
+ g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+
+ uid = icalcomponent_get_uid (comp_data->icalcomp);
+ editor = comp_editor_find_instance (uid);
+
+ if (editor != NULL)
+ goto exit;
+
+ comp = e_cal_component_new ();
+ clone = icalcomponent_new_clone (comp_data->icalcomp);
+ e_cal_component_set_icalcomponent (comp, clone);
+
+ prop = icalcomponent_get_first_property (
+ comp_data->icalcomp, ICAL_ATTENDEE_PROPERTY);
+ if (prop != NULL)
+ flags |= COMP_EDITOR_IS_ASSIGNED;
+
+ if (itip_organizer_is_user (comp, comp_data->client))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ if (!e_cal_component_has_attendees (comp))
+ flags |= COMP_EDITOR_USER_ORG;
+
+ editor = task_editor_new (comp_data->client, shell, flags);
+ comp_editor_edit_comp (editor, comp);
+
+ g_object_ref (comp);
+
+ if (flags & COMP_EDITOR_IS_ASSIGNED)
+ task_editor_show_assignment (TASK_EDITOR (editor));
+
+exit:
+ gtk_window_present (GTK_WINDOW (editor));
+}
+
+void
+e_task_shell_view_set_status_message (ETaskShellView *task_shell_view,
+ const gchar *status_message,
+ gdouble percent)
+{
+ EActivity *activity;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+
+ g_return_if_fail (E_IS_TASK_SHELL_VIEW (task_shell_view));
+
+ activity = task_shell_view->priv->activity;
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ if (status_message == NULL || *status_message == '\0') {
+ if (activity != NULL) {
+ e_activity_complete (activity);
+ g_object_unref (activity);
+ activity = NULL;
+ }
+
+ } else if (activity == NULL) {
+ activity = e_activity_new (status_message);
+ e_activity_set_percent (activity, percent);
+ e_shell_backend_add_activity (shell_backend, activity);
+
+ } else {
+ e_activity_set_percent (activity, percent);
+ e_activity_set_primary_text (activity, status_message);
+ }
+
+ task_shell_view->priv->activity = activity;
+}
+
+void
+e_task_shell_view_update_sidebar (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ ECalendarTable *task_table;
+ ECalModel *model;
+ ETable *table;
+ GString *string;
+ const gchar *format;
+ gint n_rows;
+ gint n_selected;
+
+ shell_view = E_SHELL_VIEW (task_shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_table = e_task_shell_content_get_task_table (task_shell_content);
+
+ model = e_calendar_table_get_model (task_table);
+ table = e_calendar_table_get_table (task_table);
+
+ n_rows = e_table_model_row_count (E_TABLE_MODEL (model));
+ n_selected = e_table_selected_count (table);
+
+ string = g_string_sized_new (64);
+
+ format = ngettext ("%d task", "%d tasks", n_rows);
+ g_string_append_printf (string, format, n_rows);
+
+ if (n_selected > 0) {
+ format = _("%d selected");
+ g_string_append_len (string, ", ", 2);
+ g_string_append_printf (string, format, n_selected);
+ }
+
+ e_shell_sidebar_set_secondary_text (shell_sidebar, string->str);
+
+ g_string_free (string, TRUE);
+}
+
+void
+e_task_shell_view_update_timezone (ETaskShellView *task_shell_view)
+{
+ ETaskShellContent *task_shell_content;
+ ETaskShellSidebar *task_shell_sidebar;
+ ECalComponentPreview *task_preview;
+ icaltimezone *timezone;
+ GList *clients, *iter;
+
+ task_shell_content = task_shell_view->priv->task_shell_content;
+ task_preview = e_task_shell_content_get_task_preview (task_shell_content);
+
+ task_shell_sidebar = task_shell_view->priv->task_shell_sidebar;
+ clients = e_task_shell_sidebar_get_clients (task_shell_sidebar);
+
+ timezone = calendar_config_get_icaltimezone ();
+
+ for (iter = clients; iter != NULL; iter = iter->next) {
+ ECal *client = iter->data;
+
+ if (e_cal_get_load_state (client) == E_CAL_LOAD_LOADED)
+ e_cal_set_default_timezone (client, timezone, NULL);
+ }
+
+ e_cal_component_preview_set_default_timezone (task_preview, timezone);
+
+ g_list_free (clients);
+}
diff --cc calendar/module/e-task-shell-view-private.h
index c613e9e,0000000..d3bb3cf
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view-private.h
+++ b/calendar/module/e-task-shell-view-private.h
@@@ -1,141 -1,0 +1,141 @@@
+/*
+ * e-task-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_VIEW_PRIVATE_H
+#define E_TASK_SHELL_VIEW_PRIVATE_H
+
+#include "e-task-shell-view.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <libecal/e-cal-time-util.h>
+#include <libedataserver/e-categories.h>
+#include <libedataserver/e-sexp.h>
+
+#include "e-util/e-dialog-utils.h"
+#include "e-util/e-error.h"
+#include "e-util/e-util.h"
+#include "e-util/gconf-bridge.h"
+#include "widgets/misc/e-popup-action.h"
+
+#include "calendar/common/authentication.h"
+#include "calendar/gui/calendar-config.h"
+#include "calendar/gui/comp-util.h"
+#include "calendar/gui/e-cal-component-preview.h"
+#include "calendar/gui/e-cal-model-tasks.h"
+#include "calendar/gui/e-calendar-selector.h"
+#include "calendar/gui/print.h"
+#include "calendar/gui/dialogs/calendar-setup.h"
+#include "calendar/gui/dialogs/copy-source-dialog.h"
+#include "calendar/gui/dialogs/task-editor.h"
+
+#include "e-task-shell-backend.h"
+#include "e-task-shell-content.h"
+#include "e-task-shell-sidebar.h"
+#include "e-task-shell-view-actions.h"
+
+#define E_TASK_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* For use in dispose() methods. */
+#define DISPOSE(obj) \
+ G_STMT_START { \
+ if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
+ } G_STMT_END
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "e-calendar-table.etspec"
+
+G_BEGIN_DECLS
+
+/* Filter items are displayed in ascending order.
+ * Non-negative values are reserved for categories. */
+enum {
+ TASK_FILTER_ANY_CATEGORY = -7,
+ TASK_FILTER_UNMATCHED = -6,
+ TASK_FILTER_NEXT_7_DAYS_TASKS = -5,
+ TASK_FILTER_ACTIVE_TASKS = -4,
+ TASK_FILTER_OVERDUE_TASKS = -3,
+ TASK_FILTER_COMPLETED_TASKS = -2,
+ TASK_FILTER_TASKS_WITH_ATTACHMENTS = -1
+};
+
+/* Search items are displayed in ascending order. */
+enum {
+ TASK_SEARCH_SUMMARY_CONTAINS,
+ TASK_SEARCH_DESCRIPTION_CONTAINS,
+ TASK_SEARCH_ANY_FIELD_CONTAINS
+};
+
+struct _ETaskShellViewPrivate {
+
+ /* These are just for convenience. */
+ ETaskShellBackend *task_shell_backend;
+ ETaskShellContent *task_shell_content;
+ ETaskShellSidebar *task_shell_sidebar;
+
+ EActivity *activity;
+ guint update_timeout;
+
+ /* GConf notification IDs */
+ GList *notifications;
+};
+
+void e_task_shell_view_private_init
+ (ETaskShellView *task_shell_view,
+ EShellViewClass *shell_view_class);
+void e_task_shell_view_private_constructed
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_private_dispose
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_private_finalize
+ (ETaskShellView *task_shell_view);
+
+/* Private Utilities */
+
+void e_task_shell_view_actions_init
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_execute_search
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_open_task
+ (ETaskShellView *task_shell_view,
+ ECalModelComponent *comp_data);
+void e_task_shell_view_set_status_message
+ (ETaskShellView *task_shell_view,
+ const gchar *status_message,
+ gdouble percent);
+void e_task_shell_view_update_sidebar
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_update_search_filter
+ (ETaskShellView *task_shell_view);
+void e_task_shell_view_update_timezone
+ (ETaskShellView *task_shell_view);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_VIEW_PRIVATE_H */
diff --cc calendar/module/e-task-shell-view.c
index d2f7899,0000000..ce1b53a
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view.c
+++ b/calendar/module/e-task-shell-view.c
@@@ -1,255 -1,0 +1,255 @@@
+/*
+ * e-task-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-task-shell-view-private.h"
+
+static gpointer parent_class;
+static GType task_shell_view_type;
+
+static void
+task_shell_view_dispose (GObject *object)
+{
+ e_task_shell_view_private_dispose (E_TASK_SHELL_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+task_shell_view_finalize (GObject *object)
+{
+ e_task_shell_view_private_finalize (E_TASK_SHELL_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+task_shell_view_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ e_task_shell_view_private_constructed (E_TASK_SHELL_VIEW (object));
+}
+
+static void
+task_shell_view_update_actions (EShellView *shell_view)
+{
+ ETaskShellViewPrivate *priv;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ const gchar *label;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean any_tasks_selected;
+ gboolean has_primary_source;
+ gboolean multiple_tasks_selected;
+ gboolean primary_source_is_system;
+ gboolean selection_has_url;
+ gboolean selection_is_assignable;
+ gboolean single_task_selected;
+ gboolean some_tasks_complete;
+ gboolean some_tasks_incomplete;
+ gboolean sources_are_editable;
+
+ priv = E_TASK_SHELL_VIEW_GET_PRIVATE (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);
+
+ single_task_selected =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_SINGLE);
+ multiple_tasks_selected =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_MULTIPLE);
+ selection_is_assignable =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_CAN_ASSIGN);
+ sources_are_editable =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_CAN_EDIT);
+ some_tasks_complete =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_COMPLETE);
+ some_tasks_incomplete =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_INCOMPLETE);
+ selection_has_url =
+ (state & E_TASK_SHELL_CONTENT_SELECTION_HAS_URL);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ state = e_shell_sidebar_check_state (shell_sidebar);
+
+ has_primary_source =
+ (state & E_TASK_SHELL_SIDEBAR_HAS_PRIMARY_SOURCE);
+ primary_source_is_system =
+ (state & E_TASK_SHELL_SIDEBAR_PRIMARY_SOURCE_IS_SYSTEM);
+
+ any_tasks_selected =
+ (single_task_selected || multiple_tasks_selected);
+
+ action = ACTION (TASK_ASSIGN);
+ sensitive =
+ single_task_selected && sources_are_editable &&
+ selection_is_assignable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_CLIPBOARD_COPY);
+ sensitive = any_tasks_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_CLIPBOARD_CUT);
+ sensitive = any_tasks_selected && sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_CLIPBOARD_PASTE);
+ sensitive = sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_DELETE);
+ sensitive = any_tasks_selected && sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+ if (multiple_tasks_selected)
+ label = _("Delete Tasks");
+ else
+ label = _("Delete Task");
+ g_object_set (action, "label", label, NULL);
+
+ action = ACTION (TASK_FORWARD);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_COPY);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_DELETE);
+ sensitive = has_primary_source && !primary_source_is_system;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_PROPERTIES);
+ sensitive = has_primary_source;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_LIST_RENAME);
+ sensitive = has_primary_source;
+ gtk_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);
+
+ action = ACTION (TASK_MARK_INCOMPLETE);
+ sensitive =
+ any_tasks_selected &&
+ sources_are_editable &&
+ some_tasks_complete;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_OPEN);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_OPEN_URL);
+ sensitive = single_task_selected && selection_has_url;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_PRINT);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_PURGE);
+ sensitive = sources_are_editable;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (TASK_SAVE_AS);
+ sensitive = single_task_selected;
+ gtk_action_set_sensitive (action, sensitive);
+}
+
+static void
+task_shell_view_class_init (ETaskShellViewClass *class,
+ GTypeModule *type_module)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETaskShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = task_shell_view_dispose;
+ object_class->finalize = task_shell_view_finalize;
+ object_class->constructed = task_shell_view_constructed;
+
+ 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_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_task_shell_sidebar_new;
+ shell_view_class->update_actions = task_shell_view_update_actions;
+}
+
+static void
+task_shell_view_init (ETaskShellView *task_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ task_shell_view->priv =
+ E_TASK_SHELL_VIEW_GET_PRIVATE (task_shell_view);
+
+ e_task_shell_view_private_init (task_shell_view, shell_view_class);
+}
+
+GType
+e_task_shell_view_get_type (void)
+{
+ return task_shell_view_type;
+}
+
+void
+e_task_shell_view_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (ETaskShellViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) task_shell_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ type_module,
+ sizeof (ETaskShellView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) task_shell_view_init,
+ NULL /* value_table */
+ };
+
+ task_shell_view_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_VIEW,
+ "ETaskShellView", &type_info, 0);
+}
diff --cc calendar/module/e-task-shell-view.h
index 8dca041,0000000..8478e53
mode 100644,000000..100644
--- a/calendar/module/e-task-shell-view.h
+++ b/calendar/module/e-task-shell-view.h
@@@ -1,67 -1,0 +1,67 @@@
+/*
+ * e-task-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TASK_SHELL_VIEW_H
+#define E_TASK_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+#include <libedataserver/e-source-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TASK_SHELL_VIEW \
+ (e_task_shell_view_get_type ())
+#define E_TASK_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellView))
+#define E_TASK_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewClass))
+#define E_IS_TASK_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TASK_SHELL_VIEW))
+#define E_IS_TASK_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TASK_SHELL_VIEW))
+#define E_TASK_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TASK_SHELL_VIEW, ETaskShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETaskShellView ETaskShellView;
+typedef struct _ETaskShellViewClass ETaskShellViewClass;
+typedef struct _ETaskShellViewPrivate ETaskShellViewPrivate;
+
+struct _ETaskShellView {
+ EShellView parent;
+ ETaskShellViewPrivate *priv;
+};
+
+struct _ETaskShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_task_shell_view_get_type (void);
+void e_task_shell_view_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_TASK_SHELL_VIEW_H */
diff --cc calendar/module/evolution-module-calendar.c
index e89005f,0000000..63bf98e
mode 100644,000000..100644
--- a/calendar/module/evolution-module-calendar.c
+++ b/calendar/module/evolution-module-calendar.c
@@@ -1,65 -1,0 +1,65 @@@
+/*
+ * evolution-module-calendar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-cal-shell-backend.h"
+#include "e-cal-shell-content.h"
+#include "e-cal-shell-sidebar.h"
+#include "e-cal-shell-view.h"
+
+#include "e-memo-shell-backend.h"
+#include "e-memo-shell-content.h"
+#include "e-memo-shell-sidebar.h"
+#include "e-memo-shell-view.h"
+
+#include "e-task-shell-backend.h"
+#include "e-task-shell-content.h"
+#include "e-task-shell-sidebar.h"
+#include "e-task-shell-view.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ /* Register dynamically loaded types. */
+
+ e_cal_shell_backend_register_type (type_module);
+ e_cal_shell_content_register_type (type_module);
+ e_cal_shell_sidebar_register_type (type_module);
+ e_cal_shell_view_register_type (type_module);
+
+ e_memo_shell_backend_register_type (type_module);
+ e_memo_shell_content_register_type (type_module);
+ e_memo_shell_sidebar_register_type (type_module);
+ e_memo_shell_view_register_type (type_module);
+
+ e_task_shell_backend_register_type (type_module);
+ e_task_shell_content_register_type (type_module);
+ e_task_shell_sidebar_register_type (type_module);
+ e_task_shell_view_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --cc composer/Makefile.am
index 3ba27e8,97debe5..12ad680
--- a/composer/Makefile.am
+++ b/composer/Makefile.am
@@@ -50,10 -52,6 +50,9 @@@ libcomposer_la_SOURCES =
e-composer-text-header.c \
e-msg-composer.c
-
+libcomposer_la_LIBADD = \
+ $(top_builddir)/widgets/misc/libemiscwidgets.la \
+ $(top_builddir)/em-format/libemformat.la
uidir = $(evolutionuidir)
ui_DATA = evolution-composer.ui
diff --cc composer/e-composer-header-table.c
index df96d76,f25c3b7..d883d8e
--- a/composer/e-composer-header-table.c
+++ b/composer/e-composer-header-table.c
@@@ -514,7 -514,7 +514,6 @@@ composer_header_table_constructor (GTyp
if (composer_lite)
gtk_widget_show_all ((GtkWidget *)priv->actions_container);
-
-
ii = E_COMPOSER_HEADER_FROM;
/* Leave room in the "From" row for signature stuff. */
diff --cc composer/e-composer-private.c
index fffd18a,2a2cea6..d4ec9dd
--- a/composer/e-composer-private.c
+++ b/composer/e-composer-private.c
@@@ -103,7 -101,7 +103,7 @@@ e_composer_private_init (EMsgComposer *
widget = gtkhtml_editor_get_managed_widget (editor, "/main-menu");
gtk_widget_hide (widget);
widget = gtkhtml_editor_get_managed_widget (editor, "/main-toolbar");
- gtk_toolbar_set_style ((GtkToolbar *)widget, GTK_TOOLBAR_BOTH_HORIZ);
- gtk_toolbar_set_style ((GtkToolbar *)widget, GTK_TOOLBAR_BOTH_HORIZ);
++ gtk_toolbar_set_style (GTK_TOOLBAR (widget), GTK_TOOLBAR_BOTH_HORIZ);
gtk_widget_hide (widget);
}
@@@ -161,7 -159,7 +161,6 @@@
gtk_container_remove((GtkContainer *)send_widget, gtk_bin_get_child ((GtkBin *)send_widget));
gtk_container_add((GtkContainer *)send_widget, tmp);
gtk_button_set_relief ((GtkButton *)send_widget, GTK_RELIEF_NORMAL);
-
-
path = "/main-toolbar/pre-main-toolbar/save-draft";
send_widget = gtk_ui_manager_get_widget (ui_manager, path);
tmp = gtk_hbox_new (FALSE, 0);
diff --cc composer/e-msg-composer.c
index 2589786,946bff2..98f2c31
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@@ -2854,9 -2926,9 +2854,9 @@@ e_msg_composer_new_with_message (CamelM
}
/* Remove any other X-Evolution-* headers that may have been set */
- xev = mail_tool_remove_xevolution_headers (message);
+ xev = emcu_remove_xevolution_headers (message);
camel_header_raw_clear (&xev);
-
+
/* Check for receipt request */
if (camel_medium_get_header (CAMEL_MEDIUM (message), "Disposition-Notification-To")) {
action = GTK_TOGGLE_ACTION (ACTION (REQUEST_READ_RECEIPT));
diff --cc configure.ac
index b912c95,1a9f816..6a4826c
--- a/configure.ac
+++ b/configure.ac
@@@ -46,9 -45,35 +46,36 @@@ m4_define([libnotify_minimum_version],
m4_define([gnome_pilot_minimum_version], [2.0.15])
m4_define([gweather_minimum_version], [2.25.3])
+ # Compiler Warning Flags
+
+ AS_COMPILER_FLAGS(WARNING_FLAGS,
+ "-DG_DISABLE_DEPRECATED
+ -DPANGO_DISABLE_DEPRECATED
+ -DGDK_PIXBUF_DISABLE_DEPRECATED
+ -DGDK_DISABLE_DEPRECATED
+ -Wall -Wextra
+ -Wno-missing-field-initializers
+ -Wno-sign-compare
+ -Wno-unused-parameter
+ -Wdeclaration-after-statement
+ -Werror-implicit-function-declaration
+ -Wformat-nonliteral -Wformat-security -Winit-self
+ -Wmissing-declarations -Wmissing-include-dirs
+ -Wmissing-noreturn -Wnested-externs -Wpointer-arith
+ -Wredundant-decls -Wundef -Wwrite-strings")
+ AC_SUBST(WARNING_FLAGS)
+
+ # Other useful compiler warnings for test builds only.
+ # These may produce warnings we have no control over.
+ #
+ # -Wmissing-format-attribute
+ # -Wshadow
+
+ CFLAGS="$CFLAGS $WARNING_FLAGS"
+
# GNOME Documentation
GNOME_DOC_INIT
+GTK_DOC_CHECK(1.10)
# Gross hack to enable 'make dist' on automake 1.9+tar 1.14.
# The extra brackets are to foil regex-based scans.
m4_ifdef([_A][M_PROG_TAR],[_A][M_SET_OPTION([tar-ustar])])
diff --cc e-util/e-account-utils.c
index d98a378,0000000..5fdffd8
mode 100644,000000..100644
--- a/e-util/e-account-utils.c
+++ b/e-util/e-account-utils.c
@@@ -1,96 -1,0 +1,96 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#include "e-account-utils.h"
+
+#include <gconf/gconf-client.h>
+
+static EAccountList *global_account_list;
+
+EAccountList *
+e_get_account_list (void)
+{
+ if (G_UNLIKELY (global_account_list == NULL)) {
+ GConfClient *client;
+
+ client = gconf_client_get_default ();
+ global_account_list = e_account_list_new (client);
+ g_object_unref (client);
+ }
+
+ g_return_val_if_fail (global_account_list != NULL, NULL);
+
+ return global_account_list;
+}
+
+EAccount *
+e_get_default_account (void)
+{
+ EAccountList *account_list;
+ const EAccount *account;
+
+ account_list = e_get_account_list ();
+ account = e_account_list_get_default (account_list);
+
+ /* XXX EAccountList misuses const. */
+ return (EAccount *) account;
+}
+
+void
+e_set_default_account (EAccount *account)
+{
+ EAccountList *account_list;
+
+ g_return_if_fail (E_IS_ACCOUNT (account));
+
+ account_list = e_get_account_list ();
+ e_account_list_set_default (account_list, account);
+}
+
+EAccount *
+e_get_account_by_name (const gchar *name)
+{
+ EAccountList *account_list;
+ const EAccount *account;
+ e_account_find_t find;
+
+ g_return_val_if_fail (name != NULL, NULL);
+
+ find = E_ACCOUNT_FIND_NAME;
+ account_list = e_get_account_list ();
+ account = e_account_list_find (account_list, find, name);
+
+ /* XXX EAccountList misuses const. */
+ return (EAccount *) account;
+}
+
+EAccount *
+e_get_account_by_uid (const gchar *uid)
+{
+ EAccountList *account_list;
+ const EAccount *account;
+ e_account_find_t find;
+
+ g_return_val_if_fail (uid != NULL, NULL);
+
+ find = E_ACCOUNT_FIND_UID;
+ account_list = e_get_account_list ();
+ account = e_account_list_find (account_list, find, uid);
+
+ /* XXX EAccountList misuses const. */
+ return (EAccount *) account;
+}
diff --cc e-util/e-account-utils.h
index 2426234,0000000..f2ae8fc
mode 100644,000000..100644
--- a/e-util/e-account-utils.h
+++ b/e-util/e-account-utils.h
@@@ -1,35 -1,0 +1,35 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#ifndef E_ACCOUNT_UTILS_H
+#define E_ACCOUNT_UTILS_H
+
+#include <glib.h>
+#include <libedataserver/e-account.h>
+#include <libedataserver/e-account-list.h>
+
+G_BEGIN_DECLS
+
+EAccountList * e_get_account_list (void);
+EAccount * e_get_default_account (void);
+void e_set_default_account (EAccount *account);
+EAccount * e_get_account_by_name (const gchar *name);
+EAccount * e_get_account_by_uid (const gchar *uid);
+
+G_END_DECLS
+
+#endif /* E_ACCOUNT_UTILS_H */
diff --cc e-util/e-logger.c
index 97d27d0,19326d2..6c391ef
--- a/e-util/e-logger.c
+++ b/e-util/e-logger.c
@@@ -240,13 -240,13 +240,13 @@@ e_logger_log (ELogger *logger
fprintf (logger->priv->fp, "%d:%ld:%s\n", level, t, primary);
fprintf (logger->priv->fp, "%d:%ld:%s\n", level, t, secondary);
- set_dirty (logger);
+ logger_set_dirty (logger);
}
- void
+ void
e_logger_get_logs (ELogger *logger,
ELogFunction func,
- gpointer data)
+ gpointer user_data)
{
FILE *fp;
gchar buf[250];
diff --cc e-util/e-marshal.list
index b667ca4,3666024..d6a3f0c
--- a/e-util/e-marshal.list
+++ b/e-util/e-marshal.list
@@@ -66,4 -66,3 +66,5 @@@ NONE:STRING,STRING,STRIN
NONE:STRING,STRING,UINT
OBJECT:OBJECT,DOUBLE,DOUBLE,BOOLEAN
POINTER:NONE
+STRING:NONE
++
diff --cc e-util/e-module.c
index 51e1e18,0000000..3919841
mode 100644,000000..100644
--- a/e-util/e-module.c
+++ b/e-util/e-module.c
@@@ -1,318 -1,0 +1,318 @@@
+/*
+ * e-module.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-module.h"
+
+#include <glib/gi18n.h>
+
+/* This is the symbol we call when loading a module. */
+#define LOAD_SYMBOL "e_module_load"
+
+/* This is the symbol we call when unloading a module. */
+#define UNLOAD_SYMBOL "e_module_unload"
+
+#define E_MODULE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MODULE, EModulePrivate))
+
+struct _EModulePrivate {
+ GModule *module;
+ gchar *filename;
+
+ void (*load) (GTypeModule *type_module);
+ void (*unload) (GTypeModule *type_module);
+};
+
+enum {
+ PROP_0,
+ PROP_FILENAME
+};
+
+static gpointer parent_class;
+
+static void
+module_set_filename (EModule *module,
+ const gchar *filename)
+{
+ g_return_if_fail (module->priv->filename == NULL);
+
+ module->priv->filename = g_strdup (filename);
+}
+
+static void
+module_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FILENAME:
+ module_set_filename (
+ E_MODULE (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+module_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FILENAME:
+ g_value_set_string (
+ value, e_module_get_filename (
+ E_MODULE (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+module_finalize (GObject *object)
+{
+ EModulePrivate *priv;
+
+ priv = E_MODULE_GET_PRIVATE (object);
+
+ g_free (priv->filename);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+module_load (GTypeModule *type_module)
+{
+ EModulePrivate *priv;
+ gpointer symbol;
+
+ priv = E_MODULE_GET_PRIVATE (type_module);
+
+ g_return_val_if_fail (priv->filename != NULL, FALSE);
+ priv->module = g_module_open (priv->filename, 0);
+
+ if (priv->module == NULL)
+ goto fail;
+
+ if (!g_module_symbol (priv->module, LOAD_SYMBOL, &symbol))
+ goto fail;
+
+ priv->load = symbol;
+
+ if (!g_module_symbol (priv->module, UNLOAD_SYMBOL, &symbol))
+ goto fail;
+
+ priv->unload = symbol;
+
+ priv->load (type_module);
+
+ return TRUE;
+
+fail:
+ g_warning ("%s", g_module_error ());
+
+ if (priv->module != NULL)
+ g_module_close (priv->module);
+
+ return FALSE;
+}
+
+static void
+module_unload (GTypeModule *type_module)
+{
+ EModulePrivate *priv;
+
+ priv = E_MODULE_GET_PRIVATE (type_module);
+
+ priv->unload (type_module);
+
+ g_module_close (priv->module);
+ priv->module = NULL;
+
+ priv->load = NULL;
+ priv->unload = NULL;
+}
+
+static void
+module_class_init (EModuleClass *class)
+{
+ GObjectClass *object_class;
+ GTypeModuleClass *type_module_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EModulePrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = module_set_property;
+ object_class->get_property = module_get_property;
+ object_class->finalize = module_finalize;
+
+ type_module_class = G_TYPE_MODULE_CLASS (class);
+ type_module_class->load = module_load;
+ type_module_class->unload = module_unload;
+
+ /**
+ * EModule:filename
+ *
+ * The filename of the module.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_FILENAME,
+ g_param_spec_string (
+ "filename",
+ _("Filename"),
+ _("The filename of the module"),
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+module_init (EModule *module)
+{
+ module->priv = E_MODULE_GET_PRIVATE (module);
+}
+
+GType
+e_module_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (EModuleClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) module_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EModule),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) module_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_TYPE_MODULE, "EModule", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * e_module_new:
+ * @filename: filename of the shared library module
+ *
+ * Creates a new #EModule that will load the specific shared library
+ * when in use.
+ *
+ * Returns: a new #EModule for @filename
+ **/
+EModule *
+e_module_new (const gchar *filename)
+{
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ return g_object_new (E_TYPE_MODULE, "filename", filename, NULL);
+}
+
+/**
+ * e_module_get_filename:
+ * @module: an #EModule
+ *
+ * Returns the filename of the shared library for @module. The
+ * string is owned by @module and should not be modified or freed.
+ *
+ * Returns: the filename for @module
+ **/
+const gchar *
+e_module_get_filename (EModule *module)
+{
+ g_return_val_if_fail (E_IS_MODULE (module), NULL);
+
+ return module->priv->filename;
+}
+
+/**
+ * e_module_load_all_in_directory:
+ * @dirname: pathname for a directory containing modules to load
+ *
+ * Loads all the modules in the specified directory into memory. If
+ * you want to unload them (enabling on-demand loading) you must call
+ * g_type_module_unuse() on all the modules. Free the returned list
+ * with g_list_free().
+ *
+ * Returns: a list of #EModules loaded from @dirname
+ **/
+GList *
+e_module_load_all_in_directory (const gchar *dirname)
+{
+ GDir *dir;
+ const gchar *basename;
+ GList *loaded_modules = NULL;
+ GError *error = NULL;
+
+ g_return_val_if_fail (dirname != NULL, NULL);
+
+ if (!g_module_supported ())
+ return NULL;
+
+ dir = g_dir_open (dirname, 0, &error);
+ if (dir == NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ while ((basename = g_dir_read_name (dir)) != NULL) {
+ EModule *module;
+ gchar *filename;
+
+ if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX))
+ continue;
+
+ filename = g_build_filename (dirname, basename, NULL);
+
+ module = e_module_new (filename);
+
+ if (!g_type_module_use (G_TYPE_MODULE (module))) {
+ g_printerr ("Failed to load module: %s\n", filename);
+ g_object_unref (module);
+ g_free (filename);
+ continue;
+ }
+
+ g_free (filename);
+
+ loaded_modules = g_list_prepend (loaded_modules, module);
+ }
+
+ g_dir_close (dir);
+
+ return loaded_modules;
+}
diff --cc e-util/e-module.h
index 022769d,0000000..a812056
mode 100644,000000..100644
--- a/e-util/e-module.h
+++ b/e-util/e-module.h
@@@ -1,81 -1,0 +1,81 @@@
+/*
+ * e-module.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/**
+ * SECTION: e-module
+ * @short_description: generic module loader
+ * @include: e-util/e-module.h
+ **/
+
+#ifndef E_MODULE_H
+#define E_MODULE_H
+
+#include <gmodule.h>
+#include <glib-object.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MODULE \
+ (e_module_get_type ())
+#define E_MODULE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MODULE, EModule))
+#define E_MODULE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MODULE, EModuleClass))
+#define E_IS_MODULE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MODULE))
+#define E_IS_MODULE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MODULE))
+#define E_MODULE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MODULE, EModuleClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EModule EModule;
+typedef struct _EModuleClass EModuleClass;
+typedef struct _EModulePrivate EModulePrivate;
+
+/**
+ * EModule:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _EModule {
+ GTypeModule parent;
+ EModulePrivate *priv;
+};
+
+struct _EModuleClass {
+ GTypeModuleClass parent_class;
+};
+
+GType e_module_get_type (void);
+EModule * e_module_new (const gchar *filename);
+const gchar * e_module_get_filename (EModule *module);
+GList * e_module_load_all_in_directory (const gchar *dirname);
+
+G_END_DECLS
+
+#endif /* E_MODULE_H */
diff --cc e-util/e-signature-utils.c
index 0114ce6,0000000..1321fc5
mode 100644,000000..100644
--- a/e-util/e-signature-utils.c
+++ b/e-util/e-signature-utils.c
@@@ -1,347 -1,0 +1,347 @@@
+/*
+ * e-signature-utils.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#include "e-signature-utils.h"
+
+#include <errno.h>
+#include <glib/gstdio.h>
+#include <gconf/gconf-client.h>
+#include <camel/camel-stream.h>
+#include <camel/camel-stream-fs.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-mime-filter-charset.h>
+#include <camel/camel-mime-filter-tohtml.h>
+
+#ifndef G_OS_WIN32
+#include <sys/wait.h>
+#endif
+
+#include "e-util/e-util.h"
+
+static ESignatureList *global_signature_list;
+
+ESignatureList *
+e_get_signature_list (void)
+{
+ if (G_UNLIKELY (global_signature_list == NULL)) {
+ GConfClient *client;
+
+ client = gconf_client_get_default ();
+ global_signature_list = e_signature_list_new (client);
+ g_object_unref (client);
+ }
+
+ g_return_val_if_fail (global_signature_list != NULL, NULL);
+
+ return global_signature_list;
+}
+
+ESignature *
+e_get_signature_by_name (const gchar *name)
+{
+ ESignatureList *signature_list;
+ const ESignature *signature;
+ e_signature_find_t find;
+
+ g_return_val_if_fail (name != NULL, NULL);
+
+ find = E_SIGNATURE_FIND_NAME;
+ signature_list = e_get_signature_list ();
+ signature = e_signature_list_find (signature_list, find, name);
+
+ /* XXX ESignatureList misuses const. */
+ return (ESignature *) signature;
+}
+
+ESignature *
+e_get_signature_by_uid (const gchar *uid)
+{
+ ESignatureList *signature_list;
+ const ESignature *signature;
+ e_signature_find_t find;
+
+ g_return_val_if_fail (uid != NULL, NULL);
+
+ find = E_SIGNATURE_FIND_UID;
+ signature_list = e_get_signature_list ();
+ signature = e_signature_list_find (signature_list, find, uid);
+
+ /* XXX ESignatureList misuses const. */
+ return (ESignature *) signature;
+}
+
+gchar *
+e_create_signature_file (GError **error)
+{
+ const gchar *data_dir;
+ gchar basename[32];
+ gchar *filename;
+ gchar *pathname;
+ gint32 ii;
+
+ data_dir = e_get_user_data_dir ();
+ pathname = g_build_filename (data_dir, "signatures", NULL);
+ filename = NULL;
+
+ if (g_mkdir_with_parents (pathname, 0700) < 0) {
+ g_set_error (
+ error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "%s: %s", pathname, g_strerror (errno));
+ g_free (pathname);
+ return NULL;
+ }
+
+ for (ii = 0; ii < G_MAXINT32; ii++) {
+
+ g_snprintf (
+ basename, sizeof (basename),
+ "signature-%" G_GINT32_FORMAT, ii);
+
+ g_free (filename);
+ filename = g_build_filename (pathname, basename, NULL);
+
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ gint fd;
+
+ fd = g_creat (filename, 0600);
+ if (fd >= 0) {
+ close (fd);
+ break;
+ }
+
+ /* If we failed once we're probably going
+ * to continue failing, so just give up. */
+ g_set_error (
+ error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "%s: %s", filename, g_strerror (errno));
+ g_free (filename);
+ filename = NULL;
+ break;
+ }
+ }
+
+ /* If there are actually G_MAXINT32 signature files, the
+ * most recent signature file we be overwritten. Sorry. */
+
+ return filename;
+}
+
+gchar *
+e_read_signature_file (ESignature *signature,
+ gboolean convert_to_html,
+ GError **error)
+{
+ CamelStream *input_stream;
+ CamelStream *output_stream;
+ GByteArray *buffer;
+ gchar *content;
+ gsize length;
+ gint fd;
+
+ g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL);
+
+ fd = g_open (signature->filename, O_RDONLY, 0);
+ if (fd < 0) {
+ g_set_error (
+ error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "%s: %s", signature->filename,
+ g_strerror (errno));
+ return NULL;
+ }
+
+ input_stream = camel_stream_fs_new_with_fd (fd);
+
+ if (!signature->html && convert_to_html) {
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *filter;
+ gint32 flags;
+
+ filtered_stream =
+ camel_stream_filter_new_with_stream (input_stream);
+ camel_object_unref (input_stream);
+
+ flags =
+ CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES |
+ CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
+ filter = camel_mime_filter_tohtml_new (flags, 0);
+ camel_stream_filter_add (filtered_stream, filter);
+ camel_object_unref (filter);
+
+ input_stream = (CamelStream *) filtered_stream;
+ }
+
+ buffer = g_byte_array_new ();
+ output_stream = camel_stream_mem_new ();
+ camel_stream_mem_set_byte_array (
+ CAMEL_STREAM_MEM (output_stream), buffer);
+ camel_stream_write_to_stream (input_stream, output_stream);
+ camel_object_unref (output_stream);
+ camel_object_unref (input_stream);
+
+ /* Make sure the buffer is nul-terminated. */
+ length = (gsize) buffer->len;
+ g_byte_array_append (buffer, (guint8 *) "", 1);
+ content = (gchar *) g_byte_array_free (buffer, FALSE);
+
+ /* Signatures are saved as UTF-8, but we still need to check that
+ * the signature is valid UTF-8 because the user may be opening
+ * a signature file that is in his/her locale character set. If
+ * it's not in UTF-8 then try converting from the current locale. */
+ if (!g_utf8_validate (content, length, NULL)) {
+ gchar *utf8;
+
+ utf8 = g_locale_to_utf8 (content, length, NULL, NULL, error);
+ g_free (content);
+ content = utf8;
+ }
+
+ return content;
+}
+
+gchar *
+e_run_signature_script (const gchar *filename)
+{
+ /* FIXME Make this cross-platform, prefer GLib functions over
+ * POSIX, and report errors via GError instead of dumping
+ * messages to the terminal where users won't see them. */
+
+#ifndef G_OS_WIN32
+ gint in_fds[2];
+ pid_t pid;
+
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ if (pipe (in_fds) == -1) {
+ g_warning (
+ "Failed to create pipe to '%s': %s",
+ filename, g_strerror (errno));
+ return NULL;
+ }
+
+ pid = fork ();
+
+ /* Child Process */
+ if (pid == 0) {
+ gint maxfd, ii;
+
+ close (in_fds[0]);
+ if (dup2 (in_fds[1], STDOUT_FILENO) < 0)
+ _exit (255);
+ close (in_fds[1]);
+
+ setsid ();
+
+ maxfd = sysconf (_SC_OPEN_MAX);
+ for (ii = 3; ii < maxfd; ii++) {
+ if (ii == STDIN_FILENO)
+ continue;
+ if (ii == STDOUT_FILENO)
+ continue;
+ if (ii == STDERR_FILENO)
+ continue;
+ fcntl (ii, F_SETFD, FD_CLOEXEC);
+ }
+
+ execlp ("/bin/sh", "/bin/sh", "-c", filename, NULL);
+
+ g_warning (
+ "Could not execute '%s': %s",
+ filename, g_strerror (errno));
+
+ _exit (255);
+
+ /* Parent Process */
+ } else if (pid > 0) {
+ CamelStream *output_stream;
+ CamelStream *input_stream;
+ GByteArray *buffer;
+ gchar *content;
+ gsize length;
+ gint result;
+ gint status;
+
+ close (in_fds[1]);
+
+ buffer = g_byte_array_new ();
+ output_stream = camel_stream_mem_new ();
+ camel_stream_mem_set_byte_array (
+ CAMEL_STREAM_MEM (output_stream), buffer);
+
+ input_stream = camel_stream_fs_new_with_fd (in_fds[0]);
+ camel_stream_write_to_stream (input_stream, output_stream);
+ camel_object_unref (input_stream);
+
+ camel_object_unref (output_stream);
+
+ /* Make sure the buffer is nul-terminated. */
+ length = (gsize) buffer->len;
+ g_byte_array_append (buffer, (guchar *) "", 1);
+ content = (gchar *) g_byte_array_free (buffer, FALSE);
+
+ /* Signature scripts are supposed to generate UTF-8 content,
+ * but because users are known to never read the manual, we
+ * try to do our best if the content isn't valid UTF-8 by
+ * assuming that the content is in the user's locale
+ * character set. */
+ if (!g_utf8_validate (content, length, NULL)) {
+ gchar *utf8;
+
+ /* XXX Should pass a GError here. */
+ utf8 = g_locale_to_utf8 (
+ content, length, NULL, NULL, NULL);
+ g_free (content);
+ content = utf8;
+ }
+
+ /* Wait for the script process to terminate. */
+ result = waitpid (pid, &status, 0);
+
+ if (result == -1 && errno == EINTR) {
+ /* Child process is hanging... */
+ kill (pid, SIGTERM);
+ sleep (1);
+ result = waitpid (pid, &status, WNOHANG);
+ if (result == 0) {
+ /* ...still hanging, set phasers to KILL. */
+ kill (pid, SIGKILL);
+ sleep (1);
+ result = waitpid (pid, &status, WNOHANG);
+ }
+ }
+
+ return content;
+
+ /* Forking Failed */
+ } else {
+ g_warning (
+ "Failed to create child process '%s': %s",
+ filename, g_strerror (errno));
+ close (in_fds[0]);
+ close (in_fds[1]);
+ }
+#endif
+
+ return NULL;
+}
diff --cc e-util/e-signature-utils.h
index 41472f4,0000000..56f8564
mode 100644,000000..100644
--- a/e-util/e-signature-utils.h
+++ b/e-util/e-signature-utils.h
@@@ -1,40 -1,0 +1,40 @@@
+/*
+ * e-signature-utils.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+
+#ifndef E_SIGNATURE_UTILS_H
+#define E_SIGNATURE_UTILS_H
+
+#include <gtk/gtk.h>
+#include <e-util/e-signature.h>
+#include <e-util/e-signature-list.h>
+
+G_BEGIN_DECLS
+
+ESignatureList *e_get_signature_list (void);
+ESignature * e_get_signature_by_name (const gchar *name);
+ESignature * e_get_signature_by_uid (const gchar *uid);
+gchar * e_create_signature_file (GError **error);
+gchar * e_read_signature_file (ESignature *signature,
+ gboolean convert_to_html,
+ GError **error);
+gchar * e_run_signature_script (const gchar *filename);
+
+G_END_DECLS
+
+#endif /* E_SIGNATURE_UTILS_H */
diff --cc em-format/em-format-quote.c
index 5503cca,0000000..7918b94
mode 100644,000000..100644
--- a/em-format/em-format-quote.c
+++ b/em-format/em-format-quote.c
@@@ -1,586 -1,0 +1,586 @@@
+/*
+ *
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <camel/camel-iconv.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-mime-filter-tohtml.h>
+#include <camel/camel-mime-filter-enriched.h>
+#include <camel/camel-string-utils.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-url.h>
+
+#include <glib/gi18n.h>
+#include <gconf/gconf-client.h>
+
+#include "em-stripsig-filter.h"
+#include "em-format-quote.h"
+
+struct _EMFormatQuotePrivate {
+ int dummy;
+};
+
+static void emfq_format_clone(EMFormat *, CamelFolder *, const char *, CamelMimeMessage *, EMFormat *);
+static void emfq_format_error(EMFormat *emf, CamelStream *stream, const char *txt);
+static void emfq_format_message(EMFormat *, CamelStream *, CamelMimePart *, const EMFormatHandler *);
+static void emfq_format_source(EMFormat *, CamelStream *, CamelMimePart *);
+static void emfq_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, const char *, const EMFormatHandler *);
+
+static void emfq_builtin_init(EMFormatQuoteClass *efhc);
+
+static gpointer parent_class;
+
+static void
+emfq_init(GObject *o)
+{
+ EMFormatQuote *emfq =(EMFormatQuote *) o;
+
+ /* we want to convert url's etc */
+ emfq->text_html_flags = CAMEL_MIME_FILTER_TOHTML_PRE | CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS
+ | CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES;
+}
+
+static void
+emfq_finalize (GObject *object)
+{
+ EMFormatQuote *emfq =(EMFormatQuote *) object;
+
+ if (emfq->stream)
+ camel_object_unref(emfq->stream);
+ g_free(emfq->credits);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+emfq_base_init(EMFormatQuoteClass *emfqclass)
+{
+ emfq_builtin_init(emfqclass);
+}
+
+static void
+emfq_class_init (EMFormatQuoteClass *class)
+{
+ GObjectClass *object_class;
+ EMFormatClass *format_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMFormatQuotePrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = emfq_finalize;
+
+ format_class = EM_FORMAT_CLASS (class);
+ format_class->format_clone = emfq_format_clone;
+ format_class->format_error = emfq_format_error;
+ format_class->format_source = emfq_format_source;
+ format_class->format_attachment = emfq_format_attachment;
+}
+
+GType
+em_format_quote_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMFormatQuoteClass),
+ (GBaseInitFunc) emfq_base_init,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) emfq_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMFormatQuote),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) emfq_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ EM_TYPE_FORMAT, "EMFormatQuote", &type_info, 0);
+ }
+
+ return type;
+}
+
+EMFormatQuote *
+em_format_quote_new (const gchar *credits,
+ CamelStream *stream,
+ guint32 flags)
+{
+ EMFormatQuote *emfq;
+
+ emfq = g_object_new (EM_TYPE_FORMAT_QUOTE, NULL);
+
+ emfq->credits = g_strdup (credits);
+ emfq->stream = stream;
+ camel_object_ref (stream);
+ emfq->flags = flags;
+
+ return emfq;
+}
+
+static void
+emfq_format_empty_line(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ camel_stream_printf(stream, "<br>\n");
+}
+
+static void
+emfq_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *src)
+{
+ EMFormatQuote *emfq = (EMFormatQuote *) emf;
+ const EMFormatHandler *handle;
+ GConfClient *gconf;
+
+ /* Chain up to parent's format_clone() method. */
+ EM_FORMAT_CLASS (parent_class)->format_clone (emf, folder, uid, msg, src);
+
+ gconf = gconf_client_get_default ();
+ camel_stream_reset(emfq->stream);
+ if (gconf_client_get_bool(gconf, "/apps/evolution/mail/composer/top_signature", NULL))
+ emfq_format_empty_line(emf, emfq->stream, (CamelMimePart *)msg, NULL);
+ g_object_unref (gconf);
+ handle = em_format_find_handler(emf, "x-evolution/message/prefix");
+ if (handle)
+ handle->handler(emf, emfq->stream, (CamelMimePart *)msg, handle);
+ handle = em_format_find_handler(emf, "x-evolution/message/rfc822");
+ if (handle)
+ handle->handler(emf, emfq->stream, (CamelMimePart *)msg, handle);
+
+ camel_stream_flush(emfq->stream);
+
+ g_signal_emit_by_name(emf, "complete");
+}
+
+static void
+emfq_format_error(EMFormat *emf, CamelStream *stream, const char *txt)
+{
+ /* FIXME: should we even bother writing error text for quoting? probably not... */
+}
+
+static void
+emfq_format_text_header (EMFormatQuote *emfq, CamelStream *stream, const char *label, const char *value, guint32 flags, int is_html)
+{
+ const char *fmt, *html;
+ char *mhtml = NULL;
+
+ if (value == NULL)
+ return;
+
+ while (*value == ' ')
+ value++;
+
+ if (!is_html)
+ html = mhtml = camel_text_to_html (value, 0, 0);
+ else
+ html = value;
+
+ if (flags & EM_FORMAT_HEADER_BOLD)
+ fmt = "<b>%s</b>: %s<br>";
+ else
+ fmt = "%s: %s<br>";
+
+ camel_stream_printf (stream, fmt, label, html);
+ g_free (mhtml);
+}
+
- static char *addrspec_hdrs[] = {
++static const gchar *addrspec_hdrs[] = {
+ "Sender", "From", "Reply-To", "To", "Cc", "Bcc",
+ "Resent-Sender", "Resent-from", "Resent-Reply-To",
+ "Resent-To", "Resent-cc", "Resent-Bcc", NULL
+};
+
+#if 0
+/* FIXME: include Sender and Resent-* headers too? */
+/* For Translators only: The following strings are used in the header table in the preview pane */
+static char *i18n_hdrs[] = {
+ N_("From"), N_("Reply-To"), N_("To"), N_("Cc"), N_("Bcc")
+};
+#endif
+
+static void
+emfq_format_address (GString *out, struct _camel_header_address *a)
+{
+ guint32 flags = CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES;
+ char *name, *mailto, *addr;
+
+ while (a) {
+ if (a->name)
+ name = camel_text_to_html (a->name, flags, 0);
+ else
+ name = NULL;
+
+ switch (a->type) {
+ case CAMEL_HEADER_ADDRESS_NAME:
+ if (name && *name) {
+ char *real, *mailaddr;
+
+ g_string_append_printf (out, "%s <", name);
+ /* rfc2368 for mailto syntax and url encoding extras */
+ if ((real = camel_header_encode_phrase ((unsigned char *)a->name))) {
+ mailaddr = g_strdup_printf ("%s <%s>", real, a->v.addr);
+ g_free (real);
+ mailto = camel_url_encode (mailaddr, "?=&()");
+ g_free (mailaddr);
+ } else {
+ mailto = camel_url_encode (a->v.addr, "?=&()");
+ }
+ } else {
+ mailto = camel_url_encode (a->v.addr, "?=&()");
+ }
+ addr = camel_text_to_html (a->v.addr, flags, 0);
+ g_string_append_printf (out, "<a href=\"mailto:%s\">%s</a>", mailto, addr);
+ g_free (mailto);
+ g_free (addr);
+
+ if (name && *name)
+ g_string_append (out, ">");
+ break;
+ case CAMEL_HEADER_ADDRESS_GROUP:
+ g_string_append_printf (out, "%s: ", name);
+ emfq_format_address (out, a->v.members);
+ g_string_append_printf (out, ";");
+ break;
+ default:
+ g_warning ("Invalid address type");
+ break;
+ }
+
+ g_free (name);
+
+ a = a->next;
+ if (a)
+ g_string_append (out, ", ");
+ }
+}
+
+static void
+canon_header_name (char *name)
+{
+ char *inptr = name;
-
++
+ /* canonicalise the header name... first letter is
+ * capitalised and any letter following a '-' also gets
+ * capitalised */
-
++
+ if (*inptr >= 'a' && *inptr <= 'z')
+ *inptr -= 0x20;
-
++
+ inptr++;
-
++
+ while (*inptr) {
+ if (inptr[-1] == '-' && *inptr >= 'a' && *inptr <= 'z')
+ *inptr -= 0x20;
+ else if (*inptr >= 'A' && *inptr <= 'Z')
+ *inptr += 0x20;
-
++
+ inptr++;
+ }
+}
+
+static void
+emfq_format_header (EMFormat *emf, CamelStream *stream, CamelMedium *part, const char *namein, guint32 flags, const char *charset)
+{
+ CamelMimeMessage *msg = (CamelMimeMessage *) part;
+ EMFormatQuote *emfq = (EMFormatQuote *) emf;
+ char *name, *buf, *value = NULL;
+ const char *txt, *label;
+ gboolean addrspec = FALSE;
+ int is_html = FALSE;
+ int i;
+
+ name = g_alloca (strlen (namein) + 1);
+ strcpy (name, namein);
+ canon_header_name (name);
+
+ for (i = 0; addrspec_hdrs[i]; i++) {
+ if (!strcmp (name, addrspec_hdrs[i])) {
+ addrspec = TRUE;
+ break;
+ }
+ }
-
++
+ label = _(name);
-
++
+ if (addrspec) {
+ struct _camel_header_address *addrs;
+ GString *html;
+
+ if (!(txt = camel_medium_get_header (part, name)))
+ return;
-
++
+ buf = camel_header_unfold (txt);
+ if (!(addrs = camel_header_address_decode (txt, emf->charset ? emf->charset : emf->default_charset))) {
+ g_free (buf);
+ return;
+ }
-
++
+ g_free (buf);
-
++
+ html = g_string_new ("");
+ emfq_format_address (html, addrs);
+ camel_header_address_unref (addrs);
+ txt = value = html->str;
+ g_string_free (html, FALSE);
+ flags |= EM_FORMAT_HEADER_BOLD;
+ is_html = TRUE;
+ } else if (!strcmp (name, "Subject")) {
+ txt = camel_mime_message_get_subject (msg);
+ label = _("Subject");
+ flags |= EM_FORMAT_HEADER_BOLD;
+ } else if (!strcmp (name, "X-Evolution-Mailer")) { /* pseudo-header */
+ if (!(txt = camel_medium_get_header (part, "x-mailer")))
+ if (!(txt = camel_medium_get_header (part, "user-agent")))
+ if (!(txt = camel_medium_get_header (part, "x-newsreader")))
+ if (!(txt = camel_medium_get_header (part, "x-mimeole")))
+ return;
-
++
+ txt = value = camel_header_format_ctext (txt, charset);
-
++
+ label = _("Mailer");
+ flags |= EM_FORMAT_HEADER_BOLD;
+ } else if (!strcmp (name, "Date") || !strcmp (name, "Resent-Date")) {
+ if (!(txt = camel_medium_get_header (part, name)))
+ return;
-
++
+ flags |= EM_FORMAT_HEADER_BOLD;
+ } else {
+ txt = camel_medium_get_header (part, name);
+ buf = camel_header_unfold (txt);
+ txt = value = camel_header_decode_string (txt, charset);
+ g_free (buf);
+ }
+
+ emfq_format_text_header (emfq, stream, label, txt, flags, is_html);
+
+ g_free (value);
+}
+
+static void
+emfq_format_headers (EMFormatQuote *emfq, CamelStream *stream, CamelMedium *part)
+{
+ EMFormat *emf = (EMFormat *) emfq;
+ CamelContentType *ct;
+ const char *charset;
+ EMFormatHeader *h;
+
+ if (!part)
+ return;
+
+ ct = camel_mime_part_get_content_type ((CamelMimePart *) part);
+ charset = camel_content_type_param (ct, "charset");
+ charset = camel_iconv_charset_name (charset);
+
+ /* dump selected headers */
+ h = (EMFormatHeader *) emf->header_list.head;
+ while (h->next) {
+ emfq_format_header (emf, stream, part, h->name, h->flags, charset);
+ h = h->next;
+ }
+
+ camel_stream_printf(stream, "<br>\n");
+}
+
+static void
+emfq_format_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ EMFormatQuote *emfq = (EMFormatQuote *) emf;
+
+ if (emfq->credits)
+ camel_stream_printf(stream, "%s<br>\n", emfq->credits);
+}
+
+static void
+emfq_format_message(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ EMFormatQuote *emfq = (EMFormatQuote *) emf;
+
+ if (emfq->flags & EM_FORMAT_QUOTE_CITE)
+ camel_stream_printf(stream, "<!--+GtkHTML:<DATA class=\"ClueFlow\" key=\"orig\" value=\"1\">-->\n"
+ "<blockquote type=cite>\n");
+
+ if (((CamelMimePart *)emf->message) != part) {
+ camel_stream_printf(stream, "%s</br>\n", _("-------- Forwarded Message --------"));
+ emfq_format_headers (emfq, stream, (CamelMedium *)part);
+ } else if (emfq->flags & EM_FORMAT_QUOTE_HEADERS)
+ emfq_format_headers (emfq, stream, (CamelMedium *)part);
+
+ em_format_part (emf, stream, part);
+
+ if (emfq->flags & EM_FORMAT_QUOTE_CITE)
+ camel_stream_write_string(stream, "</blockquote><!--+GtkHTML:<DATA class=\"ClueFlow\" clear=\"orig\">-->");
+}
+
+static void
+emfq_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *html_filter;
+
+ filtered_stream = camel_stream_filter_new_with_stream ((CamelStream *) stream);
+ html_filter = camel_mime_filter_tohtml_new (CAMEL_MIME_FILTER_TOHTML_CONVERT_NL
+ | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES
+ | CAMEL_MIME_FILTER_TOHTML_ESCAPE_8BIT, 0);
+ camel_stream_filter_add(filtered_stream, html_filter);
+ camel_object_unref(html_filter);
+
+ em_format_format_text(emf, (CamelStream *)filtered_stream, (CamelDataWrapper *)part);
+ camel_object_unref(filtered_stream);
+}
+
+static void
+emfq_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type, const EMFormatHandler *handle)
+{
+ if (handle && em_format_is_inline(emf, emf->part_id->str, part, handle)) {
+ char *text, *html;
+
+ camel_stream_write_string(stream,
+ "<table border=1 cellspacing=0 cellpadding=0><tr><td><font size=-1>\n");
+
+ /* output some info about it */
+ text = em_format_describe_part(part, mime_type);
+ html = camel_text_to_html(text, ((EMFormatQuote *)emf)->text_html_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0);
+ camel_stream_write_string(stream, html);
+ g_free(html);
+ g_free(text);
+
+ camel_stream_write_string(stream, "</font></td></tr></table>");
+
+ handle->handler(emf, stream, part, handle);
+ }
+}
+
+#include <camel/camel-medium.h>
+#include <camel/camel-mime-part.h>
+#include <camel/camel-multipart.h>
+#include <camel/camel-url.h>
+
+static void
+emfq_text_plain(EMFormatQuote *emfq, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *html_filter;
+ CamelMimeFilter *sig_strip;
+ CamelContentType *type;
+ const char *format;
+ guint32 rgb = 0x737373, flags;
+
+ if (!part)
+ return;
+
+ flags = emfq->text_html_flags;
+
+ /* Check for RFC 2646 flowed text. */
+ type = camel_mime_part_get_content_type(part);
+ if (camel_content_type_is(type, "text", "plain")
+ && (format = camel_content_type_param(type, "format"))
+ && !g_ascii_strcasecmp(format, "flowed"))
+ flags |= CAMEL_MIME_FILTER_TOHTML_FORMAT_FLOWED;
+
+ filtered_stream = camel_stream_filter_new_with_stream(stream);
+
+ if (emfq->flags != 0) {
+ sig_strip = em_stripsig_filter_new ();
+ camel_stream_filter_add (filtered_stream, sig_strip);
+ camel_object_unref (sig_strip);
+ }
+
+ html_filter = camel_mime_filter_tohtml_new(flags, rgb);
+ camel_stream_filter_add(filtered_stream, html_filter);
+ camel_object_unref(html_filter);
+
+ em_format_format_text((EMFormat *)emfq, (CamelStream *)filtered_stream, (CamelDataWrapper *)part);
+ camel_stream_flush((CamelStream *)filtered_stream);
+ camel_object_unref(filtered_stream);
+}
+
+static void
+emfq_text_enriched(EMFormatQuote *emfq, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilter *enriched;
+ CamelDataWrapper *dw;
+ guint32 flags = 0;
+
+ dw = camel_medium_get_content_object((CamelMedium *)part);
+
+ if (!strcmp(info->mime_type, "text/richtext")) {
+ flags = CAMEL_MIME_FILTER_ENRICHED_IS_RICHTEXT;
+ camel_stream_write_string(stream, "\n<!-- text/richtext -->\n");
+ } else {
+ camel_stream_write_string(stream, "\n<!-- text/enriched -->\n");
+ }
+
+ enriched = camel_mime_filter_enriched_new(flags);
+ filtered_stream = camel_stream_filter_new_with_stream (stream);
+ camel_stream_filter_add(filtered_stream, enriched);
+ camel_object_unref(enriched);
+
+ camel_stream_write_string(stream, "<br><hr><br>");
+ em_format_format_text((EMFormat *)emfq, (CamelStream *)filtered_stream, (CamelDataWrapper *)part);
+ camel_object_unref(filtered_stream);
+}
+
+static void
+emfq_text_html(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
+{
+ camel_stream_write_string(stream, "\n<!-- text/html -->\n");
+ em_format_format_text(emf, stream, (CamelDataWrapper *)part);
+}
+
+static void
+emfq_ignore(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info)
+{
+ /* NOOP */
+}
+
+static EMFormatHandler type_builtin_table[] = {
- { "text/plain",(EMFormatFunc)emfq_text_plain },
- { "text/enriched",(EMFormatFunc)emfq_text_enriched },
- { "text/richtext",(EMFormatFunc)emfq_text_enriched },
- { "text/html",(EMFormatFunc)emfq_text_html },
- /* { "multipart/related",(EMFormatFunc)emfq_multipart_related },*/
- { "message/external-body", (EMFormatFunc)emfq_ignore },
- { "multipart/appledouble", (EMFormatFunc)emfq_ignore },
++ { (gchar *) "text/plain", (EMFormatFunc)emfq_text_plain },
++ { (gchar *) "text/enriched", (EMFormatFunc)emfq_text_enriched },
++ { (gchar *) "text/richtext", (EMFormatFunc)emfq_text_enriched },
++ { (gchar *) "text/html", (EMFormatFunc)emfq_text_html },
++/* { (gchar *) "multipart/related",(EMFormatFunc)emfq_multipart_related },*/
++ { (gchar *) "message/external-body", (EMFormatFunc)emfq_ignore },
++ { (gchar *) "multipart/appledouble", (EMFormatFunc)emfq_ignore },
+
+ /* internal evolution types */
- { "x-evolution/evolution-rss-feed", (EMFormatFunc)emfq_text_html },
- { "x-evolution/message/rfc822", (EMFormatFunc)emfq_format_message },
- { "x-evolution/message/prefix", (EMFormatFunc)emfq_format_message_prefix },
++ { (gchar *) "x-evolution/evolution-rss-feed", (EMFormatFunc)emfq_text_html },
++ { (gchar *) "x-evolution/message/rfc822", (EMFormatFunc)emfq_format_message },
++ { (gchar *) "x-evolution/message/prefix", (EMFormatFunc)emfq_format_message_prefix },
+};
+
+static void
+emfq_builtin_init(EMFormatQuoteClass *efhc)
+{
+ int i;
+
+ for (i=0;i<sizeof(type_builtin_table)/sizeof(type_builtin_table[0]);i++)
+ em_format_class_add_handler((EMFormatClass *)efhc, &type_builtin_table[i]);
+}
diff --cc em-format/em-format-quote.h
index d34548a,0000000..8aca4b8
mode 100644,000000..100644
--- a/em-format/em-format-quote.h
+++ b/em-format/em-format-quote.h
@@@ -1,81 -1,0 +1,81 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef EM_FORMAT_QUOTE_H
+#define EM_FORMAT_QUOTE_H
+
+#include <camel/camel-stream.h>
+#include "em-format.h"
+
+/* Standard GObject macros */
+#define EM_TYPE_FORMAT_QUOTE \
+ (em_format_quote_get_type ())
+#define EM_FORMAT_QUOTE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), EM_TYPE_FORMAT_QUOTE, EMFormatQuote))
+#define EM_FORMAT_QUOTE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), EM_TYPE_FORMAT_QUOTE, EMFormatQuoteClass))
+#define EM_IS_FORMAT_QUOTE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), EM_TYPE_FORMAT_QUOTE))
+#define EM_IS_FORMAT_QUOTE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), EM_TYPE_FORMAT_QUOTE))
+#define EM_FORMAT_QUOTE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), EM_TYPE_FORMAT_QUOTE, EMFormatQuoteClass))
+
+#define EM_FORMAT_QUOTE_CITE (1<<0)
+#define EM_FORMAT_QUOTE_HEADERS (1<<1)
+
+G_BEGIN_DECLS
+
+typedef struct _EMFormatQuote EMFormatQuote;
+typedef struct _EMFormatQuoteClass EMFormatQuoteClass;
+typedef struct _EMFormatQuotePrivate EMFormatQuotePrivate;
+
+struct _EMFormatQuote {
+ EMFormat format;
+
+ EMFormatQuotePrivate *priv;
+
+ char *credits;
+ CamelStream *stream;
+ guint32 flags;
+
+ guint32 text_html_flags;
+ guint32 citation_colour;
+};
+
+struct _EMFormatQuoteClass {
+ EMFormatClass format_class;
+};
+
+GType em_format_quote_get_type (void);
+EMFormatQuote * em_format_quote_new (const gchar *credits,
+ CamelStream *stream,
+ guint32 flags);
+
+G_END_DECLS
+
+#endif /* EM_FORMAT_QUOTE_H */
diff --cc em-format/em-format.c
index 7128644,0000000..c2669e7
mode 100644,000000..100644
--- a/em-format/em-format.c
+++ b/em-format/em-format.c
@@@ -1,1945 -1,0 +1,1946 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Michael Zucchi <notzed ximian com>
+ * Jeffrey Stedfast <fejj ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-msgport.h>
+#include <camel/camel-stream.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-multipart.h>
+#include <camel/camel-multipart-encrypted.h>
+#include <camel/camel-multipart-signed.h>
+#include <camel/camel-medium.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-gpg-context.h>
+#include <camel/camel-smime-context.h>
+#include <camel/camel-string-utils.h>
+#include <camel/camel-stream-filter.h>
+#include <camel/camel-stream-null.h>
+#include <camel/camel-stream-mem.h>
+#include <camel/camel-mime-filter-charset.h>
+#include <camel/camel-mime-filter-windows.h>
+#include <camel/camel-mime-filter-pgp.h>
+
+#include "em-format.h"
+#include "e-util/e-util.h"
+#include "shell/e-shell.h"
+#include "shell/e-shell-settings.h"
+
+#define d(x)
+
+/* Used to cache various data/info for redraws
+ The validity stuff could be cached at a higher level but this is easier
+ This absolutely relies on the partid being _globally unique_
+ This is still kind of yucky, we should maintian a full tree of all this data,
+ along with/as part of the puri tree */
+struct _EMFormatCache {
+ CamelCipherValidity *valid; /* validity copy */
+ CamelMimePart *secured; /* encrypted subpart */
+
+ unsigned int state:2; /* inline state */
+
+ char partid[1];
+};
+
+#define INLINE_UNSET (0)
+#define INLINE_ON (1)
+#define INLINE_OFF (2)
+
+static void emf_builtin_init(EMFormatClass *);
+
+static const EMFormatHandler *emf_find_handler(EMFormat *emf, const char *mime_type);
+static void emf_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource);
+static void emf_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid);
+static gboolean emf_busy(EMFormat *emf);
+enum {
+ EMF_COMPLETE,
+ EMF_LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[EMF_LAST_SIGNAL];
+
+static void
+emf_free_cache(struct _EMFormatCache *efc)
+{
+ if (efc->valid)
+ camel_cipher_validity_free(efc->valid);
+ if (efc->secured)
+ camel_object_unref(efc->secured);
+ g_free(efc);
+}
+
+static struct _EMFormatCache *
+emf_insert_cache(EMFormat *emf, const char *partid)
+{
+ struct _EMFormatCache *new;
+
+ new = g_malloc0(sizeof(*new)+strlen(partid));
+ strcpy(new->partid, partid);
+ g_hash_table_insert(emf->inline_table, new->partid, new);
+
+ return new;
+}
+
+static void
+emf_finalize (GObject *object)
+{
+ EMFormat *emf = EM_FORMAT (object);
+
+ if (emf->session)
+ camel_object_unref (emf->session);
+
+ g_hash_table_destroy (emf->inline_table);
+
+ em_format_clear_headers(emf);
+ camel_cipher_validity_free(emf->valid);
+ g_free(emf->charset);
+ g_free (emf->default_charset);
+ g_string_free(emf->part_id, TRUE);
+
+ /* FIXME: check pending jobs */
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+emf_base_init (EMFormatClass *class)
+{
+ class->type_handlers = g_hash_table_new (g_str_hash, g_str_equal);
+ emf_builtin_init (class);
+}
+
+static void
+emf_class_init (EMFormatClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = emf_finalize;
+
+ class->find_handler = emf_find_handler;
+ class->format_clone = emf_format_clone;
+ class->format_secure = emf_format_secure;
+ class->busy = emf_busy;
+
+ signals[EMF_COMPLETE] = g_signal_new (
+ "complete",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMFormatClass, complete),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ class->type_handlers = g_hash_table_new (g_str_hash, g_str_equal);
+ emf_builtin_init (class);
+}
+
+static void
+emf_init (EMFormat *emf)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+
+ emf->inline_table = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) emf_free_cache);
+ emf->composer = FALSE;
+ emf->print = FALSE;
+ e_dlist_init(&emf->header_list);
+ em_format_default_headers(emf);
+ emf->part_id = g_string_new("");
+
+ shell = e_shell_get_default ();
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ emf->session = e_shell_settings_get_pointer (shell_settings, "mail-session");
+ g_return_if_fail (emf->session != NULL);
+
+ camel_object_ref (emf->session);
+}
+
+GType
+em_format_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMFormatClass),
+ (GBaseInitFunc) emf_base_init,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) emf_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMFormat),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) emf_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EMFormat", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * em_format_class_add_handler:
+ * @emfc: EMFormatClass
+ * @info: Callback information.
+ *
+ * Add a mime type handler to this class. This is only used by
+ * implementing classes. The @info.old pointer will automatically be
+ * setup to point to the old hanlder if one was already set. This can
+ * be used for overrides a fallback.
+ *
+ * When a mime type described by @info is encountered, the callback will
+ * be invoked. Note that @info may be extended by sub-classes if
+ * they require additional context information.
+ *
+ * Use a mime type of "foo/ *" to insert a fallback handler for type "foo".
+ **/
+void
+em_format_class_add_handler(EMFormatClass *emfc, EMFormatHandler *info)
+{
+ d(printf("adding format handler to '%s' '%s'\n", g_type_name_from_class((GTypeClass *)emfc), info->mime_type));
+ info->old = g_hash_table_lookup(emfc->type_handlers, info->mime_type);
- g_hash_table_insert(emfc->type_handlers, info->mime_type, info);
++ g_hash_table_insert(emfc->type_handlers, (gpointer) info->mime_type, info);
+}
+
+struct _class_handlers {
+ EMFormatClass *old;
+ EMFormatClass *new;
+};
+static void
+merge_missing (gpointer key, gpointer value, gpointer userdata)
+{
+ struct _class_handlers *classes = (struct _class_handlers *) userdata;
+ EMFormatHandler *info, *oldinfo;
+
+ oldinfo = (EMFormatHandler *) value;
+ info = g_hash_table_lookup (classes->new->type_handlers, key);
+ if (!info) {
+ /* Might be from a plugin */
+ g_hash_table_insert (classes->new->type_handlers, key, value);
+ }
+
+}
+
+void
+em_format_merge_handler(EMFormat *new, EMFormat *old)
+{
+ EMFormatClass *oldc = (EMFormatClass *)G_OBJECT_GET_CLASS(old);
+ EMFormatClass *newc = (EMFormatClass *)G_OBJECT_GET_CLASS(new);
+ struct _class_handlers fclasses;
+
+ fclasses.old = oldc;
+ fclasses.new = newc;
+
+ g_hash_table_foreach (oldc->type_handlers, merge_missing, &fclasses);
+
+}
+
+/**
+ * em_format_class_remove_handler:
+ * @emfc:
+ * @info:
+ *
+ * Remove a handler. @info must be a value which was previously
+ * added.
+ **/
+void
+em_format_class_remove_handler(EMFormatClass *emfc, EMFormatHandler *info)
+{
+ EMFormatHandler *current;
+
+ /* TODO: thread issues? */
+
+ current = g_hash_table_lookup(emfc->type_handlers, info->mime_type);
+ if (current == info) {
+ current = info->old;
+ if (current)
- g_hash_table_insert(emfc->type_handlers, current->mime_type, current);
++ g_hash_table_insert(emfc->type_handlers, (gpointer) current->mime_type, current);
+ else
+ g_hash_table_remove(emfc->type_handlers, info->mime_type);
+ } else {
+ while (current && current->old != info)
+ current = current->old;
+ g_return_if_fail(current != NULL);
+ current->old = info->old;
+ }
+}
+
+const EMFormatHandler *
+em_format_find_handler (EMFormat *emf,
+ const gchar *mime_type)
+{
+ EMFormatClass *class;
+
+ g_return_val_if_fail (EM_IS_FORMAT (emf), NULL);
+ g_return_val_if_fail (mime_type != NULL, NULL);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_val_if_fail (class->find_handler != NULL, NULL);
+ return class->find_handler (emf, mime_type);
+}
+
+/**
+ * em_format_find_handler:
+ * @emf:
+ * @mime_type:
+ *
+ * Find a format handler by @mime_type.
+ *
+ * Return value: NULL if no handler is available.
+ **/
+static const EMFormatHandler *
+emf_find_handler(EMFormat *emf, const char *mime_type)
+{
+ EMFormatClass *emfc = (EMFormatClass *)G_OBJECT_GET_CLASS(emf);
+
+ return g_hash_table_lookup(emfc->type_handlers, mime_type);
+}
+
+/**
+ * em_format_fallback_handler:
+ * @emf:
+ * @mime_type:
+ *
+ * Try to find a format handler based on the major type of the @mime_type.
+ *
+ * The subtype is replaced with "*" and a lookup performed.
+ *
+ * Return value:
+ **/
+const EMFormatHandler *
+em_format_fallback_handler(EMFormat *emf, const char *mime_type)
+{
+ char *mime, *s;
+
+ s = strchr(mime_type, '/');
+ if (s == NULL)
+ mime = (char *)mime_type;
+ else {
+ size_t len = (s-mime_type)+1;
+
+ mime = alloca(len+2);
+ strncpy(mime, mime_type, len);
+ strcpy(mime+len, "*");
+ }
+
+ return em_format_find_handler(emf, mime);
+}
+
+/**
+ * em_format_add_puri:
+ * @emf:
+ * @size:
+ * @cid: Override the autogenerated content id.
+ * @part:
+ * @func:
+ *
+ * Add a pending-uri handler. When formatting parts that reference
+ * other parts, a pending-uri (PURI) can be used to track the reference.
+ *
+ * @size is used to allocate the structure, so that it can be directly
+ * subclassed by implementors.
+ *
+ * @cid can be used to override the key used to retreive the PURI, if NULL,
+ * then the content-location and the content-id of the @part are stored
+ * as lookup keys for the part.
+ *
+ * FIXME: This may need a free callback.
+ *
+ * Return value: A new PURI, with a referenced copy of @part, and the cid
+ * always set. The uri will be set if one is available. Clashes
+ * are resolved by forgetting the old PURI in the global index.
+ **/
+EMFormatPURI *
+em_format_add_puri(EMFormat *emf, size_t size, const char *cid, CamelMimePart *part, EMFormatPURIFunc func)
+{
+ EMFormatPURI *puri;
+ const char *tmp;
+
+ d(printf("adding puri for part: %s\n", emf->part_id->str));
+
+ if (size < sizeof(*puri)) {
+ g_warning (
+ "size (%" G_GSIZE_FORMAT
+ ") less than size of puri\n", size);
+ size = sizeof (*puri);
+ }
+
+ puri = g_malloc0(size);
+
+ puri->format = emf;
+ puri->func = func;
+ puri->use_count = 0;
+ puri->cid = g_strdup(cid);
+ puri->part_id = g_strdup(emf->part_id->str);
+
+ if (part) {
+ camel_object_ref(part);
+ puri->part = part;
+ }
+
+ if (part != NULL && cid == NULL) {
+ tmp = camel_mime_part_get_content_id(part);
+ if (tmp)
+ puri->cid = g_strdup_printf("cid:%s", tmp);
+ else
+ puri->cid = g_strdup_printf("em-no-cid:%s", emf->part_id->str);
+
+ d(printf("built cid '%s'\n", puri->cid));
+
+ /* not quite same as old behaviour, it also put in the relative uri and a fallback for no parent uri */
+ tmp = camel_mime_part_get_content_location(part);
+ puri->uri = NULL;
+ if (tmp == NULL) {
+ /* no location, don't set a uri at all, html parts do this themselves */
+ } else {
+ if (strchr(tmp, ':') == NULL && emf->base != NULL) {
+ CamelURL *uri;
+
+ uri = camel_url_new_with_base(emf->base, tmp);
+ puri->uri = camel_url_to_string(uri, 0);
+ camel_url_free(uri);
+ } else {
+ puri->uri = g_strdup(tmp);
+ }
+ }
+ }
+
+ g_return_val_if_fail (puri->cid != NULL, NULL);
+ g_return_val_if_fail (emf->pending_uri_level != NULL, NULL);
+ g_return_val_if_fail (emf->pending_uri_table != NULL, NULL);
+
+ e_dlist_addtail(&emf->pending_uri_level->uri_list, (EDListNode *)puri);
+
+ if (puri->uri)
+ g_hash_table_insert(emf->pending_uri_table, puri->uri, puri);
+ g_hash_table_insert(emf->pending_uri_table, puri->cid, puri);
+
+ return puri;
+}
+
+/**
+ * em_format_push_level:
+ * @emf:
+ *
+ * This is used to build a heirarchy of visible PURI objects based on
+ * the structure of the message. Used by multipart/alternative formatter.
+ *
+ * FIXME: This could probably also take a uri so it can automaticall update
+ * the base location.
+ **/
+void
+em_format_push_level(EMFormat *emf)
+{
+ struct _EMFormatPURITree *purilist;
+
+ d(printf("em_format_push_level\n"));
+ purilist = g_malloc0(sizeof(*purilist));
+ e_dlist_init(&purilist->children);
+ e_dlist_init(&purilist->uri_list);
+ purilist->parent = emf->pending_uri_level;
+ if (emf->pending_uri_tree == NULL) {
+ emf->pending_uri_tree = purilist;
+ } else {
+ e_dlist_addtail(&emf->pending_uri_level->children, (EDListNode *)purilist);
+ }
+ emf->pending_uri_level = purilist;
+}
+
+/**
+ * em_format_pull_level:
+ * @emf:
+ *
+ * Drop a level of visibility back to the parent. Note that
+ * no PURI values are actually freed.
+ **/
+void
+em_format_pull_level(EMFormat *emf)
+{
+ d(printf("em_format_pull_level\n"));
+ emf->pending_uri_level = emf->pending_uri_level->parent;
+}
+
+/**
+ * em_format_find_visible_puri:
+ * @emf:
+ * @uri:
+ *
+ * Search for a PURI based on the visibility defined by :push_level()
+ * and :pull_level().
+ *
+ * Return value:
+ **/
+EMFormatPURI *
+em_format_find_visible_puri(EMFormat *emf, const char *uri)
+{
+ EMFormatPURI *pw;
+ struct _EMFormatPURITree *ptree;
+
+ d(printf("checking for visible uri '%s'\n", uri));
+
+ ptree = emf->pending_uri_level;
+ while (ptree) {
+ pw = (EMFormatPURI *)ptree->uri_list.head;
+ while (pw->next) {
+ d(printf(" pw->uri = '%s' pw->cid = '%s\n", pw->uri?pw->uri:"", pw->cid));
+ if ((pw->uri && !strcmp(pw->uri, uri)) || !strcmp(pw->cid, uri))
+ return pw;
+ pw = pw->next;
+ }
+ ptree = ptree->parent;
+ }
+
+ return NULL;
+}
+
+/**
+ * em_format_find_puri:
+ * @emf:
+ * @uri:
+ *
+ * Search for a PURI based on a uri. Both the content-id
+ * and content-location are checked.
+ *
+ * Return value:
+ **/
+EMFormatPURI *
+
+em_format_find_puri(EMFormat *emf, const char *uri)
+{
+ return g_hash_table_lookup(emf->pending_uri_table, uri);
+}
+
+static void
+emf_clear_puri_node(struct _EMFormatPURITree *node)
+{
+ {
+ EMFormatPURI *pw, *pn;
+
+ /* clear puri's at this level */
+ pw = (EMFormatPURI *)node->uri_list.head;
+ pn = pw->next;
+ while (pn) {
+ d(printf ("freeing pw %p format:%p\n", pw, pw->format));
+ if (pw->free)
+ pw->free(pw);
+ g_free(pw->uri);
+ g_free(pw->cid);
+ g_free(pw->part_id);
+ if (pw->part)
+ camel_object_unref(pw->part);
+ g_free(pw);
+ pw = pn;
+ pn = pn->next;
+ }
+ }
+
+ {
+ struct _EMFormatPURITree *cw, *cn;
+
+ /* clear child nodes */
+ cw = (struct _EMFormatPURITree *)node->children.head;
+ cn = cw->next;
+ while (cn) {
+ emf_clear_puri_node(cw);
+ cw = cn;
+ cn = cn->next;
+ }
+ }
+
+ g_free(node);
+}
+
+/**
+ * em_format_clear_puri_tree:
+ * @emf:
+ *
+ * For use by implementors to clear out the message structure
+ * data.
+ **/
+void
+em_format_clear_puri_tree(EMFormat *emf)
+{
+ d(printf("clearing pending uri's\n"));
+
+ if (emf->pending_uri_table) {
+ g_hash_table_destroy(emf->pending_uri_table);
+ emf_clear_puri_node(emf->pending_uri_tree);
+ emf->pending_uri_level = NULL;
+ emf->pending_uri_tree = NULL;
+ }
+ emf->pending_uri_table = g_hash_table_new(g_str_hash, g_str_equal);
+ em_format_push_level(emf);
+}
+
+/* use mime_type == NULL to force showing as application/octet-stream */
+void
+em_format_part_as(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const char *mime_type)
+{
+ const EMFormatHandler *handle = NULL;
+ const char *snoop_save = emf->snoop_mime_type, *tmp;
+ CamelURL *base_save = emf->base, *base = NULL;
+ char *basestr = NULL;
+
+ d(printf("format_part_as()\n"));
+
+ emf->snoop_mime_type = NULL;
+
+ /* RFC 2110, we keep track of content-base, and absolute content-location headers
+ This is actually only required for html, but, *shrug* */
+ tmp = camel_medium_get_header((CamelMedium *)part, "Content-Base");
+ if (tmp == NULL) {
+ tmp = camel_mime_part_get_content_location(part);
+ if (tmp && strchr(tmp, ':') == NULL)
+ tmp = NULL;
+ } else {
+ tmp = basestr = camel_header_location_decode(tmp);
+ }
+ d(printf("content-base is '%s'\n", tmp?tmp:"<unset>"));
+ if (tmp
+ && (base = camel_url_new(tmp, NULL))) {
+ emf->base = base;
+ d(printf("Setting content base '%s'\n", tmp));
+ }
+ g_free(basestr);
+
+ if (mime_type != NULL) {
+ if (g_ascii_strcasecmp(mime_type, "application/octet-stream") == 0) {
+ emf->snoop_mime_type = mime_type = em_format_snoop_type(part);
+ if (mime_type == NULL)
+ mime_type = "application/octet-stream";
+ }
+
+ handle = em_format_find_handler(emf, mime_type);
+ if (handle == NULL)
+ handle = em_format_fallback_handler(emf, mime_type);
+
+ if (handle != NULL
+ && !em_format_is_attachment(emf, part)) {
+ d(printf("running handler for type '%s'\n", mime_type));
+ handle->handler(emf, stream, part, handle);
+ goto finish;
+ }
+ d(printf("this type is an attachment? '%s'\n", mime_type));
+ } else {
+ mime_type = "application/octet-stream";
+ }
+
+ ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_attachment(emf, stream, part, mime_type, handle);
+finish:
+ emf->base = base_save;
+ emf->snoop_mime_type = snoop_save;
+
+ if (base)
+ camel_url_free(base);
+}
+
+void
+em_format_part(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
+{
+ char *mime_type;
+ CamelDataWrapper *dw;
+
+ dw = camel_medium_get_content_object((CamelMedium *)part);
+ mime_type = camel_data_wrapper_get_mime_type(dw);
+ if (mime_type) {
+ camel_strdown(mime_type);
+ em_format_part_as(emf, stream, part, mime_type);
+ g_free(mime_type);
+ } else
+ em_format_part_as(emf, stream, part, "text/plain");
+}
+
+static void
+emf_clone_inlines(void *key, void *val, void *data)
+{
+ struct _EMFormatCache *emfc = val, *new;
+
+ new = emf_insert_cache((EMFormat *)data, emfc->partid);
+ new->state = emfc->state;
+ if (emfc->valid)
+ new->valid = camel_cipher_validity_clone(emfc->valid);
+ if (emfc->secured)
+ camel_object_ref((new->secured = emfc->secured));
+}
+
+static void
+emf_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *emfsource)
+{
+ em_format_clear_puri_tree(emf);
+
+ if (emf != emfsource) {
+ g_hash_table_remove_all(emf->inline_table);
+ if (emfsource) {
+ struct _EMFormatHeader *h;
+
+ /* We clone the current state here */
+ g_hash_table_foreach(emfsource->inline_table, emf_clone_inlines, emf);
+ emf->mode = emfsource->mode;
+ g_free(emf->charset);
+ emf->charset = g_strdup(emfsource->charset);
+ g_free (emf->default_charset);
+ emf->default_charset = g_strdup (emfsource->default_charset);
+
+ em_format_clear_headers(emf);
+ for (h = (struct _EMFormatHeader *)emfsource->header_list.head; h->next; h = h->next)
+ em_format_add_header(emf, h->name, h->flags);
+ }
+ }
+
+ /* what a mess */
+ if (folder != emf->folder) {
+ if (emf->folder)
+ camel_object_unref(emf->folder);
+ if (folder)
+ camel_object_ref(folder);
+ emf->folder = folder;
+ }
+
+ if (uid != emf->uid) {
+ g_free(emf->uid);
+ emf->uid = g_strdup(uid);
+ }
+
+ if (msg != emf->message) {
+ if (emf->message)
+ camel_object_unref(emf->message);
+ if (msg)
+ camel_object_ref(msg);
+ emf->message = msg;
+ }
+
+ g_string_truncate(emf->part_id, 0);
+ if (folder != NULL)
+ /* TODO build some string based on the folder name/location? */
+ g_string_append_printf(emf->part_id, ".%p", (gpointer) folder);
+ if (uid != NULL)
+ g_string_append_printf(emf->part_id, ".%s", uid);
+}
+
+static void
+emf_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid)
+{
+ CamelCipherValidity *save = emf->valid_parent;
+ int len;
+
+ /* Note that this also requires support from higher up in the class chain
+ - validity needs to be cleared when you start output
+ - also needs to be cleared (but saved) whenever you start a new message. */
+
+ if (emf->valid == NULL) {
+ emf->valid = valid;
+ } else {
+ camel_dlist_addtail(&emf->valid_parent->children, (CamelDListNode *)valid);
+ camel_cipher_validity_envelope(emf->valid_parent, valid);
+ }
+
+ emf->valid_parent = valid;
+
+ len = emf->part_id->len;
+ g_string_append_printf(emf->part_id, ".secured");
+ em_format_part(emf, stream, part);
+ g_string_truncate(emf->part_id, len);
+
+ emf->valid_parent = save;
+}
+
+static gboolean
+emf_busy(EMFormat *emf)
+{
+ return FALSE;
+}
+
+/**
+ * em_format_format_clone:
+ * @emf: an #EMFormat
+ * @folder: a #CamelFolder or %NULL
+ * @uid: Message UID or %NULL
+ * @msg: a #CamelMimeMessage or %NULL
+ * @emfsource: Used as a basis for user-altered layout, e.g. inline viewed
+ * attachments.
+ *
+ * Format a message @msg. If @emfsource is non NULL, then the status of
+ * inlined expansion and so forth is copied direction from @emfsource.
+ *
+ * By passing the same value for @emf and @emfsource, you can perform
+ * a display refresh, or it can be used to generate an identical layout,
+ * e.g. to print what the user has shown inline.
+ **/
+void
+em_format_format_clone (EMFormat *emf,
+ CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ EMFormat *source)
+{
+ EMFormatClass *class;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (folder == NULL || CAMEL_IS_FOLDER (folder));
+ g_return_if_fail (message == NULL || CAMEL_IS_MIME_MESSAGE (message));
+ g_return_if_fail (source == NULL || EM_IS_FORMAT (source));
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_clone != NULL);
+ class->format_clone (emf, folder, uid, message, source);
+}
+
+void
+em_format_format (EMFormat *emf,
+ CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message)
+{
+ /* em_format_format_clone() will check the arguments. */
+ em_format_format_clone (emf, folder, uid, message, NULL);
+}
+
+void
+em_format_redraw (EMFormat *emf)
+{
+ g_return_if_fail (EM_IS_FORMAT (emf));
+
+ em_format_format_clone (
+ emf, emf->folder, emf->uid, emf->message, emf);
+}
+
+/**
+ * em_format_set_mode:
+ * @emf:
+ * @type:
+ *
+ * Set display mode, EM_FORMAT_SOURCE, EM_FORMAT_ALLHEADERS, or
+ * EM_FORMAT_NORMAL.
+ **/
+void
+em_format_set_mode(EMFormat *emf, em_format_mode_t type)
+{
+ if (emf->mode == type)
+ return;
+
+ emf->mode = type;
+
+ /* force redraw if type changed afterwards */
+ if (emf->message)
+ em_format_redraw(emf);
+}
+
+/**
+ * em_format_set_charset:
+ * @emf:
+ * @charset:
+ *
+ * set override charset on formatter. message will be redisplayed if
+ * required.
+ **/
+void
+em_format_set_charset(EMFormat *emf, const char *charset)
+{
+ if ((emf->charset && charset && g_ascii_strcasecmp(emf->charset, charset) == 0)
+ || (emf->charset == NULL && charset == NULL)
+ || (emf->charset == charset))
+ return;
+
+ g_free(emf->charset);
+ emf->charset = g_strdup(charset);
+
+ if (emf->message)
+ em_format_redraw(emf);
+}
+
+/**
+ * em_format_set_default_charset:
+ * @emf:
+ * @charset:
+ *
+ * Set the fallback, default system charset to use when no other charsets
+ * are present. Message will be redisplayed if required (and sometimes redisplayed
+ * when it isn't).
+ **/
+void
+em_format_set_default_charset(EMFormat *emf, const char *charset)
+{
+ if ((emf->default_charset && charset && g_ascii_strcasecmp(emf->default_charset, charset) == 0)
+ || (emf->default_charset == NULL && charset == NULL)
+ || (emf->default_charset == charset))
+ return;
+
+ g_free(emf->default_charset);
+ emf->default_charset = g_strdup(charset);
+
+ if (emf->message && emf->charset == NULL)
+ em_format_redraw(emf);
+}
+
+/**
+ * em_format_clear_headers:
+ * @emf:
+ *
+ * Clear the list of headers to be displayed. This will force all headers to
+ * be shown.
+ **/
+void
+em_format_clear_headers(EMFormat *emf)
+{
+ EMFormatHeader *eh;
+
+ while ((eh = (EMFormatHeader *)e_dlist_remhead(&emf->header_list)))
+ g_free(eh);
+}
+
+/* note: also copied in em-mailer-prefs.c */
+static const struct {
+ const char *name;
+ guint32 flags;
+} default_headers[] = {
+ { N_("From"), EM_FORMAT_HEADER_BOLD },
+ { N_("Reply-To"), EM_FORMAT_HEADER_BOLD },
+ { N_("To"), EM_FORMAT_HEADER_BOLD },
+ { N_("Cc"), EM_FORMAT_HEADER_BOLD },
+ { N_("Bcc"), EM_FORMAT_HEADER_BOLD },
+ { N_("Subject"), EM_FORMAT_HEADER_BOLD },
+ { N_("Date"), EM_FORMAT_HEADER_BOLD },
+ { N_("Newsgroups"), EM_FORMAT_HEADER_BOLD },
+ { N_("Face"), 0 },
+};
+
+/**
+ * em_format_default_headers:
+ * @emf:
+ *
+ * Set the headers to show to the default list.
+ *
+ * From, Reply-To, To, Cc, Bcc, Subject and Date.
+ **/
+void
+em_format_default_headers(EMFormat *emf)
+{
+ int i;
+
+ em_format_clear_headers(emf);
+ for (i=0; i<sizeof(default_headers)/sizeof(default_headers[0]); i++)
+ em_format_add_header(emf, default_headers[i].name, default_headers[i].flags);
+}
+
+/**
+ * em_format_add_header:
+ * @emf:
+ * @name: The name of the header, as it will appear during output.
+ * @flags: EM_FORMAT_HEAD_* defines to control display attributes.
+ *
+ * Add a specific header to show. If any headers are set, they will
+ * be displayed in the order set by this function. Certain known
+ * headers included in this list will be shown using special
+ * formatting routines.
+ **/
+void em_format_add_header(EMFormat *emf, const char *name, guint32 flags)
+{
+ EMFormatHeader *h;
+
+ h = g_malloc(sizeof(*h) + strlen(name));
+ h->flags = flags;
+ strcpy(h->name, name);
+ e_dlist_addtail(&emf->header_list, (EDListNode *)h);
+}
+
+/**
+ * em_format_is_attachment:
+ * @emf:
+ * @part: Part to check.
+ *
+ * Returns true if the part is an attachment.
+ *
+ * A part is not considered an attachment if it is a
+ * multipart, or a text part with no filename. It is used
+ * to determine if an attachment header should be displayed for
+ * the part.
+ *
+ * Content-Disposition is not checked.
+ *
+ * Return value: TRUE/FALSE
+ **/
+int em_format_is_attachment(EMFormat *emf, CamelMimePart *part)
+{
+ /*CamelContentType *ct = camel_mime_part_get_content_type(part);*/
+ CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
+
+ /*printf("checking is attachment %s/%s\n", ct->type, ct->subtype);*/
+ return !(camel_content_type_is (dw->mime_type, "multipart", "*")
+ || camel_content_type_is(dw->mime_type, "application", "x-pkcs7-mime")
+ || camel_content_type_is(dw->mime_type, "application", "pkcs7-mime")
+ || camel_content_type_is(dw->mime_type, "application", "x-inlinepgp-signed")
+ || camel_content_type_is(dw->mime_type, "application", "x-inlinepgp-encrypted")
+ || camel_content_type_is(dw->mime_type, "x-evolution", "evolution-rss-feed")
+ || (camel_content_type_is (dw->mime_type, "text", "*")
+ && camel_mime_part_get_filename(part) == NULL));
+}
+
+/**
+ * em_format_is_inline:
+ * @emf:
+ * @part:
+ * @partid: format->part_id part id of this part.
+ * @handle: handler for this part
+ *
+ * Returns true if the part should be displayed inline. Any part with
+ * a Content-Disposition of inline, or if the @handle has a default
+ * inline set, will be shown inline.
+ *
+ * :set_inline() called on the same part will override any calculated
+ * value.
+ *
+ * Return value:
+ **/
+int em_format_is_inline(EMFormat *emf, const char *partid, CamelMimePart *part, const EMFormatHandler *handle)
+{
+ struct _EMFormatCache *emfc;
+ const char *tmp;
+
+ if (handle == NULL)
+ return FALSE;
+
+ emfc = g_hash_table_lookup(emf->inline_table, partid);
+ if (emfc && emfc->state != INLINE_UNSET)
+ return emfc->state & 1;
+
+ /* some types need to override the disposition, e.g. application/x-pkcs7-mime */
+ if (handle->flags & EM_FORMAT_HANDLER_INLINE_DISPOSITION)
+ return TRUE;
+
+ tmp = camel_mime_part_get_disposition(part);
+ if (tmp)
+ return g_ascii_strcasecmp(tmp, "inline") == 0;
+
+ /* otherwise, use the default for this handler type */
+ return (handle->flags & EM_FORMAT_HANDLER_INLINE) != 0;
+}
+
+/**
+ * em_format_set_inline:
+ * @emf:
+ * @partid: id of part
+ * @state:
+ *
+ * Force the attachment @part to be expanded or hidden explictly to match
+ * @state. This is used only to record the change for a redraw or
+ * cloned layout render and does not force a redraw.
+ **/
+void em_format_set_inline(EMFormat *emf, const char *partid, int state)
+{
+ struct _EMFormatCache *emfc;
+
+ emfc = g_hash_table_lookup(emf->inline_table, partid);
+ if (emfc == NULL) {
+ emfc = emf_insert_cache(emf, partid);
+ } else if (emfc->state != INLINE_UNSET && (emfc->state & 1) == state)
+ return;
+
+ emfc->state = state?INLINE_ON:INLINE_OFF;
+
+ if (emf->message)
+ em_format_redraw(emf);
+}
+
+void
+em_format_format_attachment (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part,
+ const gchar *mime_type,
+ const struct _EMFormatHandler *info)
+{
+ EMFormatClass *class;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+ g_return_if_fail (mime_type != NULL);
+ g_return_if_fail (info != NULL);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_attachment != NULL);
+ class->format_attachment (emf, stream, mime_part, mime_type, info);
+}
+
+void
+em_format_format_error (EMFormat *emf,
+ CamelStream *stream,
+ const gchar *format,
+ ...)
+{
+ EMFormatClass *class;
+ gchar *errmsg;
+ va_list ap;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+ g_return_if_fail (format != NULL);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_error != NULL);
+
+ va_start (ap, format);
+ errmsg = g_strdup_vprintf (format, ap);
+ class->format_error (emf, stream, errmsg);
+ g_free (errmsg);
+ va_end (ap);
+}
+
+void
+em_format_format_secure (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part,
+ CamelCipherValidity *valid)
+{
+ EMFormatClass *class;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+ g_return_if_fail (valid != NULL);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_secure != NULL);
+ class->format_secure (emf, stream, mime_part, valid);
+
+ if (emf->valid_parent == NULL && emf->valid != NULL) {
+ camel_cipher_validity_free (emf->valid);
+ emf->valid = NULL;
+ }
+}
+
+void
+em_format_format_source (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part)
+{
+ EMFormatClass *class;
+
+ g_return_if_fail (EM_IS_FORMAT (emf));
+ g_return_if_fail (CAMEL_IS_STREAM (stream));
+ g_return_if_fail (CAMEL_IS_MIME_PART (mime_part));
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_if_fail (class->format_source != NULL);
+ class->format_source (emf, stream, mime_part);
+}
+
+gboolean
+em_format_busy (EMFormat *emf)
+{
+ EMFormatClass *class;
+
+ g_return_val_if_fail (EM_IS_FORMAT (emf), FALSE);
+
+ class = EM_FORMAT_GET_CLASS (emf);
+ g_return_val_if_fail (class->busy != NULL, FALSE);
+ return class->busy (emf);
+}
+
+/* should this be virtual? */
+void
+em_format_format_content(EMFormat *emf, CamelStream *stream, CamelMimePart *part)
+{
+ CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
+
+ if (camel_content_type_is (dw->mime_type, "text", "*"))
+ em_format_format_text(emf, stream, (CamelDataWrapper *)part);
+ else
+ camel_data_wrapper_decode_to_stream(dw, stream);
+}
+
+/**
+ * em_format_format_content:
+ * @emf:
+ * @stream: Where to write the converted text
+ * @part: Part whose container is to be formatted
+ *
+ * Decode/output a part's content to @stream.
+ **/
+void
+em_format_format_text(EMFormat *emf, CamelStream *stream, CamelDataWrapper *dw)
+{
+ CamelStreamFilter *filter_stream;
+ CamelMimeFilterCharset *filter;
+ const char *charset = NULL;
+ CamelMimeFilterWindows *windows = NULL;
+ CamelStream *mem_stream = NULL;
+ size_t size;
+ size_t max;
+ GConfClient *gconf;
+
+ if (emf->charset) {
+ charset = emf->charset;
+ } else if (dw->mime_type
+ && (charset = camel_content_type_param (dw->mime_type, "charset"))
+ && g_ascii_strncasecmp(charset, "iso-8859-", 9) == 0) {
+ CamelStream *null;
+
+ /* Since a few Windows mailers like to claim they sent
+ * out iso-8859-# encoded text when they really sent
+ * out windows-cp125#, do some simple sanity checking
+ * before we move on... */
+
+ null = camel_stream_null_new();
+ filter_stream = camel_stream_filter_new_with_stream(null);
+ camel_object_unref(null);
+
+ windows = (CamelMimeFilterWindows *)camel_mime_filter_windows_new(charset);
+ camel_stream_filter_add(filter_stream, (CamelMimeFilter *)windows);
+
+ camel_data_wrapper_decode_to_stream(dw, (CamelStream *)filter_stream);
+ camel_stream_flush((CamelStream *)filter_stream);
+ camel_object_unref(filter_stream);
+
+ charset = camel_mime_filter_windows_real_charset (windows);
+ } else if (charset == NULL) {
+ charset = emf->default_charset;
+ }
+
+ mem_stream = (CamelStream *)camel_stream_mem_new ();
+ filter_stream = camel_stream_filter_new_with_stream(mem_stream);
+
+ if ((filter = camel_mime_filter_charset_new_convert(charset, "UTF-8"))) {
+ camel_stream_filter_add(filter_stream, (CamelMimeFilter *) filter);
+ camel_object_unref(filter);
+ }
+
+ max = -1;
+
+ gconf = gconf_client_get_default ();
+ if (gconf_client_get_bool (gconf, "/apps/evolution/mail/display/force_message_limit", NULL)) {
+ max = gconf_client_get_int (gconf, "/apps/evolution/mail/display/message_text_part_limit", NULL);
+ if (max == 0)
+ max = -1;
+ }
+ g_object_unref (gconf);
+
+ size = camel_data_wrapper_decode_to_stream(emf->mode == EM_FORMAT_SOURCE ? (CamelDataWrapper *)dw: camel_medium_get_content_object((CamelMedium *)dw), (CamelStream *)filter_stream);
+ camel_stream_flush((CamelStream *)filter_stream);
+ camel_object_unref(filter_stream);
+ camel_stream_reset (mem_stream);
+
+ if (max == -1 || size == -1 || size < (max * 1024) || emf->composer) {
+ camel_stream_write_to_stream(mem_stream, (CamelStream *)stream);
+ camel_stream_flush((CamelStream *)stream);
+ } else {
+ ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->format_optional(emf, stream, (CamelMimePart *)dw, mem_stream);
+ }
+
+ if (windows)
+ camel_object_unref(windows);
+}
+
+/**
+ * em_format_describe_part:
+ * @part:
+ * @mimetype:
+ *
+ * Generate a simple textual description of a part, @mime_type represents the
+ * the content.
+ *
+ * Return value:
+ **/
+char *
+em_format_describe_part(CamelMimePart *part, const char *mime_type)
+{
+ GString *stext;
+ const char *filename, *description;
+ char *content_type, *desc;
+
+ stext = g_string_new("");
+ content_type = g_content_type_from_mime_type (mime_type);
+ desc = g_content_type_get_description (content_type ? content_type : mime_type);
+ g_free (content_type);
+ g_string_append_printf (stext, _("%s attachment"), desc ? desc : mime_type);
+ g_free (desc);
+ if ((filename = camel_mime_part_get_filename (part)))
+ g_string_append_printf(stext, " (%s)", filename);
+ if ((description = camel_mime_part_get_description(part)) &&
+ (*description != 0) &&
+ !(filename && (strcmp(filename, description) == 0)))
+ g_string_append_printf(stext, ", \"%s\"", description);
+
+ return g_string_free (stext, FALSE);
+}
+
+/* ********************************************************************** */
+
+#ifdef ENABLE_SMIME
+static void
+emf_application_xpkcs7mime(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelCipherContext *context;
+ CamelException *ex;
+ CamelMimePart *opart;
+ CamelCipherValidity *valid;
+ struct _EMFormatCache *emfc;
+
+ /* should this perhaps run off a key of ".secured" ? */
+ emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
+ if (emfc && emfc->valid) {
+ em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
+ return;
+ }
+
+ ex = camel_exception_new();
+
+ context = camel_smime_context_new(emf->session);
+
+ opart = camel_mime_part_new();
+ valid = camel_cipher_decrypt(context, part, opart, ex);
+ if (valid == NULL) {
+ em_format_format_error(emf, stream, "%s", ex->desc?ex->desc:_("Could not parse S/MIME message: Unknown error"));
+ em_format_part_as(emf, stream, part, NULL);
+ } else {
+ if (emfc == NULL)
+ emfc = emf_insert_cache(emf, emf->part_id->str);
+
+ emfc->valid = camel_cipher_validity_clone(valid);
+ camel_object_ref((emfc->secured = opart));
+
+ em_format_format_secure(emf, stream, opart, valid);
+ }
+
+ camel_object_unref(opart);
+ camel_object_unref(context);
+ camel_exception_free(ex);
+}
+#endif
+
+/* RFC 1740 */
+static void
+emf_multipart_appledouble(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+ CamelMimePart *mime_part;
+ int len;
+
+ if (!CAMEL_IS_MULTIPART(mp)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ mime_part = camel_multipart_get_part(mp, 1);
+ if (mime_part) {
+ /* try the data fork for something useful, doubtful but who knows */
+ len = emf->part_id->len;
+ g_string_append_printf(emf->part_id, ".appledouble.1");
+ em_format_part(emf, stream, mime_part);
+ g_string_truncate(emf->part_id, len);
+ } else
+ em_format_format_source(emf, stream, part);
+
+}
+
+/* RFC ??? */
+static void
+emf_multipart_mixed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+ int i, nparts, len;
+
+ if (!CAMEL_IS_MULTIPART(mp)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ len = emf->part_id->len;
+ nparts = camel_multipart_get_number(mp);
+ for (i = 0; i < nparts; i++) {
+ part = camel_multipart_get_part(mp, i);
+ g_string_append_printf(emf->part_id, ".mixed.%d", i);
+ em_format_part(emf, stream, part);
+ g_string_truncate(emf->part_id, len);
+ }
+}
+
+/* RFC 1740 */
+static void
+emf_multipart_alternative(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+ int i, nparts, bestid = 0;
+ CamelMimePart *best = NULL;
+
+ if (!CAMEL_IS_MULTIPART(mp)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ /* as per rfc, find the last part we know how to display */
+ nparts = camel_multipart_get_number(mp);
+ for (i = 0; i < nparts; i++) {
+ CamelContentType *type;
+ char *mime_type;
+
+ /* is it correct to use the passed in *part here? */
+ part = camel_multipart_get_part(mp, i);
+
+ if (!part)
+ continue;
+
+ type = camel_mime_part_get_content_type (part);
+ mime_type = camel_content_type_simple (type);
+
+ camel_strdown (mime_type);
+
+ /*if (want_plain && !strcmp (mime_type, "text/plain"))
+ return part;*/
+
+ if (em_format_find_handler(emf, mime_type)
+ || (best == NULL && em_format_fallback_handler(emf, mime_type))) {
+ best = part;
+ bestid = i;
+ }
+
+ g_free(mime_type);
+ }
+
+ if (best) {
+ int len = emf->part_id->len;
+
+ g_string_append_printf(emf->part_id, ".alternative.%d", bestid);
+ em_format_part(emf, stream, best);
+ g_string_truncate(emf->part_id, len);
+ } else
+ emf_multipart_mixed(emf, stream, part, info);
+}
+
+static void
+emf_multipart_encrypted(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelCipherContext *context;
+ CamelException *ex;
+ const char *protocol;
+ CamelMimePart *opart;
+ CamelCipherValidity *valid;
+ CamelMultipartEncrypted *mpe;
+ struct _EMFormatCache *emfc;
+
+ /* should this perhaps run off a key of ".secured" ? */
+ emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
+ if (emfc && emfc->valid) {
+ em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
+ return;
+ }
+
+ mpe = (CamelMultipartEncrypted*)camel_medium_get_content_object((CamelMedium *)part);
+ if (!CAMEL_IS_MULTIPART_ENCRYPTED(mpe)) {
+ em_format_format_error(emf, stream, _("Could not parse MIME message. Displaying as source."));
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ /* Currently we only handle RFC2015-style PGP encryption. */
+ protocol = camel_content_type_param(((CamelDataWrapper *)mpe)->mime_type, "protocol");
+ if (!protocol || g_ascii_strcasecmp (protocol, "application/pgp-encrypted") != 0) {
+ em_format_format_error(emf, stream, _("Unsupported encryption type for multipart/encrypted"));
+ em_format_part_as(emf, stream, part, "multipart/mixed");
+ return;
+ }
+
+ ex = camel_exception_new();
+ context = camel_gpg_context_new(emf->session);
+ opart = camel_mime_part_new();
+ valid = camel_cipher_decrypt(context, part, opart, ex);
+ if (valid == NULL) {
+ em_format_format_error(emf, stream, ex->desc?_("Could not parse PGP/MIME message"):_("Could not parse PGP/MIME message: Unknown error"));
+ if (ex->desc)
+ em_format_format_error(emf, stream, "%s", ex->desc);
+ em_format_part_as(emf, stream, part, "multipart/mixed");
+ } else {
+ if (emfc == NULL)
+ emfc = emf_insert_cache(emf, emf->part_id->str);
+
+ emfc->valid = camel_cipher_validity_clone(valid);
+ camel_object_ref((emfc->secured = opart));
+
+ em_format_format_secure(emf, stream, opart, valid);
+ }
+
+ /* TODO: Make sure when we finalize this part, it is zero'd out */
+ camel_object_unref(opart);
+ camel_object_unref(context);
+ camel_exception_free(ex);
+}
+
+static void
+emf_write_related(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri)
+{
+ em_format_format_content(emf, stream, puri->part);
+ camel_stream_close(stream);
+}
+
+/* RFC 2387 */
+static void
+emf_multipart_related(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMultipart *mp = (CamelMultipart *)camel_medium_get_content_object((CamelMedium *)part);
+ CamelMimePart *body_part, *display_part = NULL;
+ CamelContentType *content_type;
+ const char *start;
+ int i, nparts, partidlen, displayid = 0;
+ char *oldpartid;
+ struct _EMFormatPURITree *ptree;
+ EMFormatPURI *puri, *purin;
+
+ if (!CAMEL_IS_MULTIPART(mp)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ /* FIXME: put this stuff in a shared function */
+ nparts = camel_multipart_get_number(mp);
+ content_type = camel_mime_part_get_content_type(part);
+ start = camel_content_type_param (content_type, "start");
+ if (start && strlen(start)>2) {
+ int len;
+ const char *cid;
+
+ /* strip <>'s */
+ len = strlen (start) - 2;
+ start++;
+
+ for (i=0; i<nparts; i++) {
+ body_part = camel_multipart_get_part(mp, i);
+ cid = camel_mime_part_get_content_id(body_part);
+
+ if (cid && !strncmp(cid, start, len) && strlen(cid) == len) {
+ display_part = body_part;
+ displayid = i;
+ break;
+ }
+ }
+ } else {
+ display_part = camel_multipart_get_part(mp, 0);
+ }
+
+ if (display_part == NULL) {
+ emf_multipart_mixed(emf, stream, part, info);
+ return;
+ }
+
+ em_format_push_level(emf);
+
+ oldpartid = g_strdup(emf->part_id->str);
+ partidlen = emf->part_id->len;
+
+ /* queue up the parts for possible inclusion */
+ for (i = 0; i < nparts; i++) {
+ body_part = camel_multipart_get_part(mp, i);
+ if (body_part != display_part) {
+ /* set the partid since add_puri uses it */
+ g_string_append_printf(emf->part_id, ".related.%d", i);
+ puri = em_format_add_puri(emf, sizeof(EMFormatPURI), NULL, body_part, emf_write_related);
+ g_string_truncate(emf->part_id, partidlen);
+ d(printf(" part '%s' '%s' added\n", puri->uri?puri->uri:"", puri->cid));
+ }
+ }
+
+ g_string_append_printf(emf->part_id, ".related.%d", displayid);
+ em_format_part(emf, stream, display_part);
+ g_string_truncate(emf->part_id, partidlen);
+ camel_stream_flush(stream);
+
+ ptree = emf->pending_uri_level;
+ puri = (EMFormatPURI *)ptree->uri_list.head;
+ purin = puri->next;
+ while (purin) {
+ if (puri->use_count == 0) {
+ d(printf("part '%s' '%s' used '%d'\n", puri->uri?puri->uri:"", puri->cid, puri->use_count));
+ if (puri->func == emf_write_related) {
+ g_string_printf(emf->part_id, "%s", puri->part_id);
+ em_format_part(emf, stream, puri->part);
- } else
++ } else {
+ d(printf("unreferenced uri generated by format code: %s\n", puri->uri?puri->uri:puri->cid));
++ }
+ }
+ puri = purin;
+ purin = purin->next;
+ }
+
+ g_string_printf(emf->part_id, "%s", oldpartid);
+ g_free(oldpartid);
+
+ em_format_pull_level(emf);
+}
+
+static void
+emf_multipart_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelMimePart *cpart;
+ CamelMultipartSigned *mps;
+ CamelCipherContext *cipher = NULL;
+ struct _EMFormatCache *emfc;
+
+ /* should this perhaps run off a key of ".secured" ? */
+ emfc = g_hash_table_lookup(emf->inline_table, emf->part_id->str);
+ if (emfc && emfc->valid) {
+ em_format_format_secure(emf, stream, emfc->secured, camel_cipher_validity_clone(emfc->valid));
+ return;
+ }
+
+ mps = (CamelMultipartSigned *)camel_medium_get_content_object((CamelMedium *)part);
+ if (!CAMEL_IS_MULTIPART_SIGNED(mps)
+ || (cpart = camel_multipart_get_part((CamelMultipart *)mps, CAMEL_MULTIPART_SIGNED_CONTENT)) == NULL) {
+ em_format_format_error(emf, stream, _("Could not parse MIME message. Displaying as source."));
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ /* FIXME: Should be done via a plugin interface */
+ /* FIXME: duplicated in em-format-html-display.c */
+ if (mps->protocol) {
+#ifdef ENABLE_SMIME
+ if (g_ascii_strcasecmp("application/x-pkcs7-signature", mps->protocol) == 0
+ || g_ascii_strcasecmp("application/pkcs7-signature", mps->protocol) == 0)
+ cipher = camel_smime_context_new(emf->session);
+ else
+#endif
+ if (g_ascii_strcasecmp("application/pgp-signature", mps->protocol) == 0)
+ cipher = camel_gpg_context_new(emf->session);
+ }
+
+ if (cipher == NULL) {
+ em_format_format_error(emf, stream, _("Unsupported signature format"));
+ em_format_part_as(emf, stream, part, "multipart/mixed");
+ } else {
+ CamelException *ex = camel_exception_new();
+ CamelCipherValidity *valid;
+
+ valid = camel_cipher_verify(cipher, part, ex);
+ if (valid == NULL) {
+ em_format_format_error(emf, stream, ex->desc?_("Error verifying signature"):_("Unknown error verifying signature"));
+ if (ex->desc)
+ em_format_format_error(emf, stream, "%s", ex->desc);
+ em_format_part_as(emf, stream, part, "multipart/mixed");
+ } else {
+ if (emfc == NULL)
+ emfc = emf_insert_cache(emf, emf->part_id->str);
+
+ emfc->valid = camel_cipher_validity_clone(valid);
+ camel_object_ref((emfc->secured = cpart));
+
+ em_format_format_secure(emf, stream, cpart, valid);
+ }
+
+ camel_exception_free(ex);
+ camel_object_unref(cipher);
+ }
+}
+
+static void
+emf_message_rfc822(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ CamelDataWrapper *dw = camel_medium_get_content_object((CamelMedium *)part);
+ const EMFormatHandler *handle;
+ int len;
+
+ if (!CAMEL_IS_MIME_MESSAGE(dw)) {
+ em_format_format_source(emf, stream, part);
+ return;
+ }
+
+ len = emf->part_id->len;
+ g_string_append_printf(emf->part_id, ".rfc822");
+
+ handle = em_format_find_handler(emf, "x-evolution/message/rfc822");
+ if (handle)
+ handle->handler(emf, stream, (CamelMimePart *)dw, handle);
+
+ g_string_truncate(emf->part_id, len);
+}
+
+static void
+emf_message_deliverystatus(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info)
+{
+ em_format_format_text(emf, stream, (CamelDataWrapper *)part);
+}
+
+static void
+emf_inlinepgp_signed(EMFormat *emf, CamelStream *stream, CamelMimePart *ipart, EMFormatHandler *info)
+{
+ CamelStreamFilter *filtered_stream;
+ CamelMimeFilterPgp *pgp_filter;
+ CamelContentType *content_type;
+ CamelCipherContext *cipher;
+ CamelCipherValidity *valid;
+ CamelDataWrapper *dw;
+ CamelMimePart *opart;
+ CamelStream *ostream;
+ CamelException *ex;
+ char *type;
+
+ if (!ipart) {
+ em_format_format_error(emf, stream, _("Unknown error verifying signature"));
+ return;
+ }
+
+ ex = camel_exception_new();
+ cipher = camel_gpg_context_new(emf->session);
+ /* Verify the signature of the message */
+ valid = camel_cipher_verify(cipher, ipart, ex);
+ if (!valid) {
+ em_format_format_error(emf, stream, ex->desc?_("Error verifying signature"):_("Unknown error verifying signature"));
+ if (ex->desc)
+ em_format_format_error(emf, stream, "%s", ex->desc);
+ em_format_format_source(emf, stream, ipart);
+ /* I think this will loop: em_format_part_as(emf, stream, part, "text/plain"); */
+ camel_exception_free(ex);
+ camel_object_unref(cipher);
+ return;
+ }
+
+ /* Setup output stream */
+ ostream = camel_stream_mem_new();
+ filtered_stream = camel_stream_filter_new_with_stream(ostream);
+
+ /* Add PGP header / footer filter */
+ pgp_filter = (CamelMimeFilterPgp *)camel_mime_filter_pgp_new();
+ camel_stream_filter_add(filtered_stream, (CamelMimeFilter *)pgp_filter);
+ camel_object_unref(pgp_filter);
+
+ /* Pass through the filters that have been setup */
+ dw = camel_medium_get_content_object((CamelMedium *)ipart);
+ camel_data_wrapper_decode_to_stream(dw, (CamelStream *)filtered_stream);
+ camel_stream_flush((CamelStream *)filtered_stream);
+ camel_object_unref(filtered_stream);
+
+ /* Create a new text/plain MIME part containing the signed content preserving the original part's Content-Type params */
+ content_type = camel_mime_part_get_content_type (ipart);
+ type = camel_content_type_format (content_type);
+ content_type = camel_content_type_decode (type);
+ g_free (type);
+
+ g_free (content_type->type);
+ content_type->type = g_strdup ("text");
+ g_free (content_type->subtype);
+ content_type->subtype = g_strdup ("plain");
+ type = camel_content_type_format (content_type);
+ camel_content_type_unref (content_type);
+
+ dw = camel_data_wrapper_new ();
+ camel_data_wrapper_construct_from_stream (dw, ostream);
+ camel_data_wrapper_set_mime_type (dw, type);
+ g_free (type);
+
+ opart = camel_mime_part_new ();
+ camel_medium_set_content_object ((CamelMedium *) opart, dw);
+ camel_data_wrapper_set_mime_type_field ((CamelDataWrapper *) opart, dw->mime_type);
+
+ /* Pass it off to the real formatter */
+ em_format_format_secure(emf, stream, opart, valid);
+
+ /* Clean Up */
+ camel_object_unref(dw);
+ camel_object_unref(opart);
+ camel_object_unref(ostream);
+ camel_object_unref(cipher);
+ camel_exception_free(ex);
+}
+
+static void
+emf_inlinepgp_encrypted(EMFormat *emf, CamelStream *stream, CamelMimePart *ipart, EMFormatHandler *info)
+{
+ CamelCipherContext *cipher;
+ CamelCipherValidity *valid;
+ CamelException *ex;
+ CamelMimePart *opart;
+ CamelDataWrapper *dw;
+ char *mime_type;
+
+ cipher = camel_gpg_context_new(emf->session);
+ ex = camel_exception_new();
+ opart = camel_mime_part_new();
+ /* Decrypt the message */
+ valid = camel_cipher_decrypt (cipher, ipart, opart, ex);
+ if (!valid) {
+ em_format_format_error(emf, stream, ex->desc?_("Could not parse PGP message"):_("Could not parse PGP message: Unknown error"));
+ if (ex->desc)
+ em_format_format_error(emf, stream, "%s", ex->desc);
+ em_format_format_source(emf, stream, ipart);
+ /* I think this will loop: em_format_part_as(emf, stream, part, "text/plain"); */
+ camel_exception_free(ex);
+ camel_object_unref(cipher);
+ camel_object_unref(opart);
+ return;
+ }
+
+ dw = camel_medium_get_content_object ((CamelMedium *)opart);
+ mime_type = camel_data_wrapper_get_mime_type (dw);
+
+ /* this ensures to show the 'opart' as inlined, if possible */
+ if (mime_type && g_ascii_strcasecmp (mime_type, "application/octet-stream") == 0) {
+ const char *snoop = em_format_snoop_type (opart);
+
+ if (snoop)
+ camel_data_wrapper_set_mime_type (dw, snoop);
+ }
+
+ g_free (mime_type);
+
+ /* Pass it off to the real formatter */
+ em_format_format_secure(emf, stream, opart, valid);
+
+ /* Clean Up */
+ camel_object_unref(opart);
+ camel_object_unref (cipher);
+ camel_exception_free (ex);
+}
+
+static EMFormatHandler type_builtin_table[] = {
+#ifdef ENABLE_SMIME
- { "application/x-pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
++ { (gchar *) "application/x-pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
+#endif
- { "multipart/alternative", emf_multipart_alternative },
- { "multipart/appledouble", emf_multipart_appledouble },
- { "multipart/encrypted", emf_multipart_encrypted },
- { "multipart/mixed", emf_multipart_mixed },
- { "multipart/signed", emf_multipart_signed },
- { "multipart/related", emf_multipart_related },
- { "multipart/*", emf_multipart_mixed },
- { "message/rfc822", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
- { "message/news", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
- { "message/delivery-status", emf_message_deliverystatus },
- { "message/*", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
++ { (gchar *) "multipart/alternative", emf_multipart_alternative },
++ { (gchar *) "multipart/appledouble", emf_multipart_appledouble },
++ { (gchar *) "multipart/encrypted", emf_multipart_encrypted },
++ { (gchar *) "multipart/mixed", emf_multipart_mixed },
++ { (gchar *) "multipart/signed", emf_multipart_signed },
++ { (gchar *) "multipart/related", emf_multipart_related },
++ { (gchar *) "multipart/*", emf_multipart_mixed },
++ { (gchar *) "message/rfc822", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
++ { (gchar *) "message/news", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
++ { (gchar *) "message/delivery-status", emf_message_deliverystatus },
++ { (gchar *) "message/*", emf_message_rfc822, EM_FORMAT_HANDLER_INLINE },
+
+ /* Insert brokenly-named parts here */
+#ifdef ENABLE_SMIME
- { "application/pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
++ { (gchar *) "application/pkcs7-mime", (EMFormatFunc)emf_application_xpkcs7mime, EM_FORMAT_HANDLER_INLINE_DISPOSITION },
+#endif
+
+ /* internal types */
- { "application/x-inlinepgp-signed", (EMFormatFunc)emf_inlinepgp_signed },
- { "application/x-inlinepgp-encrypted", (EMFormatFunc)emf_inlinepgp_encrypted },
++ { (gchar *) "application/x-inlinepgp-signed", (EMFormatFunc)emf_inlinepgp_signed },
++ { (gchar *) "application/x-inlinepgp-encrypted", (EMFormatFunc)emf_inlinepgp_encrypted },
+};
+
+static void
+emf_builtin_init(EMFormatClass *class)
+{
+ int i;
+
+ for (i=0;i<sizeof(type_builtin_table)/sizeof(type_builtin_table[0]);i++)
+ g_hash_table_insert(class->type_handlers, type_builtin_table[i].mime_type, &type_builtin_table[i]);
+}
+
+/**
+ * em_format_snoop_type:
+ * @part:
+ *
+ * Tries to snoop the mime type of a part.
+ *
+ * Return value: NULL if unknown (more likely application/octet-stream).
+ **/
+const char *
+em_format_snoop_type (CamelMimePart *part)
+{
+ /* cache is here only to be able still return const char * */
+ static GHashTable *types_cache = NULL;
+
+ const char *filename;
+ char *name_type = NULL, *magic_type = NULL, *res, *tmp;
+ CamelDataWrapper *dw;
+
+ filename = camel_mime_part_get_filename (part);
+ if (filename != NULL)
+ name_type = e_util_guess_mime_type (filename, FALSE);
+
+ dw = camel_medium_get_content_object((CamelMedium *)part);
+ if (!camel_data_wrapper_is_offline(dw)) {
+ CamelStreamMem *mem = (CamelStreamMem *)camel_stream_mem_new();
+
+ if (camel_data_wrapper_decode_to_stream(dw, (CamelStream *)mem) > 0) {
+ char *ct = g_content_type_guess (filename, mem->buffer->data, mem->buffer->len, NULL);
+
+ if (ct)
+ magic_type = g_content_type_get_mime_type (ct);
+
+ g_free (ct);
+ }
+ camel_object_unref(mem);
+ }
+
+ d(printf("snooped part, magic_type '%s' name_type '%s'\n", magic_type, name_type));
+
+ /* If gvfs doesn't recognize the data by magic, but it
+ * contains English words, it will call it text/plain. If the
+ * filename-based check came up with something different, use
+ * that instead and if it returns "application/octet-stream"
+ * try to do better with the filename check.
+ */
+
+ if (magic_type) {
+ if (name_type
+ && (!strcmp(magic_type, "text/plain")
+ || !strcmp(magic_type, "application/octet-stream")))
+ res = name_type;
+ else
+ res = magic_type;
+ } else
+ res = name_type;
+
+
+ if (res != name_type)
+ g_free (name_type);
+
+ if (res != magic_type)
+ g_free (magic_type);
+
+ if (!types_cache)
+ types_cache = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) NULL);
+
+ if (res) {
+ tmp = g_hash_table_lookup (types_cache, res);
+ if (tmp) {
+ g_free (res);
+ res = tmp;
+ } else {
+ g_hash_table_insert (types_cache, res, res);
+ }
+ }
+
+ return res;
+
+ /* We used to load parts to check their type, we dont anymore,
+ see bug #11778 for some discussion */
+}
diff --cc em-format/em-format.h
index 2817661,0000000..a9d9356
mode 100644,000000..100644
--- a/em-format/em-format.h
+++ b/em-format/em-format.h
@@@ -1,403 -1,0 +1,403 @@@
+/*
+ *
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Michael Zucchi <notzed ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/*
+ Abstract class for formatting mime messages
+*/
+
+#ifndef EM_FORMAT_H
+#define EM_FORMAT_H
+
+#include <glib-object.h>
+#include <camel/camel-url.h>
+#include <camel/camel-folder.h>
+#include <camel/camel-stream.h>
+#include <camel/camel-session.h>
+#include <camel/camel-mime-part.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-cipher-context.h>
+#include <libedataserver/e-msgport.h>
+
+/* Standard GObject macros */
+#define EM_TYPE_FORMAT \
+ (em_format_get_type ())
+#define EM_FORMAT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), EM_TYPE_FORMAT, EMFormat))
+#define EM_FORMAT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), EM_TYPE_FORMAT, EMFormatClass))
+#define EM_IS_FORMAT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), EM_TYPE_FORMAT))
+#define EM_IS_FORMAT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), EM_TYPE_FORMAT))
+#define EM_FORMAT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), EM_TYPE_FORMAT, EMFormatClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMFormat EMFormat;
+typedef struct _EMFormatClass EMFormatClass;
+typedef struct _EMFormatPrivate EMFormatPrivate;
+
+typedef struct _EMFormatHandler EMFormatHandler;
+typedef struct _EMFormatHeader EMFormatHeader;
+
+typedef void (*EMFormatFunc) (EMFormat *md, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info);
+
+typedef enum _em_format_mode_t {
+ EM_FORMAT_NORMAL,
+ EM_FORMAT_ALLHEADERS,
+ EM_FORMAT_SOURCE
+} em_format_mode_t;
+
+/**
+ * struct _EMFormatHandler - MIME type handler.
+ *
+ * @mime_type: Type this handler handles.
+ * @handler: The handler callback.
+ * @flags: Handling flags, see enum _em_format_handler_t.
+ * @old: The last handler set on this type. Allows overrides to
+ * fallback to previous implementation.
+ *
+ **/
+struct _EMFormatHandler {
- char *mime_type;
++ gchar *mime_type;
+ EMFormatFunc handler;
+ guint32 flags;
+
+ struct _EMFormatHandler *old;
+};
+
+/**
+ * enum _em_format_handler_t - Format handler flags.
+ *
+ * @EM_FORMAT_HANDLER_INLINE: This type should be shown expanded
+ * inline by default.
+ * @EM_FORMAT_HANDLER_INLINE_DISPOSITION: This type should always be
+ * shown inline, despite what the Content-Disposition suggests.
+ *
+ **/
+enum _em_format_handler_t {
+ EM_FORMAT_HANDLER_INLINE = 1<<0,
+ EM_FORMAT_HANDLER_INLINE_DISPOSITION = 1<<1
+};
+
+
+typedef struct _EMFormatPURI EMFormatPURI;
+typedef void (*EMFormatPURIFunc)(EMFormat *md, CamelStream *stream, EMFormatPURI *puri);
+
+/**
+ * struct _EMFormatPURI - Pending URI object.
+ *
+ * @next: Double-linked list header.
+ * @prev: Double-linked list header.
+ * @free: May be set by allocator and will be called when no longer needed.
+ * @format:
+ * @uri: Calculated URI of the part, if the part has one in its
+ * Content-Location field.
+ * @cid: The RFC2046 Content-Id of the part. If none is present, a unique value
+ * is calculated from @part_id.
+ * @part_id: A unique identifier for each part.
+ * @func: Callback for when the URI is requested. The callback writes
+ * its data to the supplied stream.
+ * @part:
+ * @use_count:
+ *
+ * This is used for multipart/related, and other formatters which may
+ * need to include a reference to out-of-band data in the content
+ * stream.
+ *
+ * This object may be subclassed as a struct.
+ **/
+struct _EMFormatPURI {
+ struct _EMFormatPURI *next;
+ struct _EMFormatPURI *prev;
+
+ void (*free)(struct _EMFormatPURI *p); /* optional callback for freeing user-fields */
+ struct _EMFormat *format;
+
+ char *uri; /* will be the location of the part, may be empty */
+ char *cid; /* will always be set, a fake one created if needed */
+ char *part_id; /* will always be set, emf->part_id->str for this part */
+
+ EMFormatPURIFunc func;
+ CamelMimePart *part;
+
+ unsigned int use_count; /* used by multipart/related to see if it was accessed */
+};
+
+/**
+ * struct _EMFormatPURITree - Pending URI visibility tree.
+ *
+ * @next: Double-linked list header.
+ * @prev: Double-linked list header.
+ * @parent: Parent in tree.
+ * @uri_list: List of EMFormatPURI objects at this level.
+ * @children: Child nodes of EMFormatPURITree.
+ *
+ * This structure is used internally to form a visibility tree of
+ * parts in the current formatting stream. This is to implement the
+ * part resolution rules for RFC2387 to implement multipart/related.
+ **/
+struct _EMFormatPURITree {
+ struct _EMFormatPURITree *next;
+ struct _EMFormatPURITree *prev;
+ struct _EMFormatPURITree *parent;
+
+ EDList uri_list;
+ EDList children;
+};
+
+struct _EMFormatHeader {
+ struct _EMFormatHeader *next, *prev;
+
+ guint32 flags; /* E_FORMAT_HEADER_* */
+ char name[1];
+};
+
+#define EM_FORMAT_HEADER_BOLD (1<<0)
+#define EM_FORMAT_HEADER_LAST (1<<4) /* reserve 4 slots */
+
+/**
+ * struct _EMFormat - Mail formatter object.
+ *
+ * @parent:
+ * @priv:
+ * @message:
+ * @folder:
+ * @uid:
+ * @part_id:
+ * @header_list:
+ * @session:
+ * @base url:
+ * @snoop_mime_type:
+ * @valid:
+ * @valid_parent:
+ * @inline_table:
+ * @pending_uri_table:
+ * @pending_uri_tree:
+ * @pending_uri_level:
+ * @mode:
+ * @charset:
+ * @default_charset:
+ *
+ * Most fields are private or read-only.
+ *
+ * This is the base MIME formatter class. It provides no formatting
+ * itself, but drives most of the basic types, including multipart / * types.
+ **/
+struct _EMFormat {
+ GObject parent;
+
+ EMFormatPrivate *priv;
+
+ CamelMimeMessage *message; /* the current message */
+
+ CamelFolder *folder;
+ char *uid;
+
+ GString *part_id; /* current part id prefix, for identifying parts directly */
+
+ EDList header_list; /* if empty, then all */
+
+ CamelSession *session; /* session, used for authentication when required */
+ CamelURL *base; /* content-base header or absolute content-location, for any part */
+
+ const char *snoop_mime_type; /* if we snooped an application/octet-stream type, what we snooped */
+
+ /* for validity enveloping */
+ CamelCipherValidity *valid;
+ CamelCipherValidity *valid_parent;
+
+ /* for forcing inlining */
+ GHashTable *inline_table;
+
+ /* global lookup table for message */
+ GHashTable *pending_uri_table;
+
+ /* visibility tree, also stores every puri permanently */
+ struct _EMFormatPURITree *pending_uri_tree;
+ /* current level to search from */
+ struct _EMFormatPURITree *pending_uri_level;
+
+ em_format_mode_t mode; /* source/headers/etc */
+ char *charset; /* charset override */
+ char *default_charset; /* charset fallback */
+ gboolean composer; /* Formatting from composer ?*/
+ gboolean print;
+};
+
+struct _EMFormatClass {
+ GObjectClass parent_class;
+
+ GHashTable *type_handlers;
+
+ /* lookup handler, default falls back to hashtable above */
+ const EMFormatHandler *(*find_handler)(EMFormat *, const char *mime_type);
+
+ /* start formatting a message */
+ void (*format_clone)(EMFormat *, CamelFolder *, const char *uid, CamelMimeMessage *, EMFormat *);
+
+ /* some internel error/inconsistency */
+ void (*format_error)(EMFormat *, CamelStream *, const char *msg);
+
+ /* use for external structured parts */
+ void (*format_attachment)(EMFormat *, CamelStream *, CamelMimePart *, const char *mime_type, const struct _EMFormatHandler *info);
+
+ /* use for unparsable content */
+ void (*format_source)(EMFormat *, CamelStream *, CamelMimePart *);
+ /* for outputing secure(d) content */
+ void (*format_secure)(EMFormat *, CamelStream *, CamelMimePart *, CamelCipherValidity *);
+
+ /* returns true if the formatter is still busy with pending stuff */
+ gboolean (*busy)(EMFormat *);
+
+ /* Shows optional way to open messages */
+ void (*format_optional)(EMFormat *, CamelStream *, CamelMimePart *, CamelStream* );
+
+ /* signals */
+ /* complete, alternative to polling busy, for asynchronous work */
+ void (*complete)(EMFormat *);
+};
+
+void em_format_set_mode (EMFormat *emf,
+ em_format_mode_t type);
+void em_format_set_charset (EMFormat *emf,
+ const char *charset);
+void em_format_set_default_charset (EMFormat *emf,
+ const char *charset);
+
+/* also indicates to show all headers */
+void em_format_clear_headers (EMFormat *emf);
+
+void em_format_default_headers (EMFormat *emf);
+void em_format_add_header (EMFormat *emf,
+ const gchar *name,
+ guint32 flags);
+
+/* FIXME: Need a 'clone' api to copy details about the current view (inlines etc)
+ Or maybe it should live with sub-classes? */
+
+int em_format_is_attachment (EMFormat *emf,
+ CamelMimePart *part);
+
+int em_format_is_inline (EMFormat *emf,
+ const char *partid,
+ CamelMimePart *part,
+ const EMFormatHandler *handle);
+void em_format_set_inline (EMFormat *emf,
+ const char *partid,
+ int state);
+
+char * em_format_describe_part (CamelMimePart *part,
+ const char *mime_type);
+
+/* for implementers */
+GType em_format_get_type (void);
+
+void em_format_class_add_handler (EMFormatClass *emfc,
+ EMFormatHandler *info);
+void em_format_class_remove_handler (EMFormatClass *emfc,
+ EMFormatHandler *info);
+const EMFormatHandler *
+ em_format_find_handler (EMFormat *emf,
+ const gchar *mime_type);
+const EMFormatHandler *
+ em_format_fallback_handler (EMFormat *emf,
+ const gchar *mime_type);
+
+/* puri is short for pending uri ... really */
+EMFormatPURI * em_format_add_puri (EMFormat *emf,
+ size_t size,
+ const char *uri,
+ CamelMimePart *part,
+ EMFormatPURIFunc func);
+EMFormatPURI * em_format_find_visible_puri (EMFormat *emf,
+ const char *uri);
+EMFormatPURI * em_format_find_puri (EMFormat *emf,
+ const char *uri);
+void em_format_clear_puri_tree (EMFormat *emf);
+void em_format_push_level (EMFormat *emf);
+void em_format_pull_level (EMFormat *emf);
+
+/* clones inline state/view and format, or use to redraw */
+void em_format_format_clone (EMFormat *emf,
+ CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ EMFormat *source);
+
+/* formats a new message */
+void em_format_format (EMFormat *emf,
+ CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message);
+void em_format_redraw (EMFormat *emf);
+void em_format_format_attachment (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part,
+ const gchar *mime_type,
+ const struct _EMFormatHandler *info);
+void em_format_format_error (EMFormat *emf,
+ CamelStream *stream,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (3, 4);
+void em_format_format_secure (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part,
+ CamelCipherValidity *valid);
+void em_format_format_source (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *mime_part);
+
+gboolean em_format_busy (EMFormat *emf);
+
+/* raw content only */
+void em_format_format_content (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *part);
+
+/* raw content text parts - should this just be checked/done by above? */
+void em_format_format_text (EMFormat *emf,
+ CamelStream *stream,
+ CamelDataWrapper *part);
+
+void em_format_part_as (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *part,
+ const gchar *mime_type);
+void em_format_part (EMFormat *emf,
+ CamelStream *stream,
+ CamelMimePart *part);
+void em_format_merge_handler (EMFormat *new,
+ EMFormat *old);
+
+const char * em_format_snoop_type (CamelMimePart *part);
+
+G_END_DECLS
+
+#endif /* EM_FORMAT_H */
diff --cc mail/Makefile.am
index 3df6164,e1b0da9..2544164
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@@ -4,10 -4,8 +4,9 @@@ mailincludedir = $(privincludedir)/mai
INCLUDES = \
-I$(top_srcdir)/widgets \
- -I$(top_srcdir)/widgets/e-text \
-I$(top_srcdir)/widgets/misc \
-I$(top_srcdir) \
+ -I$(top_srcdir)/em-format \
-I$(top_srcdir)/mail \
-I$(top_srcdir)/composer \
-I$(top_builddir)/composer \
diff --cc mail/e-mail-browser.c
index 152821b,0000000..e4013c5
mode 100644,000000..100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@@ -1,751 -1,0 +1,751 @@@
+/*
+ * e-mail-browser.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-browser.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <camel/camel-folder.h>
+
+#include "e-util/e-util.h"
+#include "e-util/gconf-bridge.h"
+#include "shell/e-shell.h"
+
+#include "mail/e-mail-reader.h"
+#include "mail/e-mail-reader-utils.h"
+#include "mail/e-mail-search-bar.h"
+#include "mail/e-mail-shell-backend.h"
+#include "mail/em-folder-tree-model.h"
+#include "mail/em-format-html-display.h"
+#include "mail/message-list.h"
+
+#define E_MAIL_BROWSER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_BROWSER, EMailBrowserPrivate))
+
+#define MAIL_BROWSER_GCONF_PREFIX "/apps/evolution/mail/mail_browser"
+
+struct _EMailBrowserPrivate {
+ GtkUIManager *ui_manager;
+ EShellBackend *shell_backend;
+ GtkActionGroup *action_group;
+ EMFormatHTMLDisplay *html_display;
+
+ GtkWidget *main_menu;
+ GtkWidget *main_toolbar;
+ GtkWidget *message_list;
+ GtkWidget *search_bar;
+ GtkWidget *statusbar;
+
+ guint show_deleted : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_SHELL_BACKEND,
+ PROP_SHOW_DELETED,
+ PROP_UI_MANAGER
+};
+
+static gpointer parent_class;
+
+/* This is too trivial to put in a file.
+ * It gets merged with the EMailReader UI. */
+static const gchar *ui =
+"<ui>"
+" <menubar name='main-menu'>"
+" <menu action='file-menu'>"
+" <placeholder name='file-actions'/>"
+" <placeholder name='print-actions'/>"
+" <separator/>"
+" <menuitem action='close'/>"
+" </menu>"
+" </menubar>"
+"</ui>";
+
+static void
+action_close_cb (GtkAction *action,
+ EMailBrowser *browser)
+{
+ e_mail_browser_close (browser);
+}
+
+static GtkActionEntry mail_browser_entries[] = {
+
+ { "close",
+ GTK_STOCK_CLOSE,
+ NULL,
+ NULL,
+ N_("Close this window"),
+ G_CALLBACK (action_close_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 void
+mail_browser_menu_item_select_cb (EMailBrowser *browser,
+ GtkWidget *menu_item)
+{
+ GtkAction *action;
+ GtkStatusbar *statusbar;
+ gchar *tooltip = NULL;
+ guint context_id;
+ gpointer data;
+
+ action = g_object_get_data (G_OBJECT (menu_item), "action");
+ g_return_if_fail (GTK_IS_ACTION (action));
+
+ data = g_object_get_data (G_OBJECT (menu_item), "context-id");
+ context_id = GPOINTER_TO_UINT (data);
+
+ g_object_get (action, "tooltip", &tooltip, NULL);
+
+ 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_full (
+ G_OBJECT (proxy),
+ "action", g_object_ref (action),
+ (GDestroyNotify) g_object_unref);
+
+ 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)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ CamelMessageInfo *info;
+ EMailReader *reader;
+
+ if (uid == NULL)
+ return;
+
+ reader = E_MAIL_READER (browser);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+ info = camel_folder_get_message_info (message_list->folder, uid);
+
+ if (info == NULL)
+ return;
+
+ gtk_window_set_title (
+ GTK_WINDOW (browser),
+ camel_message_info_subject (info));
+ gtk_widget_grab_focus (
+ GTK_WIDGET (((EMFormatHTML *) html_display)->html));
+
+ camel_folder_free_message_info (message_list->folder, info);
+}
+
+static void
+mail_browser_status_message_cb (EMailBrowser *browser,
+ const gchar *status_message)
+{
+ GtkStatusbar *statusbar;
+ guint context_id;
+
+ statusbar = GTK_STATUSBAR (browser->priv->statusbar);
+ context_id = gtk_statusbar_get_context_id (statusbar, G_STRFUNC);
+
+ /* Always pop first. This prevents messages from piling up. */
+ gtk_statusbar_pop (statusbar, context_id);
+
+ if (status_message != NULL && *status_message != '\0')
+ gtk_statusbar_push (statusbar, context_id, status_message);
+}
+
+static void
+mail_browser_set_shell_backend (EMailBrowser *browser,
+ EShellBackend *shell_backend)
+{
+ g_return_if_fail (browser->priv->shell_backend == NULL);
+
+ browser->priv->shell_backend = g_object_ref (shell_backend);
+}
+
+static void
+mail_browser_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SHELL_BACKEND:
+ mail_browser_set_shell_backend (
+ E_MAIL_BROWSER (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SHOW_DELETED:
+ e_mail_browser_set_show_deleted (
+ E_MAIL_BROWSER (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_browser_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SHELL_BACKEND:
+ g_value_set_object (
+ value, e_mail_reader_get_shell_backend (
+ E_MAIL_READER (object)));
+ return;
+
+ case PROP_SHOW_DELETED:
+ g_value_set_boolean (
+ value, e_mail_browser_get_show_deleted (
+ 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;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_browser_dispose (GObject *object)
+{
+ EMailBrowserPrivate *priv;
+
+ priv = E_MAIL_BROWSER_GET_PRIVATE (object);
+
+ if (priv->ui_manager != NULL) {
+ g_object_unref (priv->ui_manager);
+ priv->ui_manager = NULL;
+ }
+
+ if (priv->shell_backend != NULL) {
+ g_object_unref (priv->shell_backend);
+ priv->shell_backend = NULL;
+ }
+
+ if (priv->action_group != NULL) {
+ g_object_unref (priv->action_group);
+ priv->action_group = NULL;
+ }
+
+ if (priv->html_display != NULL) {
+ g_object_unref (priv->html_display);
+ priv->html_display = NULL;
+ }
+
+ if (priv->main_menu != NULL) {
+ g_object_unref (priv->main_menu);
+ priv->main_menu = NULL;
+ }
+
+ if (priv->main_toolbar != NULL) {
+ g_object_unref (priv->main_toolbar);
+ priv->main_toolbar = NULL;
+ }
+
+ if (priv->message_list != NULL) {
+ g_object_unref (priv->message_list);
+ priv->message_list = NULL;
+ }
+
+ if (priv->search_bar != NULL) {
+ g_object_unref (priv->search_bar);
+ priv->search_bar = NULL;
+ }
+
+ if (priv->statusbar != NULL) {
+ g_object_unref (priv->statusbar);
+ priv->statusbar = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_browser_constructed (GObject *object)
+{
+ EMFormatHTMLDisplay *html_display;
+ EMailBrowserPrivate *priv;
+ EMailReader *reader;
+ EShellBackend *shell_backend;
+ EShell *shell;
+ GConfBridge *bridge;
+ GtkAccelGroup *accel_group;
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
+ GtkWidget *container;
+ GtkWidget *widget;
+ GtkHTML *html;
+ const gchar *domain;
+ const gchar *key;
+ guint merge_id;
+
+ priv = E_MAIL_BROWSER_GET_PRIVATE (object);
+
+ reader = E_MAIL_READER (object);
+ ui_manager = priv->ui_manager;
+ domain = GETTEXT_PACKAGE;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ e_shell_watch_window (shell, GTK_WINDOW (object));
+
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ /* The message list is a widget, but it is not shown in the browser.
+ * Unfortunately, the widget is inseparable from its model, and the
+ * model is all we need. */
+ priv->message_list = message_list_new (shell_backend);
+ g_object_ref_sink (priv->message_list);
+
+ g_signal_connect_swapped (
+ priv->message_list, "message-selected",
+ G_CALLBACK (mail_browser_message_selected_cb), object);
+
+ g_signal_connect_swapped (
+ html, "status-message",
+ G_CALLBACK (mail_browser_status_message_cb), object);
+
+ e_mail_reader_init (reader);
+
+ action_group = priv->action_group;
+ 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);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+
+ e_load_ui_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);
+
+ /* Construct window widgets. */
+
+ widget = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (object), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ /* Create the status bar before connecting proxy widgets. */
+ widget = gtk_statusbar_new ();
+ gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->statusbar = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = e_mail_search_bar_new (EM_FORMAT_HTML (html_display)->html);
+ gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->search_bar = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ g_signal_connect_swapped (
+ widget, "changed",
+ G_CALLBACK (em_format_redraw), html_display);
+
+ widget = gtk_ui_manager_get_widget (ui_manager, "/main-menu");
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->main_menu = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_ui_manager_get_widget (ui_manager, "/main-toolbar");
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->main_toolbar = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = GTK_WIDGET (EM_FORMAT_HTML (html_display)->html);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (reader);
+ key = "/apps/evolution/mail/display/show_deleted";
+ gconf_bridge_bind_property (bridge, key, object, "show-deleted");
+}
+
+static gboolean
+mail_browser_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ if (event->keyval == GDK_Escape) {
+ e_mail_browser_close (E_MAIL_BROWSER (widget));
+ return TRUE;
+ }
+
+ /* Chain up to parent's key_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ key_press_event (widget, event);
+}
+
+static GtkActionGroup *
+mail_browser_get_action_group (EMailReader *reader)
+{
+ EMailBrowserPrivate *priv;
+
+ priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
+
+ return priv->action_group;
+}
+
+static gboolean
+mail_browser_get_hide_deleted (EMailReader *reader)
+{
+ EMailBrowser *browser;
+
+ browser = E_MAIL_BROWSER (reader);
+
+ return !e_mail_browser_get_show_deleted (browser);
+}
+
+static EMFormatHTMLDisplay *
+mail_browser_get_html_display (EMailReader *reader)
+{
+ EMailBrowserPrivate *priv;
+
+ priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
+
+ return priv->html_display;
+}
+
+static MessageList *
+mail_browser_get_message_list (EMailReader *reader)
+{
+ EMailBrowserPrivate *priv;
+
+ priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
+
+ return MESSAGE_LIST (priv->message_list);
+}
+
+static EShellBackend *
+mail_browser_get_shell_backend (EMailReader *reader)
+{
+ EMailBrowserPrivate *priv;
+
+ priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
+
+ return priv->shell_backend;
+}
+
+static GtkWindow *
+mail_browser_get_window (EMailReader *reader)
+{
+ return GTK_WINDOW (reader);
+}
+
+static void
+mail_browser_set_message (EMailReader *reader,
+ const gchar *uid,
+ gboolean mark_read)
+{
+ EMailReaderIface *iface;
+ MessageList *message_list;
+ CamelMessageInfo *info;
+ CamelFolder *folder;
+
+ /* Chain up to parent's set_message() method. */
+ iface = g_type_default_interface_peek (E_TYPE_MAIL_READER);
+ iface->set_message (reader, uid, mark_read);
+
+ if (uid == NULL) {
+ e_mail_browser_close (E_MAIL_BROWSER (reader));
+ return;
+ }
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ info = camel_folder_get_message_info (folder, uid);
+
+ if (info != NULL) {
+ gtk_window_set_title (
+ GTK_WINDOW (reader),
+ camel_message_info_subject (info));
+ camel_folder_free_message_info (folder, info);
+ }
+
+ if (mark_read)
+ e_mail_reader_mark_as_read (reader, uid);
+}
+
+static void
+mail_browser_show_search_bar (EMailReader *reader)
+{
+ EMailBrowserPrivate *priv;
+
+ priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
+
+ gtk_widget_show (priv->search_bar);
+}
+
+static void
+mail_browser_class_init (EMailBrowserClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailBrowserPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_browser_set_property;
+ object_class->get_property = mail_browser_get_property;
+ object_class->dispose = mail_browser_dispose;
+ object_class->constructed = mail_browser_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->key_press_event = mail_browser_key_press_event;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHELL_BACKEND,
+ g_param_spec_object (
+ "shell-backend",
+ _("Shell Module"),
+ _("The mail shell backend"),
+ E_TYPE_SHELL_BACKEND,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_DELETED,
+ g_param_spec_boolean (
+ "show-deleted",
+ _("Show Deleted"),
+ _("Show deleted messages"),
+ FALSE,
+ G_PARAM_READWRITE));
+}
+
+static void
+mail_browser_iface_init (EMailReaderIface *iface)
+{
+ iface->get_action_group = mail_browser_get_action_group;
+ iface->get_hide_deleted = mail_browser_get_hide_deleted;
+ iface->get_html_display = mail_browser_get_html_display;
+ iface->get_message_list = mail_browser_get_message_list;
+ iface->get_shell_backend = mail_browser_get_shell_backend;
+ iface->get_window = mail_browser_get_window;
+ iface->set_message = mail_browser_set_message;
+ iface->show_search_bar = mail_browser_show_search_bar;
+}
+
+static void
+mail_browser_init (EMailBrowser *browser)
+{
+ GConfBridge *bridge;
+ const gchar *prefix;
+
+ browser->priv = E_MAIL_BROWSER_GET_PRIVATE (browser);
+
+ browser->priv->ui_manager = gtk_ui_manager_new ();
+ browser->priv->action_group = gtk_action_group_new ("mail-browser");
+ browser->priv->html_display = em_format_html_display_new ();
+
+ bridge = gconf_bridge_get ();
+ prefix = "/apps/evolution/mail/mail_browser";
+ gconf_bridge_bind_window_size (bridge, prefix, GTK_WINDOW (browser));
+
+ gtk_window_set_title (GTK_WINDOW (browser), _("Evolution"));
+}
+
+GType
+e_mail_browser_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailBrowserClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_browser_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailBrowser),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_browser_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) mail_browser_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_WINDOW, "EMailBrowser", &type_info, 0);
+
+ g_type_add_interface_static (
+ type, E_TYPE_MAIL_READER, &iface_info);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_mail_browser_new (EMailShellBackend *mail_shell_backend)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_BROWSER,
+ "shell-backend", mail_shell_backend, NULL);
+}
+
+void
+e_mail_browser_close (EMailBrowser *browser)
+{
+ g_return_if_fail (E_IS_MAIL_BROWSER (browser));
+
+ gtk_widget_destroy (GTK_WIDGET (browser));
+}
+
+gboolean
+e_mail_browser_get_show_deleted (EMailBrowser *browser)
+{
+ g_return_val_if_fail (E_IS_MAIL_BROWSER (browser), FALSE);
+
+ return browser->priv->show_deleted;
+}
+
+void
+e_mail_browser_set_show_deleted (EMailBrowser *browser,
+ gboolean show_deleted)
+{
+ g_return_if_fail (E_IS_MAIL_BROWSER (browser));
+
+ browser->priv->show_deleted = show_deleted;
+
+ g_object_notify (G_OBJECT (browser), "show-deleted");
+}
+
+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;
+}
diff --cc mail/e-mail-browser.h
index b67ea9a,0000000..2605b2e
mode 100644,000000..100644
--- a/mail/e-mail-browser.h
+++ b/mail/e-mail-browser.h
@@@ -1,72 -1,0 +1,72 @@@
+/*
+ * e-mail-browser.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_BROWSER_H
+#define E_MAIL_BROWSER_H
+
+#include <gtk/gtk.h>
+#include <mail/e-mail-shell-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_BROWSER \
+ (e_mail_browser_get_type ())
+#define E_MAIL_BROWSER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_BROWSER, EMailBrowser))
+#define E_MAIL_BROWSER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_BROWSER, EMailBrowserClass))
+#define E_IS_MAIL_BROWSER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_BROWSER))
+#define E_IS_MAIL_BROWSER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_BROWSER))
+#define E_MAIL_BROWSER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_BROWSER, EMailBrowserClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailBrowser EMailBrowser;
+typedef struct _EMailBrowserClass EMailBrowserClass;
+typedef struct _EMailBrowserPrivate EMailBrowserPrivate;
+
+struct _EMailBrowser {
+ GtkWindow parent;
+ EMailBrowserPrivate *priv;
+};
+
+struct _EMailBrowserClass {
+ GtkWindowClass parent_class;
+};
+
+GType e_mail_browser_get_type (void);
+GtkWidget * e_mail_browser_new (EMailShellBackend *mail_shell_backend);
+void e_mail_browser_close (EMailBrowser *browser);
+gboolean e_mail_browser_get_show_deleted (EMailBrowser *browser);
+void e_mail_browser_set_show_deleted (EMailBrowser *browser,
+ gboolean show_deleted);
+GtkUIManager * e_mail_browser_get_ui_manager (EMailBrowser *browser);
+
+G_END_DECLS
+
+#endif /* E_MAIL_BROWSER_H */
diff --cc mail/e-mail-display.c
index f649393,0000000..9507330
mode 100644,000000..100644
--- a/mail/e-mail-display.c
+++ b/mail/e-mail-display.c
@@@ -1,627 -1,0 +1,627 @@@
+/*
+ * e-mail-display.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-display.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+
+#define E_MAIL_DISPLAY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayPrivate))
+
+struct _EMailDisplayPrivate {
+ EMFormatHTML *formatter;
+};
+
+enum {
+ PROP_0,
+ PROP_ANIMATE,
+ PROP_CARET_MODE,
+ PROP_FORMATTER
+};
+
+enum {
+ POPUP_EVENT,
+ STATUS_MESSAGE,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static gboolean
+mail_display_emit_popup_event (EMailDisplay *display,
+ GdkEventButton *event,
+ const gchar *uri,
+ EMFormatPURI *puri)
+{
+ CamelMimePart *mime_part;
+ gboolean stop_handlers = FALSE;
+
+ mime_part = (puri != NULL) ? puri->part : NULL;
+
+ g_signal_emit (
+ display, signals[POPUP_EVENT], 0,
+ event, uri, mime_part, &stop_handlers);
+
+ return stop_handlers;
+}
+
+static void
+mail_display_emit_status_message (EMailDisplay *display,
+ const gchar *status_message)
+{
+ g_signal_emit (display, signals[STATUS_MESSAGE], 0, status_message);
+}
+
+static void
+mail_display_get_uri_puri (EMailDisplay *display,
+ GdkEventButton *event,
+ gchar **uri,
+ EMFormatPURI **puri)
+{
+ EMFormat *formatter;
+ GtkHTML *html;
+ gchar *text_uri;
+ gchar *image_uri;
+ gboolean is_cid;
+
+ html = GTK_HTML (display);
+ formatter = EM_FORMAT (display->priv->formatter);
+
+ if (event != NULL) {
+ text_uri = gtk_html_get_url_at (html, event->x, event->y);
+ image_uri = gtk_html_get_image_src_at (html, event->x, event->y);
+ } else {
+ text_uri = gtk_html_get_cursor_url (html);
+ image_uri = gtk_html_get_cursor_image_src (html);
+ }
+
+ is_cid = (image_uri != NULL) &&
+ (g_ascii_strncasecmp (image_uri, "cid:", 4) == 0);
+
+ if (image_uri != NULL) {
+ if (strstr (image_uri, "://") == NULL && !is_cid) {
+ gchar *temp;
+
+ temp = g_strconcat ("file://", image_uri, NULL);
+ g_free (image_uri);
+ temp = image_uri;
+ }
+ }
+
+ if (puri != NULL) {
+ if (text_uri != NULL)
+ *puri = em_format_find_puri (formatter, text_uri);
+
+ if (*puri == NULL && image_uri != NULL)
+ *puri = em_format_find_puri (formatter, image_uri);
+ }
+
+ if (uri != NULL) {
+ *uri = NULL;
+ if (is_cid) {
+ if (text_uri != NULL)
+ *uri = g_strdup_printf (
+ "%s\n%s", text_uri, image_uri);
+ else {
+ *uri = image_uri;
+ image_uri = NULL;
+ }
+ } else {
+ *uri = text_uri;
+ text_uri = NULL;
+ }
+ }
+
+ g_free (text_uri);
+ g_free (image_uri);
+}
+
+static void
+mail_display_update_formatter_colors (EMailDisplay *display)
+{
+ EMFormatHTMLColorType type;
+ EMFormatHTML *formatter;
+ GdkColor *color;
+ GtkStyle *style;
+ gint state;
+
+ state = GTK_WIDGET_STATE (display);
+ formatter = display->priv->formatter;
+
+ style = gtk_widget_get_style (GTK_WIDGET (display));
+ if (style == NULL)
+ return;
+
+ g_object_freeze_notify (G_OBJECT (formatter));
+
+ color = &style->bg[state];
+ type = EM_FORMAT_HTML_COLOR_BODY;
+ em_format_html_set_color (formatter, type, color);
+
+ color = &style->base[GTK_STATE_NORMAL];
+ type = EM_FORMAT_HTML_COLOR_CONTENT;
+ em_format_html_set_color (formatter, type, color);
+
+ color = &style->dark[state];
+ type = EM_FORMAT_HTML_COLOR_FRAME;
+ em_format_html_set_color (formatter, type, color);
+
+ color = &style->fg[state];
+ type = EM_FORMAT_HTML_COLOR_HEADER;
+ em_format_html_set_color (formatter, type, color);
+
+ color = &style->text[state];
+ type = EM_FORMAT_HTML_COLOR_TEXT;
+ em_format_html_set_color (formatter, type, color);
+
+ g_object_thaw_notify (G_OBJECT (formatter));
+}
+
+static void
+mail_display_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ANIMATE:
+ e_mail_display_set_animate (
+ E_MAIL_DISPLAY (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_CARET_MODE:
+ e_mail_display_set_caret_mode (
+ E_MAIL_DISPLAY (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_FORMATTER:
+ e_mail_display_set_formatter (
+ E_MAIL_DISPLAY (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_display_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ANIMATE:
+ g_value_set_boolean (
+ value, e_mail_display_get_animate (
+ E_MAIL_DISPLAY (object)));
+ return;
+
+ case PROP_CARET_MODE:
+ g_value_set_boolean (
+ value, e_mail_display_get_caret_mode (
+ E_MAIL_DISPLAY (object)));
+ return;
+
+ case PROP_FORMATTER:
+ g_value_set_object (
+ value, e_mail_display_get_formatter (
+ E_MAIL_DISPLAY (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_display_dispose (GObject *object)
+{
+ EMailDisplayPrivate *priv;
+
+ priv = E_MAIL_DISPLAY_GET_PRIVATE (object);
+
+ if (priv->formatter) {
+ g_object_unref (priv->formatter);
+ priv->formatter = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_display_realize (GtkWidget *widget)
+{
+ /* Chain up to parent's realize() method. */
+ GTK_WIDGET_CLASS (parent_class)->realize (widget);
+
+ mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
+}
+
+static void
+mail_display_style_set (GtkWidget *widget,
+ GtkStyle *previous_style)
+{
+ EMailDisplayPrivate *priv;
+
+ priv = E_MAIL_DISPLAY_GET_PRIVATE (widget);
+
+ /* Chain up to parent's style_set() method. */
+ GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
+
+ mail_display_update_formatter_colors (E_MAIL_DISPLAY (widget));
+ em_format_redraw (EM_FORMAT (priv->formatter));
+}
+
+static gboolean
+mail_display_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ if (event->button == 3) {
+ EMailDisplay *display;
+ EMFormatPURI *puri = NULL;
+ gboolean stop_handlers = TRUE;
+ gchar *uri = NULL;
+
+ display = E_MAIL_DISPLAY (widget);
+ mail_display_get_uri_puri (display, event, &uri, &puri);
+
+ if (uri == NULL || !g_str_has_prefix (uri, "##"))
+ stop_handlers = mail_display_emit_popup_event (
+ display, event, uri, puri);
+
+ g_free (uri);
+
+ if (stop_handlers)
+ return TRUE;
+ }
+
+ /* Chain up to parent's button_press_event() method. */
+ return GTK_WIDGET_CLASS (parent_class)->
+ button_press_event (widget, event);
+}
+
+static gboolean
+mail_display_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event)
+{
+ if (event->state & GDK_CONTROL_MASK) {
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ gtk_html_zoom_in (GTK_HTML (widget));
+ return TRUE;
+ case GDK_SCROLL_DOWN:
+ gtk_html_zoom_out (GTK_HTML (widget));
+ return TRUE;
+ default:
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+mail_display_link_clicked (GtkHTML *html,
+ const gchar *uri)
+{
+ EMailDisplayPrivate *priv;
+
+ priv = E_MAIL_DISPLAY_GET_PRIVATE (html);
+ g_return_if_fail (priv->formatter != NULL);
+
+ if (g_str_has_prefix (uri, "##")) {
+ guint32 flags;
+
+ flags = priv->formatter->header_wrap_flags;
+
+ if (strcmp (uri, "##TO##") == 0) {
+ if (!(flags & EM_FORMAT_HTML_HEADER_TO))
+ flags |= EM_FORMAT_HTML_HEADER_TO;
+ else
+ flags &= ~EM_FORMAT_HTML_HEADER_TO;
+ } else if (strcmp (uri, "##CC##") == 0) {
+ if (!(flags & EM_FORMAT_HTML_HEADER_CC))
+ flags |= EM_FORMAT_HTML_HEADER_CC;
+ else
+ flags |= EM_FORMAT_HTML_HEADER_CC;
+ } else if (strcmp (uri, "##BCC##") == 0) {
+ if (!(flags & EM_FORMAT_HTML_HEADER_BCC))
+ flags |= EM_FORMAT_HTML_HEADER_BCC;
+ else
+ flags |= EM_FORMAT_HTML_HEADER_BCC;
+ }
+
+ priv->formatter->header_wrap_flags = flags;
+ em_format_redraw (EM_FORMAT (priv->formatter));
+
+ } else if (*uri == '#')
+ gtk_html_jump_to_anchor (html, uri + 1);
+
+ else if (g_ascii_strncasecmp (uri, "thismessage:", 12) == 0)
+ /* ignore */ ;
+
+ else if (g_ascii_strncasecmp (uri, "cid:", 4) == 0)
+ /* ignore */ ;
+
+ else {
+ gpointer parent;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (html));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ e_show_uri (parent, uri);
+ }
+}
+
+static void
+mail_display_on_url (GtkHTML *html,
+ const gchar *uri)
+{
+ EMailDisplay *display;
+ CamelInternetAddress *address;
+ CamelURL *curl;
+ const gchar *format = NULL;
+ gchar *message = NULL;
+ gchar *who;
+
+ display = E_MAIL_DISPLAY (html);
+
+ if (uri == NULL || *uri == '\0')
+ goto exit;
+
+ if (g_str_has_prefix (uri, "mailto:"))
+ format = _("Click to mail %s");
+ else if (g_str_has_prefix (uri, "callto:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "h323:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "sip:"))
+ format = _("Click to call %s");
+ else if (g_str_has_prefix (uri, "##"))
+ message = g_strdup (_("Click to hide/unhide addresses"));
+ else
+ message = g_strdup_printf (_("Click to open %s"), uri);
+
+ if (format == NULL)
+ goto exit;
+
+ curl = camel_url_new (uri, NULL);
+ address = camel_internet_address_new ();
+ camel_address_decode (CAMEL_ADDRESS (address), curl->path);
+ who = camel_address_format (CAMEL_ADDRESS (address));
+ camel_object_unref (address);
+ camel_url_free (curl);
+
+ if (who == NULL)
+ who = g_strdup (strchr (uri, ':') + 1);
+
+ message = g_strdup_printf (format, who);
+
+ g_free (who);
+
+exit:
+ mail_display_emit_status_message (display, message);
+
+ g_free (message);
+}
+
+static void
+mail_display_iframe_created (GtkHTML *html,
+ GtkHTML *iframe)
+{
+ g_signal_connect_swapped (
+ iframe, "button-press-event",
+ G_CALLBACK (mail_display_button_press_event), html);
+}
+
+static void
+mail_display_class_init (EMailDisplayClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkHTMLClass *html_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailDisplayPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_display_set_property;
+ object_class->get_property = mail_display_get_property;
+ object_class->dispose = mail_display_dispose;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->realize = mail_display_realize;
+ widget_class->style_set = mail_display_style_set;
+ widget_class->button_press_event = mail_display_button_press_event;
+ widget_class->scroll_event = mail_display_scroll_event;
+
+ html_class = GTK_HTML_CLASS (class);
+ html_class->link_clicked = mail_display_link_clicked;
+ html_class->on_url = mail_display_on_url;
+ html_class->iframe_created = mail_display_iframe_created;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ANIMATE,
+ g_param_spec_boolean (
+ "animate",
+ "Animate Images",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CARET_MODE,
+ g_param_spec_boolean (
+ "caret-mode",
+ "Caret Mode",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FORMATTER,
+ g_param_spec_object (
+ "formatter",
+ "HTML Formatter",
+ NULL,
+ EM_TYPE_FORMAT_HTML,
+ G_PARAM_READWRITE));
+
+ signals[POPUP_EVENT] = g_signal_new (
+ "popup-event",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EMailDisplayClass, popup_event),
+ g_signal_accumulator_true_handled, NULL,
+ e_marshal_BOOLEAN__BOXED_POINTER_POINTER,
+ G_TYPE_BOOLEAN, 3,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER);
+
+ signals[STATUS_MESSAGE] = g_signal_new (
+ "status-message",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EMailDisplayClass, status_message),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
+
+static void
+mail_display_init (EMailDisplay *display)
+{
+ display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display);
+}
+
+GType
+e_mail_display_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailDisplayClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_display_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailDisplay),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_display_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_HTML, "EMailDisplay", &type_info, 0);
+ }
+
+ return type;
+}
+
+gboolean
+e_mail_display_get_animate (EMailDisplay *display)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_mail_display_set_animate(). */
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+ return gtk_html_get_animate (GTK_HTML (display));
+}
+
+void
+e_mail_display_set_animate (EMailDisplay *display,
+ gboolean animate)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_animate()
+ * so we can get a "notify::animate" signal. */
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ gtk_html_set_animate (GTK_HTML (display), animate);
+
+ g_object_notify (G_OBJECT (display), "animate");
+}
+
+gboolean
+e_mail_display_get_caret_mode (EMailDisplay *display)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_mail_display_set_caret_mode(). */
+
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE);
+
+ return gtk_html_get_caret_mode (GTK_HTML (display));
+}
+
+void
+e_mail_display_set_caret_mode (EMailDisplay *display,
+ gboolean caret_mode)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_caret_mode()
+ * so we can get a "notify::caret-mode" signal. */
+
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+
+ gtk_html_set_caret_mode (GTK_HTML (display), caret_mode);
+
+ g_object_notify (G_OBJECT (display), "caret-mode");
+}
+
+EMFormatHTML *
+e_mail_display_get_formatter (EMailDisplay *display)
+{
+ g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+ return display->priv->formatter;
+}
+
+void
+e_mail_display_set_formatter (EMailDisplay *display,
+ EMFormatHTML *formatter)
+{
+ g_return_if_fail (E_IS_MAIL_DISPLAY (display));
+ g_return_if_fail (EM_IS_FORMAT_HTML (formatter));
+
+ if (display->priv->formatter != NULL)
+ g_object_unref (display->priv->formatter);
+
+ display->priv->formatter = g_object_ref (formatter);
+
+ g_object_notify (G_OBJECT (display), "formatter");
+}
diff --cc mail/e-mail-display.h
index f1d5fc5,0000000..815fd45
mode 100644,000000..100644
--- a/mail/e-mail-display.h
+++ b/mail/e-mail-display.h
@@@ -1,83 -1,0 +1,83 @@@
+/*
+ * e-mail-display.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_DISPLAY_H
+#define E_MAIL_DISPLAY_H
+
+#include <gtkhtml/gtkhtml.h>
+#include <mail/em-format-html.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_DISPLAY \
+ (e_mail_display_get_type ())
+#define E_MAIL_DISPLAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplay))
+#define E_MAIL_DISPLAY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_DISPLAY, EMailDisplayClass))
+#define E_IS_MAIL_DISPLAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_DISPLAY))
+#define E_IS_MAIL_DISPLAY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_DISPLAY))
+#define E_MAIL_DISPLAY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_DISPLAY, EMailDisplayClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailDisplay EMailDisplay;
+typedef struct _EMailDisplayClass EMailDisplayClass;
+typedef struct _EMailDisplayPrivate EMailDisplayPrivate;
+
+struct _EMailDisplay {
+ GtkHTML parent;
+ EMailDisplayPrivate *priv;
+};
+
+struct _EMailDisplayClass {
+ GtkHTMLClass parent_class;
+
+ /* Signals */
+ gboolean (*popup_event) (EMailDisplay *display,
+ GdkEventButton *event,
+ const gchar *uri,
+ EMFormatPURI *puri);
+ void (*status_message) (EMailDisplay *display,
+ const gchar *status_message);
+};
+
+GType e_mail_display_get_type (void);
+gboolean e_mail_display_get_animate (EMailDisplay *display);
+void e_mail_display_set_animate (EMailDisplay *display,
+ gboolean animate);
+gboolean e_mail_display_get_caret_mode (EMailDisplay *display);
+void e_mail_display_set_caret_mode (EMailDisplay *display,
+ gboolean caret_mode);
+EMFormatHTML * e_mail_display_get_formatter (EMailDisplay *display);
+void e_mail_display_set_formatter (EMailDisplay *display,
+ EMFormatHTML *formatter);
+
+G_END_DECLS
+
+#endif /* E_MAIL_DISPLAY_H */
diff --cc mail/e-mail-label-dialog.c
index 23b5068,0000000..bebe0e6
mode 100644,000000..100644
--- a/mail/e-mail-label-dialog.c
+++ b/mail/e-mail-label-dialog.c
@@@ -1,323 -1,0 +1,323 @@@
+/*
+ * e-mail-label-dialog.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-label-dialog.h"
+
+#include <glib/gi18n.h>
+
+#define E_MAIL_LABEL_DIALOG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_LABEL_DIALOG, EMailLabelDialogPrivate))
+
+struct _EMailLabelDialogPrivate {
+ GtkWidget *entry;
+ GtkWidget *colorsel;
+};
+
+enum {
+ PROP_0,
+ PROP_LABEL_COLOR,
+ PROP_LABEL_NAME
+};
+
+static gpointer parent_class;
+
+static void
+mail_label_dialog_entry_changed_cb (EMailLabelDialog *dialog)
+{
+ const gchar *text;
+ gboolean sensitive;
+
+ text = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry));
+ sensitive = (text != NULL && *text != '\0');
+
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
+}
+
+static void
+mail_label_dialog_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_LABEL_COLOR:
+ e_mail_label_dialog_set_label_color (
+ E_MAIL_LABEL_DIALOG (object),
+ g_value_get_boxed (value));
+ return;
+
+ case PROP_LABEL_NAME:
+ e_mail_label_dialog_set_label_name (
+ E_MAIL_LABEL_DIALOG (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_label_dialog_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkColor color;
+
+ switch (property_id) {
+ case PROP_LABEL_COLOR:
+ e_mail_label_dialog_get_label_color (
+ E_MAIL_LABEL_DIALOG (object), &color);
+ g_value_set_boxed (value, &color);
+ return;
+
+ case PROP_LABEL_NAME:
+ g_value_set_string (
+ value, e_mail_label_dialog_get_label_name (
+ E_MAIL_LABEL_DIALOG (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_label_dialog_dispose (GObject *object)
+{
+ EMailLabelDialogPrivate *priv;
+
+ priv = E_MAIL_LABEL_DIALOG_GET_PRIVATE (object);
+
+ if (priv->entry != NULL) {
+ g_object_unref (priv->entry);
+ priv->entry = NULL;
+ }
+
+ if (priv->colorsel != NULL) {
+ g_object_unref (priv->colorsel);
+ priv->colorsel = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_label_dialog_constructed (GObject *object)
+{
+ GtkWidget *action_area;
+ GtkWidget *content_area;
+
+ /* XXX Override GTK's style property defaults for GtkDialog.
+ * Hopefully GTK+ 3.0 will fix the broken defaults. */
+
+ action_area = gtk_dialog_get_action_area (GTK_DIALOG (object));
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (object));
+
+ gtk_box_set_spacing (GTK_BOX (content_area), 12);
+ gtk_container_set_border_width (GTK_CONTAINER (object), 12);
+ gtk_container_set_border_width (GTK_CONTAINER (action_area), 0);
+ gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);
+}
+
+static void
+mail_label_dialog_class_init (EMailLabelDialogClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailLabelDialogPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_label_dialog_set_property;
+ object_class->get_property = mail_label_dialog_get_property;
+ object_class->dispose = mail_label_dialog_dispose;
+ object_class->constructed = mail_label_dialog_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_LABEL_COLOR,
+ g_param_spec_boxed (
+ "label-color",
+ "Label Color",
+ NULL,
+ GDK_TYPE_COLOR,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_LABEL_NAME,
+ g_param_spec_string (
+ "label-name",
+ "Label Name",
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+}
+
+static void
+mail_label_dialog_init (EMailLabelDialog *dialog)
+{
+ GtkWidget *content_area;
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ dialog->priv = E_MAIL_LABEL_DIALOG_GET_PRIVATE (dialog);
+
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ gtk_dialog_add_button (
+ GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+ gtk_dialog_add_button (
+ GTK_DIALOG (dialog),
+ GTK_STOCK_OK, GTK_RESPONSE_OK);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ container = content_area;
+
+ widget = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_entry_new ();
+ gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+ gtk_box_pack_end (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ dialog->priv->entry = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "changed",
+ G_CALLBACK (mail_label_dialog_entry_changed_cb), dialog);
+
+ mail_label_dialog_entry_changed_cb (dialog);
+
+ widget = gtk_label_new_with_mnemonic (_("_Label name:"));
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (widget), dialog->priv->entry);
+ gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ container = content_area;
+
+ widget = gtk_color_selection_new ();
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ dialog->priv->colorsel = g_object_ref (widget);
+ gtk_widget_show (widget);
+}
+
+GType
+e_mail_label_dialog_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailLabelDialogClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_label_dialog_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailLabelDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_label_dialog_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_DIALOG, "EMailLabelDialog", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_mail_label_dialog_new (GtkWindow *parent)
+{
+ return g_object_new (
+ E_TYPE_MAIL_LABEL_DIALOG,
+ "transient-for", parent, NULL);
+}
+
+const gchar *
+e_mail_label_dialog_get_label_name (EMailLabelDialog *dialog)
+{
+ GtkEntry *entry;
+
+ g_return_val_if_fail (E_IS_MAIL_LABEL_DIALOG (dialog), NULL);
+
+ entry = GTK_ENTRY (dialog->priv->entry);
+
+ return gtk_entry_get_text (entry);
+}
+
+void
+e_mail_label_dialog_set_label_name (EMailLabelDialog *dialog,
+ const gchar *label_name)
+{
+ GtkEntry *entry;
+
+ g_return_if_fail (E_IS_MAIL_LABEL_DIALOG (dialog));
+
+ entry = GTK_ENTRY (dialog->priv->entry);
+
+ gtk_entry_set_text (entry, label_name);
+
+ g_object_notify (G_OBJECT (dialog), "label-name");
+}
+
+void
+e_mail_label_dialog_get_label_color (EMailLabelDialog *dialog,
+ GdkColor *label_color)
+{
+ GtkColorSelection *colorsel;
+
+ g_return_if_fail (E_IS_MAIL_LABEL_DIALOG (dialog));
+ g_return_if_fail (label_color != NULL);
+
+ colorsel = GTK_COLOR_SELECTION (dialog->priv->colorsel);
+
+ gtk_color_selection_get_current_color (colorsel, label_color);
+}
+
+void
+e_mail_label_dialog_set_label_color (EMailLabelDialog *dialog,
+ const GdkColor *label_color)
+{
+ GtkColorSelection *colorsel;
+
+ g_return_if_fail (E_IS_MAIL_LABEL_DIALOG (dialog));
+ g_return_if_fail (label_color != NULL);
+
+ colorsel = GTK_COLOR_SELECTION (dialog->priv->colorsel);
+
+ gtk_color_selection_set_current_color (colorsel, label_color);
+
+ g_object_notify (G_OBJECT (dialog), "label-color");
+}
diff --cc mail/e-mail-label-dialog.h
index 3a259f6,0000000..17430c3
mode 100644,000000..100644
--- a/mail/e-mail-label-dialog.h
+++ b/mail/e-mail-label-dialog.h
@@@ -1,77 -1,0 +1,77 @@@
+/*
+ * e-mail-label-dialog.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_LABEL_DIALOG_H
+#define E_MAIL_LABEL_DIALOG_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_LABEL_DIALOG \
+ (e_mail_label_dialog_get_type ())
+#define E_MAIL_LABEL_DIALOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_LABEL_DIALOG, EMailLabelDialog))
+#define E_MAIL_LABEL_DIALOG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_LABEL_DIALOG, EMailLabelDialogClass))
+#define E_IS_MAIL_LABEL_DIALOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_LABEL_DIALOG))
+#define E_IS_MAIL_LABEL_DIALOG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_LABEL_DIALOG))
+#define E_MAIL_LABEL_DIALOG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_LABEL_DIALOG, EMailLabelDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailLabelDialog EMailLabelDialog;
+typedef struct _EMailLabelDialogClass EMailLabelDialogClass;
+typedef struct _EMailLabelDialogPrivate EMailLabelDialogPrivate;
+
+struct _EMailLabelDialog {
+ GtkDialog parent;
+ EMailLabelDialogPrivate *priv;
+};
+
+struct _EMailLabelDialogClass {
+ GtkDialogClass parent_class;
+};
+
+GType e_mail_label_dialog_get_type (void);
+GtkWidget * e_mail_label_dialog_new (GtkWindow *parent);
+const gchar * e_mail_label_dialog_get_label_name
+ (EMailLabelDialog *dialog);
+void e_mail_label_dialog_set_label_name
+ (EMailLabelDialog *dialog,
+ const gchar *label_name);
+void e_mail_label_dialog_get_label_color
+ (EMailLabelDialog *dialog,
+ GdkColor *label_color);
+void e_mail_label_dialog_set_label_color
+ (EMailLabelDialog *dialog,
+ const GdkColor *label_color);
+
+G_END_DECLS
+
+#endif /* E_MAIL_LABEL_DIALOG_H */
diff --cc mail/e-mail-label-list-store.c
index 3892838,0000000..1cbe927
mode 100644,000000..100644
--- a/mail/e-mail-label-list-store.c
+++ b/mail/e-mail-label-list-store.c
@@@ -1,513 -1,0 +1,513 @@@
+/*
+ * e-mail-label-list-store.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-label-list-store.h"
+
+#include <glib/gi18n.h>
+#include <camel/camel-utf8.h>
+#include "e-util/gconf-bridge.h"
+
+#define E_MAIL_LABEL_LIST_STORE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_LABEL_LIST_STORE, EMailLabelListStorePrivate))
+
+struct _EMailLabelListStorePrivate {
+ GHashTable *tag_index;
+};
+
+static struct {
+ const gchar *label_name;
+ const gchar *label_color;
+ const gchar *label_tag;
+} label_defaults[] = {
+ { N_("I_mportant"), "#EF2929", "$Labelimportant" }, /* red */
+ { N_("_Work"), "#F57900", "$Labelwork" }, /* orange */
+ { N_("_Personal"), "#4E9A06", "$Labelpersonal" }, /* green */
+ { N_("_To Do"), "#3465A4", "$Labeltodo" }, /* blue */
+ { N_("_Later"), "#75507B", "$Labellater" } /* purple */
+};
+
+static gpointer parent_class;
+
+static gchar *
+mail_label_list_store_tag_from_name (const gchar *label_name)
+{
+ gchar *label_tag;
+ gchar *temp;
+
+ /* Thunderbird compatible */
+ temp = g_ascii_strdown (label_name, -1);
+ g_strdelimit (temp, " ()/{%*<>\\\"", '_');
+ label_tag = camel_utf8_utf7 (temp);
+ g_free (temp);
+
+ return label_tag;
+}
+
+static gchar *
+mail_label_list_store_encode_label (const gchar *label_name,
+ const gchar *label_color,
+ const gchar *label_tag)
+{
+ GString *string;
+
+ /* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
+
+ string = g_string_new (label_name);
+ g_string_append_printf (string, ":%s", label_color);
+
+ if (label_tag != NULL)
+ g_string_append_printf (string, "|%s", label_tag);
+
+ return g_string_free (string, FALSE);
+}
+
+static void
+mail_label_list_store_ensure_defaults (EMailLabelListStore *store)
+{
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (label_defaults); ii++) {
+ GtkTreeIter iter;
+ const gchar *label_name;
+ const gchar *label_color;
+ const gchar *label_tag;
+ gchar *encoded;
+
+ label_name = gettext (label_defaults[ii].label_name);
+ label_color = label_defaults[ii].label_color;
+ label_tag = label_defaults[ii].label_tag;
+
+ encoded = mail_label_list_store_encode_label (
+ label_name, label_color, label_tag);
+
+ if (e_mail_label_list_store_lookup (store, label_tag, &iter))
+ gtk_list_store_set (
+ GTK_LIST_STORE (store),
+ &iter, 0, encoded, -1);
+ else
+ gtk_list_store_insert_with_values (
+ GTK_LIST_STORE (store),
+ NULL, -1, 0, encoded, -1);
+
+ g_free (encoded);
+ }
+}
+
+static gchar *
+mail_label_list_store_get_stock_id (EMailLabelListStore *store,
+ const gchar *color_spec)
+{
+ EMailLabelListStoreClass *class;
+ GtkIconFactory *icon_factory;
+ GdkColor color;
+ gchar *stock_id;
+
+ class = E_MAIL_LABEL_LIST_STORE_GET_CLASS (store);
+ icon_factory = class->icon_factory;
+
+ if (!gdk_color_parse (color_spec, &color))
+ return NULL;
+
+ stock_id = 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;
+ GdkPixbuf *pixbuf;
+ guint32 pixel;
+
+ pixel = ((color.red & 0xFF00) << 16) +
+ ((color.green & 0xFF00) << 8) +
+ (color.blue & 0xFF00);
+
+ 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);
+
+ g_object_unref (pixbuf);
+ }
+
+ return stock_id;
+}
+
+static void
+mail_label_list_store_finalize (GObject *object)
+{
+ EMailLabelListStorePrivate *priv;
+
+ priv = E_MAIL_LABEL_LIST_STORE_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->tag_index);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_label_list_store_constructed (GObject *object)
+{
+ EMailLabelListStore *store;
+ GtkTreeModel *model;
+ GConfBridge *bridge;
+ const gchar *key;
+
+ model = GTK_TREE_MODEL (object);
+ store = E_MAIL_LABEL_LIST_STORE (object);
+
+ bridge = gconf_bridge_get ();
+ key = "/apps/evolution/mail/labels";
+ gconf_bridge_bind_string_list_store (
+ bridge, key, GTK_LIST_STORE (store));
+
+ mail_label_list_store_ensure_defaults (store);
+}
+
+static void
+mail_label_list_store_row_inserted (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter)
+{
+ EMailLabelListStore *store;
+ GtkTreeRowReference *reference;
+ GHashTable *tag_index;
+ gchar *tag;
+
+ store = E_MAIL_LABEL_LIST_STORE (model);
+
+ /* Hash table takes ownership of both tag and reference. */
+ tag_index = store->priv->tag_index;
+ tag = e_mail_label_list_store_get_tag (store, iter);
+ reference = gtk_tree_row_reference_new (model, path);
+ g_hash_table_insert (tag_index, tag, reference);
+
+ /* We don't need to do anything special for row deletion.
+ * The reference will automatically become invalid (that's
+ * why we're storing references and not iterators or paths),
+ * so garbage collection is not important. We'll do it
+ * lazily. */
+}
+
+static void
+mail_label_list_store_class_init (EMailLabelListStoreClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailLabelListStorePrivate));
+
+ object_class = G_OBJECT_CLASS (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);
+}
+
+static void
+mail_label_list_store_init (EMailLabelListStore *store)
+{
+ GHashTable *tag_index;
+ GType type = G_TYPE_STRING;
+
+ tag_index = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) gtk_tree_row_reference_free);
+
+ store->priv = E_MAIL_LABEL_LIST_STORE_GET_PRIVATE (store);
+ store->priv->tag_index = tag_index;
+
+ /* XXX While it may seem awkward to cram the label name and color
+ * into a single string column, we do it for the benefit of
+ * letting GConfBridge keep the model in sync with GConf.
+ *
+ * XXX There's a valid argument to be made that this information
+ * doesn't belong in GConf in the first place. A key file
+ * under $(user_data_dir)/mail would work better. */
+ gtk_list_store_set_column_types (GTK_LIST_STORE (store), 1, &type);
+}
+
+static void
+mail_label_list_store_iface_init (GtkTreeModelIface *iface)
+{
+ iface->row_inserted = mail_label_list_store_row_inserted;
+}
+
+GType
+e_mail_label_list_store_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailLabelListStoreClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_label_list_store_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailLabelListStore),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_label_list_store_init,
+ NULL /* vaule_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) mail_label_list_store_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_LIST_STORE, "EMailLabelListStore",
+ &type_info, 0);
+
+ g_type_add_interface_static (
+ type, GTK_TYPE_TREE_MODEL, &iface_info);
+ }
+
+ return type;
+}
+
+EMailLabelListStore *
+e_mail_label_list_store_new (void)
+{
+ return g_object_new (E_TYPE_MAIL_LABEL_LIST_STORE, NULL);
+}
+
+gchar *
+e_mail_label_list_store_get_name (EMailLabelListStore *store,
+ GtkTreeIter *iter)
+{
+ gchar *encoded;
+ gchar *result;
+ gchar **strv;
+
+ /* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
+
+ g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &encoded, -1);
+
+ strv = g_strsplit_set (encoded, ":|", 3);
+
+ if (g_strv_length (strv) >= 2)
+ result = g_strdup (gettext (strv[0]));
+ else
+ result = NULL;
+
+ g_strfreev (strv);
+
+ return result;
+}
+
+gboolean
+e_mail_label_list_store_get_color (EMailLabelListStore *store,
+ GtkTreeIter *iter,
+ GdkColor *color)
+{
+ gchar *encoded;
+ gchar **strv;
+ gboolean valid;
+
+ /* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
+
+ g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (color != NULL, FALSE);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &encoded, -1);
+
+ strv = g_strsplit_set (encoded, ":|", 3);
+
+ if (g_strv_length (strv) >= 2)
+ valid = gdk_color_parse (strv[1], color);
+ else
+ valid = FALSE;
+
+ g_strfreev (strv);
+
+ return valid;
+}
+
+gchar *
+e_mail_label_list_store_get_stock_id (EMailLabelListStore *store,
+ GtkTreeIter *iter)
+{
+ gchar *encoded;
+ gchar *result;
+ gchar **strv;
+
+ /* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
+
+ g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &encoded, -1);
+
+ strv = g_strsplit_set (encoded, ":|", 3);
+
+ if (g_strv_length (strv) >= 2)
+ result = mail_label_list_store_get_stock_id (store, strv[1]);
+ else
+ result = NULL;
+
+ g_strfreev (strv);
+
+ return result;
+}
+
+gchar *
+e_mail_label_list_store_get_tag (EMailLabelListStore *store,
+ GtkTreeIter *iter)
+{
+ gchar *encoded;
+ gchar *result;
+ gchar **strv;
+
+ /* Encoded Form: <name> ':' <color> [ '|' <tag> ] */
+
+ g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), NULL);
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), iter, 0, &encoded, -1);
+
+ strv = g_strsplit_set (encoded, ":|", 3);
+
+ /* XXX I guess for historical reasons the default label tags have
+ * a "$Label" prefix, but the default list in GConf doesn't
+ * include tags. That's why the <tag> part is optional.
+ * So if we're missing the <tag> part, look it up in the
+ * hard-coded default list above.
+ *
+ * Not sure I got my facts straight here. Double check. */
+ if (g_strv_length (strv) >= 3)
+ result = g_strdup (strv[2]);
+ else {
+ gint ii;
+
+ result = NULL;
+
+ for (ii = 0; ii < G_N_ELEMENTS (label_defaults); ii++) {
+ const gchar *label_name;
+ const gchar *label_tag;
+
+ label_name = label_defaults[ii].label_name;
+ label_tag = label_defaults[ii].label_tag;
+
+ if (strcmp (strv[0], label_name) == 0) {
+ result = g_strdup (label_tag);
+ break;
+ }
+ }
+ }
+
+ g_strfreev (strv);
+
+ return result;
+}
+
+void
+e_mail_label_list_store_set (EMailLabelListStore *store,
+ GtkTreeIter *iter,
+ const gchar *name,
+ const GdkColor *color)
+{
+ gchar *encoded;
+ gchar *label_color;
+ gchar *label_tag = NULL;
+
+ g_return_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store));
+ g_return_if_fail (name != NULL);
+ g_return_if_fail (color != NULL);
+
+ label_color = gdk_color_to_string (color);
+
+ if (iter != NULL)
+ label_tag = e_mail_label_list_store_get_tag (store, iter);
+ if (label_tag == NULL)
+ label_tag = mail_label_list_store_tag_from_name (name);
+
+ encoded = mail_label_list_store_encode_label (
+ name, label_color, label_tag);
+
+ /* We use gtk_list_store_insert_with_values() so the data is
+ * in place when the 'row-inserted' signal is emitted and our
+ * row_inserted() method executes. */
+ if (iter != NULL)
+ gtk_list_store_set (
+ GTK_LIST_STORE (store), iter, 0, encoded, -1);
+ else
+ gtk_list_store_insert_with_values (
+ GTK_LIST_STORE (store), NULL, -1, 0, encoded, -1);
+
+ g_free (label_color);
+ g_free (label_tag);
+ g_free (encoded);
+}
+
+gboolean
+e_mail_label_list_store_lookup (EMailLabelListStore *store,
+ const gchar *tag,
+ GtkTreeIter *iter)
+{
+ GtkTreeRowReference *reference;
+ GHashTable *tag_index;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+
+ g_return_val_if_fail (E_IS_MAIL_LABEL_LIST_STORE (store), FALSE);
+ g_return_val_if_fail (tag != NULL, FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ tag_index = store->priv->tag_index;
+ reference = g_hash_table_lookup (tag_index, tag);
+
+ if (reference == NULL)
+ return FALSE;
+
+ if (!gtk_tree_row_reference_valid (reference)) {
+ /* Garbage collect the dead reference. */
+ g_hash_table_remove (tag_index, tag);
+ return FALSE;
+ }
+
+ model = gtk_tree_row_reference_get_model (reference);
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_model_get_iter (model, iter, path);
+ gtk_tree_path_free (path);
+
+ return TRUE;
+}
+
+gboolean
+e_mail_label_tag_is_default (const gchar *tag)
+{
+ g_return_val_if_fail (tag != NULL, FALSE);
+
+ return g_str_has_prefix (tag, "$Label");
+}
diff --cc mail/e-mail-label-list-store.h
index 2469d21,0000000..a9093ea
mode 100644,000000..100644
--- a/mail/e-mail-label-list-store.h
+++ b/mail/e-mail-label-list-store.h
@@@ -1,85 -1,0 +1,85 @@@
+/*
+ * e-mail-label-list-store.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_LABEL_LIST_STORE_H
+#define E_MAIL_LABEL_LIST_STORE_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_LABEL_LIST_STORE \
+ (e_mail_label_list_store_get_type ())
+#define E_MAIL_LABEL_LIST_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_LABEL_LIST_STORE, EMailLabelListStore))
+#define E_MAIL_LABEL_LIST_STORE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_LABEL_LIST_STORE, EMailLabelListStoreClass))
+#define E_IS_MAIL_LABEL_LIST_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_LABEL_LIST_STORE))
+#define E_IS_MAIL_LABEL_LIST_STORE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_LABEL_LIST_STORE))
+#define E_MAIL_LABEL_LIST_STORE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_LABEL_LIST_STORE, EMailLabelListStoreClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailLabelListStore EMailLabelListStore;
+typedef struct _EMailLabelListStoreClass EMailLabelListStoreClass;
+typedef struct _EMailLabelListStorePrivate EMailLabelListStorePrivate;
+
+struct _EMailLabelListStore {
+ GtkListStore parent;
+ EMailLabelListStorePrivate *priv;
+};
+
+struct _EMailLabelListStoreClass {
+ GtkListStoreClass parent_class;
+ GtkIconFactory *icon_factory;
+};
+
+GType e_mail_label_list_store_get_type (void);
+EMailLabelListStore *
+ e_mail_label_list_store_new (void);
+gchar * e_mail_label_list_store_get_name (EMailLabelListStore *store,
+ GtkTreeIter *iter);
+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,
+ GtkTreeIter *iter);
+gchar * e_mail_label_list_store_get_tag (EMailLabelListStore *store,
+ GtkTreeIter *iter);
+void e_mail_label_list_store_set (EMailLabelListStore *store,
+ GtkTreeIter *iter,
+ const gchar *name,
+ const GdkColor *color);
+gboolean e_mail_label_list_store_lookup (EMailLabelListStore *store,
+ const gchar *tag,
+ GtkTreeIter *iter);
+gboolean e_mail_label_tag_is_default (const gchar *tag);
+
+G_END_DECLS
+
+#endif /* E_MAIL_LABEL_LIST_STORE_H */
diff --cc mail/e-mail-label-manager.c
index fc18da3,0000000..212a050
mode 100644,000000..100644
--- a/mail/e-mail-label-manager.c
+++ b/mail/e-mail-label-manager.c
@@@ -1,479 -1,0 +1,479 @@@
+/*
+ * e-mail-label-manager.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-label-manager.h"
+
+#include <glib/gi18n.h>
+#include "e-mail-label-dialog.h"
+#include "e-mail-label-tree-view.h"
+
+#define E_MAIL_LABEL_MANAGER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_LABEL_MANAGER, EMailLabelManagerPrivate))
+
+struct _EMailLabelManagerPrivate {
+ GtkWidget *tree_view;
+ GtkWidget *add_button;
+ GtkWidget *edit_button;
+ GtkWidget *remove_button;
+};
+
+enum {
+ PROP_0,
+ PROP_LIST_STORE
+};
+
+enum {
+ ADD_LABEL,
+ EDIT_LABEL,
+ REMOVE_LABEL,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+mail_label_manager_selection_changed_cb (EMailLabelManager *manager,
+ GtkTreeSelection *selection)
+{
+ GtkWidget *edit_button;
+ GtkWidget *remove_button;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ edit_button = manager->priv->edit_button;
+ remove_button = manager->priv->remove_button;
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ EMailLabelListStore *store;
+ gboolean sensitive;
+ gchar *label_tag;
+
+ store = E_MAIL_LABEL_LIST_STORE (model);
+ label_tag = e_mail_label_list_store_get_tag (store, &iter);
+ sensitive = !e_mail_label_tag_is_default (label_tag);
+ g_free (label_tag);
+
+ /* Disallow removing default labels. */
+ gtk_widget_set_sensitive (edit_button, TRUE);
+ gtk_widget_set_sensitive (remove_button, sensitive);
+ } else {
+ gtk_widget_set_sensitive (edit_button, FALSE);
+ gtk_widget_set_sensitive (remove_button, FALSE);
+ }
+}
+
+static void
+mail_label_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_LIST_STORE:
+ e_mail_label_manager_set_list_store (
+ E_MAIL_LABEL_MANAGER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_label_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_LIST_STORE:
+ g_value_set_object (
+ value, e_mail_label_manager_get_list_store (
+ E_MAIL_LABEL_MANAGER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_label_manager_dispose (GObject *object)
+{
+ EMailLabelManagerPrivate *priv;
+
+ priv = E_MAIL_LABEL_MANAGER_GET_PRIVATE (object);
+
+ if (priv->tree_view != NULL) {
+ g_object_unref (priv->tree_view);
+ priv->tree_view = NULL;
+ }
+
+ if (priv->add_button != NULL) {
+ g_object_unref (priv->add_button);
+ priv->add_button = NULL;
+ }
+
+ if (priv->edit_button != NULL) {
+ g_object_unref (priv->edit_button);
+ priv->edit_button = NULL;
+ }
+
+ if (priv->remove_button != NULL) {
+ g_object_unref (priv->remove_button);
+ priv->remove_button = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_label_manager_add_label (EMailLabelManager *manager)
+{
+ EMailLabelDialog *label_dialog;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkWidget *dialog;
+ gpointer parent;
+ GdkColor label_color;
+ const gchar *label_name;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+ dialog = e_mail_label_dialog_new (parent);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Add Label"));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ label_dialog = E_MAIL_LABEL_DIALOG (dialog);
+ label_name = e_mail_label_dialog_get_label_name (label_dialog);
+ e_mail_label_dialog_get_label_color (label_dialog, &label_color);
+
+ tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
+ model = gtk_tree_view_get_model (tree_view);
+
+ e_mail_label_list_store_set (
+ E_MAIL_LABEL_LIST_STORE (model),
+ NULL, label_name, &label_color);
+
+exit:
+ gtk_widget_destroy (dialog);
+}
+
+static void
+mail_label_manager_edit_label (EMailLabelManager *manager)
+{
+ EMailLabelDialog *label_dialog;
+ EMailLabelListStore *label_store;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkWidget *dialog;
+ GtkWidget *parent;
+ GdkColor label_color;
+ const gchar *new_name;
+ gchar *label_name;
+
+ tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ label_store = E_MAIL_LABEL_LIST_STORE (model);
+ label_name = e_mail_label_list_store_get_name (label_store, &iter);
+ e_mail_label_list_store_get_color (label_store, &iter, &label_color);
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
+ dialog = e_mail_label_dialog_new (GTK_WINDOW (parent));
+ label_dialog = E_MAIL_LABEL_DIALOG (dialog);
+
+ e_mail_label_dialog_set_label_name (label_dialog, label_name);
+ e_mail_label_dialog_set_label_color (label_dialog, &label_color);
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Label"));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ new_name = e_mail_label_dialog_get_label_name (label_dialog);
+ e_mail_label_dialog_get_label_color (label_dialog, &label_color);
+
+ e_mail_label_list_store_set (
+ label_store, &iter, new_name, &label_color);
+
+exit:
+ gtk_widget_destroy (dialog);
+
+ g_free (label_name);
+}
+
+static void
+mail_label_manager_remove_label (EMailLabelManager *manager)
+{
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+}
+
+static void
+mail_label_manager_class_init (EMailLabelManagerClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailLabelManagerPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = mail_label_manager_set_property;
+ object_class->get_property = mail_label_manager_get_property;
+ object_class->dispose = mail_label_manager_dispose;
+
+ class->add_label = mail_label_manager_add_label;
+ class->edit_label = mail_label_manager_edit_label;
+ class->remove_label = mail_label_manager_remove_label;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_LIST_STORE,
+ g_param_spec_object (
+ "list-store",
+ "List Store",
+ NULL,
+ E_TYPE_MAIL_LABEL_LIST_STORE,
+ G_PARAM_READWRITE));
+
+ signals[ADD_LABEL] = g_signal_new (
+ "add-label",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EMailLabelManagerClass, add_label),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[EDIT_LABEL] = g_signal_new (
+ "edit-label",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EMailLabelManagerClass, edit_label),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[REMOVE_LABEL] = g_signal_new (
+ "remove-label",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EMailLabelManagerClass, remove_label),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+mail_label_manager_init (EMailLabelManager *manager)
+{
+ GtkTreeSelection *selection;
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ manager->priv = E_MAIL_LABEL_MANAGER_GET_PRIVATE (manager);
+
+ gtk_table_resize (GTK_TABLE (manager), 2, 2);
+ gtk_table_set_col_spacings (GTK_TABLE (manager), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (manager), 12);
+
+ container = GTK_WIDGET (manager);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_table_attach (
+ GTK_TABLE (container), widget, 0, 1, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_mail_label_tree_view_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ manager->priv->tree_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (mail_label_manager_selection_changed_cb),
+ manager);
+
+ container = GTK_WIDGET (manager);
+
+ /* FIXME Clarify this. What menu? */
+ widget = gtk_label_new (
+ _("Note: Underscore in the label name is used\n"
+ "as mnemonic identifier in menu."));
+ gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_CENTER);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 1, 1, 2, 0, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_vbutton_box_new ();
+ gtk_button_box_set_layout (
+ GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
+ gtk_box_set_spacing (GTK_BOX (widget), 6);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 0, 2, 0, GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_ADD);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->add_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_mail_label_manager_add_label), manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_EDIT);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->edit_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_mail_label_manager_edit_label), manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->remove_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_mail_label_manager_remove_label), manager);
+}
+
+GType
+e_mail_label_manager_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailLabelManagerClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_label_manager_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailLabelManager),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_label_manager_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_TABLE, "EMailLabelManager", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_mail_label_manager_new (void)
+{
+ return g_object_new (E_TYPE_MAIL_LABEL_MANAGER, NULL);
+}
+
+void
+e_mail_label_manager_add_label (EMailLabelManager *manager)
+{
+ g_return_if_fail (E_IS_MAIL_LABEL_MANAGER (manager));
+
+ g_signal_emit (manager, signals[ADD_LABEL], 0);
+}
+
+void
+e_mail_label_manager_edit_label (EMailLabelManager *manager)
+{
+ g_return_if_fail (E_IS_MAIL_LABEL_MANAGER (manager));
+
+ g_signal_emit (manager, signals[EDIT_LABEL], 0);
+}
+
+void
+e_mail_label_manager_remove_label (EMailLabelManager *manager)
+{
+ g_return_if_fail (E_IS_MAIL_LABEL_MANAGER (manager));
+
+ g_signal_emit (manager, signals[REMOVE_LABEL], 0);
+}
+
+EMailLabelListStore *
+e_mail_label_manager_get_list_store (EMailLabelManager *manager)
+{
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+
+ g_return_val_if_fail (E_IS_MAIL_LABEL_MANAGER (manager), NULL);
+
+ tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
+ model = gtk_tree_view_get_model (tree_view);
+
+ return E_MAIL_LABEL_LIST_STORE (model);
+}
+
+void
+e_mail_label_manager_set_list_store (EMailLabelManager *manager,
+ EMailLabelListStore *list_store)
+{
+ GtkTreeView *tree_view;
+
+ g_return_if_fail (E_IS_MAIL_LABEL_MANAGER (manager));
+ g_return_if_fail (E_IS_MAIL_LABEL_LIST_STORE (list_store));
+
+ tree_view = GTK_TREE_VIEW (manager->priv->tree_view);
+ gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (list_store));
+
+ g_object_notify (G_OBJECT (manager), "list-store");
+}
diff --cc mail/e-mail-label-manager.h
index 0a36ee2,0000000..20d375e
mode 100644,000000..100644
--- a/mail/e-mail-label-manager.h
+++ b/mail/e-mail-label-manager.h
@@@ -1,81 -1,0 +1,81 @@@
+/*
+ * e-mail-label-manager.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_LABEL_MANAGER_H
+#define E_MAIL_LABEL_MANAGER_H
+
+#include <gtk/gtk.h>
+#include <mail/e-mail-label-list-store.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_LABEL_MANAGER \
+ (e_mail_label_manager_get_type ())
+#define E_MAIL_LABEL_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_LABEL_MANAGER, EMailLabelManager))
+#define E_MAIL_LABEL_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_LABEL_MANAGER, EMailLabelManagerClass))
+#define E_IS_MAIL_LABEL_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_LABEL_MANAGER))
+#define E_IS_MAIL_LABEL_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_LABEL_MANAGER))
+#define E_MAIL_LABEL_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_LABEL_MANAGER, EMailLabelManagerClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailLabelManager EMailLabelManager;
+typedef struct _EMailLabelManagerClass EMailLabelManagerClass;
+typedef struct _EMailLabelManagerPrivate EMailLabelManagerPrivate;
+
+struct _EMailLabelManager {
+ GtkTable parent;
+ EMailLabelManagerPrivate *priv;
+};
+
+struct _EMailLabelManagerClass {
+ GtkTableClass parent_class;
+
+ void (*add_label) (EMailLabelManager *manager);
+ void (*edit_label) (EMailLabelManager *manager);
+ void (*remove_label) (EMailLabelManager *manager);
+};
+
+GType e_mail_label_manager_get_type (void);
+GtkWidget * e_mail_label_manager_new (void);
+void e_mail_label_manager_add_label (EMailLabelManager *manager);
+void e_mail_label_manager_edit_label (EMailLabelManager *manager);
+void e_mail_label_manager_remove_label
+ (EMailLabelManager *manager);
+EMailLabelListStore *
+ e_mail_label_manager_get_list_store
+ (EMailLabelManager *manager);
+void e_mail_label_manager_set_list_store
+ (EMailLabelManager *manager,
+ EMailLabelListStore *list_store);
+
+G_END_DECLS
+
+#endif /* E_MAIL_LABEL_MANAGER_H */
diff --cc mail/e-mail-label-tree-view.c
index 5675329,0000000..808d8d0
mode 100644,000000..100644
--- a/mail/e-mail-label-tree-view.c
+++ b/mail/e-mail-label-tree-view.c
@@@ -1,136 -1,0 +1,136 @@@
+/*
+ * e-mail-label-tree-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-label-tree-view.h"
+
+#include <glib/gi18n.h>
+#include "e-mail-label-list-store.h"
+
+#define E_MAIL_LABEL_TREE_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_LABEL_TREE_VIEW, EMailLabelTreeViewPrivate))
+
+struct _EMailLabelTreeViewPrivate {
+ gint placeholder;
+};
+
+static gpointer parent_class;
+
+static void
+mail_label_tree_view_render_pixbuf (GtkTreeViewColumn *column,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ EMailLabelTreeView *tree_view)
+{
+ EMailLabelListStore *store;
+ gchar *stock_id;
+
+ 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);
+}
+
+static void
+mail_label_tree_view_render_text (GtkTreeViewColumn *column,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ EMailLabelTreeView *tree_view)
+{
+ EMailLabelListStore *store;
+ gchar *name;
+
+ store = E_MAIL_LABEL_LIST_STORE (model);
+ name = e_mail_label_list_store_get_name (store, iter);
+ g_object_set (renderer, "text", name, NULL);
+ g_free (name);
+}
+
+static void
+mail_label_tree_view_class_init (EMailLabelTreeViewClass *class)
+{
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailLabelTreeViewPrivate));
+}
+
+static void
+mail_label_tree_view_init (EMailLabelTreeView *tree_view)
+{
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ tree_view->priv = E_MAIL_LABEL_TREE_VIEW_GET_PRIVATE (tree_view);
+
+ column = gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_set_title (column, _("Color"));
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+ gtk_tree_view_column_set_cell_data_func (
+ column, renderer, (GtkTreeCellDataFunc)
+ mail_label_tree_view_render_pixbuf, tree_view, NULL);
+
+ column = gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_set_title (column, _("Name"));
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+ gtk_tree_view_column_set_cell_data_func (
+ column, renderer, (GtkTreeCellDataFunc)
+ mail_label_tree_view_render_text, tree_view, NULL);
+}
+
+GType
+e_mail_label_tree_view_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailLabelTreeViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_label_tree_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailLabelTreeView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_label_tree_view_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_TREE_VIEW, "EMailLabelTreeView",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_mail_label_tree_view_new (void)
+{
+ return g_object_new (E_TYPE_MAIL_LABEL_TREE_VIEW, NULL);
+}
diff --cc mail/e-mail-label-tree-view.h
index d29ad62,0000000..0dd58f2
mode 100644,000000..100644
--- a/mail/e-mail-label-tree-view.h
+++ b/mail/e-mail-label-tree-view.h
@@@ -1,66 -1,0 +1,66 @@@
+/*
+ * e-mail-label-tree-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_LABEL_TREE_VIEW_H
+#define E_MAIL_LABEL_TREE_VIEW_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_LABEL_TREE_VIEW \
+ (e_mail_label_tree_view_get_type ())
+#define E_MAIL_LABEL_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_LABEL_TREE_VIEW, EMailLabelTreeView))
+#define E_MAIL_LABEL_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_LABEL_TREE_VIEW, EMailLabelTreeViewClass))
+#define E_IS_MAIL_LABEL_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_LABEL_TREE_VIEW))
+#define E_IS_MAIL_LABEL_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_LABEL_TREE_VIEW))
+#define E_MAIL_LABEL_TREE_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_LABEL_TREE_VIEW, EMailLabelTreeViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailLabelTreeView EMailLabelTreeView;
+typedef struct _EMailLabelTreeViewClass EMailLabelTreeViewClass;
+typedef struct _EMailLabelTreeViewPrivate EMailLabelTreeViewPrivate;
+
+struct _EMailLabelTreeView {
+ GtkTreeView parent;
+ EMailLabelTreeViewPrivate *priv;
+};
+
+struct _EMailLabelTreeViewClass {
+ GtkTreeViewClass parent_class;
+};
+
+GType e_mail_label_tree_view_get_type (void);
+GtkWidget * e_mail_label_tree_view_new (void);
+
+G_END_DECLS
+
+#endif /* E_MAIL_LABEL_TREE_VIEW_H */
diff --cc mail/e-mail-reader-utils.c
index 96fe1ba,0000000..7914421
mode 100644,000000..100644
--- a/mail/e-mail-reader-utils.c
+++ b/mail/e-mail-reader-utils.c
@@@ -1,593 -1,0 +1,593 @@@
+/*
+ * e-mail-reader-utils.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* Miscellaneous utility functions used by EMailReader actions. */
+
+#include "e-mail-reader-utils.h"
+
+#include <glib/gi18n.h>
+#include <gtkhtml/gtkhtml.h>
+#include <camel/camel-mime-message.h>
+#include <camel/camel-vee-folder.h>
+#include <camel/camel-vee-store.h>
+
+#include "e-util/e-error.h"
+#include "filter/filter-rule.h"
+
+#include "mail/e-mail-browser.h"
+#include "mail/em-composer-utils.h"
+#include "mail/em-format-html-print.h"
+#include "mail/em-utils.h"
+#include "mail/mail-autofilter.h"
+#include "mail/mail-ops.h"
+#include "mail/mail-tools.h"
+#include "mail/mail-vfolder.h"
+
+void
+e_mail_reader_activate (EMailReader *reader,
+ const gchar *action_name)
+{
+ GtkActionGroup *action_group;
+ GtkAction *action;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (action_name != NULL);
+
+ action_group = e_mail_reader_get_action_group (reader);
+ action = gtk_action_group_get_action (action_group, action_name);
+ g_return_if_fail (action != NULL);
+
+ gtk_action_activate (action);
+}
+
+gboolean
+e_mail_reader_confirm_delete (EMailReader *reader)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+ EShellSettings *shell_settings;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWidget *check_button;
+ GtkWidget *content_area;
+ GtkWidget *dialog;
+ GtkWindow *window;
+ const gchar *label;
+ gboolean prompt_delete_in_vfolder;
+ gint response;
+
+ /* Remind users what deleting from a search folder does. */
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ folder = message_list->folder;
+
+ prompt_delete_in_vfolder = e_shell_settings_get_boolean (
+ shell_settings, "mail-prompt-delete-in-vfolder");
+
+ if (!CAMEL_IS_VEE_STORE (folder->parent_store))
+ return TRUE;
+
+ if (!prompt_delete_in_vfolder)
+ return TRUE;
+
+ dialog = e_error_new (
+ window, "mail:ask-delete-vfolder-msg",
+ folder->full_name, NULL);
+
+ /* XXX e-error should provide a widget layout and API suitable
+ * for packing additional widgets to the right of the alert
+ * icon. But for now, screw it. */
+
+ label = _("Do not ask me again");
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+ check_button = gtk_check_button_new_with_label (label);
+ gtk_box_pack_start (
+ GTK_BOX (content_area), check_button, TRUE, TRUE, 6);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response == GTK_RESPONSE_OK)
+ e_shell_settings_set_boolean (
+ shell_settings,
+ "mail-prompt-delete-in-vfolder",
+ gtk_toggle_button_get_active (
+ GTK_TOGGLE_BUTTON (check_button)));
+
+ gtk_widget_destroy (dialog);
+
+ return (response == GTK_RESPONSE_OK);
+}
+
+void
+e_mail_reader_mark_as_read (EMailReader *reader,
+ const gchar *uid)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ CamelFolder *folder;
+ guint32 mask, set;
+ guint32 flags;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (uid != NULL);
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ flags = camel_folder_get_message_flags (folder, uid);
+
+ if (!(flags & CAMEL_MESSAGE_SEEN)) {
+ CamelMimeMessage *message;
+
+ message = ((EMFormat *) html_display)->message;
+ em_utils_handle_receipt (folder, uid, message);
+ }
+
+ mask = CAMEL_MESSAGE_SEEN;
+ set = CAMEL_MESSAGE_SEEN;
+ camel_folder_set_message_flags (folder, uid, mask, set);
+}
+
+guint
+e_mail_reader_mark_selected (EMailReader *reader,
+ guint32 mask,
+ guint32 set)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+ guint ii;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ if (folder == NULL)
+ return 0;
+
+ camel_folder_freeze (folder);
+ uids = message_list_get_selected (message_list);
+
+ for (ii = 0; ii < uids->len; ii++)
+ camel_folder_set_message_flags (
+ folder, uids->pdata[ii], mask, set);
+
+ message_list_free_uids (message_list, uids);
+ camel_folder_thaw (folder);
+
+ return ii;
+}
+
+guint
+e_mail_reader_open_selected (EMailReader *reader)
+{
+ EMailShellBackend *mail_shell_backend;
+ EShellBackend *shell_backend;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *views;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+ guint ii;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
+
+ message_list = e_mail_reader_get_message_list (reader);
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ window = e_mail_reader_get_window (reader);
+
+ mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len >= 10) {
+ gchar *len_str;
+ gboolean proceed;
+
+ len_str = g_strdup_printf ("%d", uids->len);
+
+ proceed = em_utils_prompt_user (
+ window, "/apps/evolution/mail/prompts/open_many",
+ "mail:ask-open-many", len_str, NULL);
+
+ g_free (len_str);
+
+ if (!proceed) {
+ message_list_free_uids (message_list, uids);
+ return 0;
+ }
+ }
+
+ if (em_utils_folder_is_drafts (folder, folder_uri) ||
+ em_utils_folder_is_outbox (folder, folder_uri) ||
+ em_utils_folder_is_templates (folder, folder_uri)) {
+ em_utils_edit_messages (folder, uids, TRUE);
+ return uids->len;
+ }
+
+ views = g_ptr_array_new ();
+
+ /* For vfolders we need to edit the original, not the vfolder copy. */
+ for (ii = 0; ii < uids->len; ii++) {
+ const gchar *uid = uids->pdata[ii];
+ CamelFolder *real_folder;
+ CamelMessageInfo *info;
+ gchar *real_folder_uri;
+ gchar *real_uid;
+
+ if (!CAMEL_IS_VEE_FOLDER (folder)) {
+ g_ptr_array_add (views, g_strdup (uid));
+ continue;
+ }
+
+ info = camel_folder_get_message_info (folder, uid);
+ if (info == NULL)
+ continue;
+
+ real_folder = camel_vee_folder_get_location (
+ CAMEL_VEE_FOLDER (folder),
+ (CamelVeeMessageInfo *) info, &real_uid);
+ real_folder_uri = mail_tools_folder_to_url (real_folder);
+
+ if (em_utils_folder_is_drafts (real_folder, real_folder_uri) ||
+ em_utils_folder_is_outbox (real_folder, real_folder_uri)) {
+ GPtrArray *edits;
+
+ edits = g_ptr_array_new ();
+ g_ptr_array_add (edits, real_uid);
+ em_utils_edit_messages (real_folder, edits, TRUE);
+ } else {
+ g_free (real_uid);
+ g_ptr_array_add (views, g_strdup (uid));
+ }
+
+ g_free (real_folder_uri);
+ }
+
+ for (ii = 0; ii < views->len; ii++) {
+ const gchar *uid = views->pdata[ii];
+ GtkWidget *browser;
+
+ browser = e_mail_browser_new (mail_shell_backend);
+ e_mail_reader_set_folder (
+ E_MAIL_READER (browser), folder, folder_uri);
+ e_mail_reader_set_message (
+ E_MAIL_READER (browser), uid, FALSE);
+ gtk_widget_show (browser);
+ }
+
+ g_ptr_array_free (views, TRUE);
+
+ message_list_free_uids (message_list, uids);
+
+ return ii;
+}
+
+void
+e_mail_reader_print (EMailReader *reader,
+ GtkPrintOperationAction action)
+{
+ MessageList *message_list;
+ EMFormatHTMLDisplay *html_display;
+ EMFormatHTMLPrint *html_print;
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ g_return_if_fail (folder != NULL);
+
+ /* XXX Learn to handle len > 1. */
+ uids = message_list_get_selected (message_list);
+ if (uids->len != 1)
+ goto exit;
+
+ html_print = em_format_html_print_new (
+ (EMFormatHTML *) html_display, action);
+ em_format_merge_handler (
+ (EMFormat *) html_print,
+ (EMFormat *) html_display);
+ em_format_html_print_message (html_print, folder, uids->pdata[0]);
+ g_object_unref (html_print);
+
+exit:
+ message_list_free_uids (message_list, uids);
+}
+
+/* Helper for e_mail_reader_reply_to_message()
+ * XXX This function belongs in e-html-utils.c */
+static gboolean
+html_contains_nonwhitespace (const gchar *html,
+ gint len)
+{
+ const gchar *cp;
+ gunichar uc = 0;
+
+ if (html == NULL || len <= 0)
+ return FALSE;
+
+ cp = html;
+
+ while (cp != NULL && cp - html < len) {
+ uc = g_utf8_get_char (cp);
+ if (uc == 0)
+ break;
+
+ if (uc == '<') {
+ /* skip until next '>' */
+ uc = g_utf8_get_char (cp);
+ while (uc != 0 && uc != '>' && cp - html < len) {
+ cp = g_utf8_next_char (cp);
+ uc = g_utf8_get_char (cp);
+ }
+ if (uc == 0)
+ break;
+ } else if (uc == '&') {
+ /* sequence ' ' is a space */
+ if (g_ascii_strncasecmp (cp, " ", 6) == 0)
+ cp = cp + 5;
+ else
+ break;
+ } else if (!g_unichar_isspace (uc))
+ break;
+
+ cp = g_utf8_next_char (cp);
+ }
+
+ return cp - html < len - 1 && uc != 0;
+}
+
+void
+e_mail_reader_reply_to_message (EMailReader *reader,
+ gint reply_mode)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ CamelMimeMessage *new_message;
+ CamelMimeMessage *src_message;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GtkHTML *html;
+ struct _camel_header_raw *header;
+ const gchar *uid;
+ gchar *selection = NULL;
+ gint length;
+
+ /* This handles quoting only selected text in the reply. If
+ * nothing is selected or only whitespace is selected, fall
+ * back to the normal em_utils_reply_to_message(). */
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = ((EMFormatHTML *) html_display)->html;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uid = message_list->cursor_uid;
+ g_return_if_fail (uid != NULL);
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ if (!gtk_html_command (html, "is-selection-active"))
+ goto whole_message;
+
+ selection = gtk_html_get_selection_html (html, &length);
+ if (selection == NULL || *selection == '\0')
+ goto whole_message;
+
+ if (!html_contains_nonwhitespace (selection, length))
+ goto whole_message;
+
+ src_message =
+ CAMEL_MIME_MESSAGE (((EMFormat *) html_display)->message);
+ new_message = camel_mime_message_new ();
+
+ /* Filter out "content-*" headers. */
+ header = CAMEL_MIME_PART (src_message)->headers;
+ while (header != NULL) {
+ if (g_ascii_strncasecmp (header->name, "content-", 8) != 0)
+ camel_medium_add_header (
+ CAMEL_MEDIUM (new_message),
+ header->name, header->value);
+ }
+
+ camel_mime_part_set_encoding (
+ CAMEL_MIME_PART (new_message),
+ CAMEL_TRANSFER_ENCODING_8BIT);
+
+ camel_mime_part_set_content (
+ CAMEL_MIME_PART (new_message),
+ selection, length, "text/html");
+
+ em_utils_reply_to_message (
+ folder, uid, new_message, reply_mode, NULL);
+
+ g_free (selection);
+
+ return;
+
+whole_message:
+ em_utils_reply_to_message (
+ folder, uid, NULL, reply_mode, (EMFormat *) html_display);
+}
+
+void
+e_mail_reader_select_next_message (EMailReader *reader,
+ gboolean or_else_previous)
+{
+ MessageList *message_list;
+ gboolean hide_deleted;
+ gboolean success;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ hide_deleted = e_mail_reader_get_hide_deleted (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ success = message_list_select (
+ message_list, MESSAGE_LIST_SELECT_NEXT, 0, 0);
+
+ if (!success && (hide_deleted || or_else_previous))
+ message_list_select (
+ message_list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0);
+}
+
+/* Helper for e_mail_reader_create_filter_from_selected() */
+static void
+mail_reader_create_filter_cb (CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ gpointer user_data)
+{
+ struct {
+ const gchar *source;
+ gint type;
+ } *filter_data = user_data;
+
+ if (message != NULL)
+ filter_gui_add_from_message (
+ message, filter_data->source, filter_data->type);
+
+ g_free (filter_data);
+}
+
+void
+e_mail_reader_create_filter_from_selected (EMailReader *reader,
+ gint filter_type)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ const gchar *filter_source;
+ const gchar *folder_uri;
+ GPtrArray *uids;
+
+ struct {
+ const gchar *source;
+ gint type;
+ } *filter_data;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+
+ if (em_utils_folder_is_sent (folder, folder_uri))
+ filter_source = FILTER_SOURCE_OUTGOING;
+ else if (em_utils_folder_is_outbox (folder, folder_uri))
+ filter_source = FILTER_SOURCE_OUTGOING;
+ else
+ filter_source = FILTER_SOURCE_INCOMING;
+
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len == 1) {
+ filter_data = g_malloc (sizeof (*filter_data));
+ filter_data->source = filter_source;
+ filter_data->type = filter_type;
+
+ mail_get_message (
+ folder, uids->pdata[0],
+ mail_reader_create_filter_cb,
+ filter_data, mail_msg_unordered_push);
+ }
+
+ em_utils_uids_free (uids);
+}
+
+/* Helper for e_mail_reader_create_vfolder_from_selected() */
+static void
+mail_reader_create_vfolder_cb (CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ gpointer user_data)
+{
+ struct {
+ gchar *uri;
+ gint type;
+ } *vfolder_data = user_data;
+
+ if (message != NULL)
+ vfolder_gui_add_from_message (
+ message, vfolder_data->type, vfolder_data->uri);
+
+ g_free (vfolder_data->uri);
+ g_free (vfolder_data);
+}
+
+void
+e_mail_reader_create_vfolder_from_selected (EMailReader *reader,
+ gint vfolder_type)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ const gchar *folder_uri;
+ GPtrArray *uids;
+
+ struct {
+ gchar *uri;
+ gint type;
+ } *vfolder_data;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len == 1) {
+ vfolder_data = g_malloc (sizeof (*vfolder_data));
+ vfolder_data->uri = g_strdup (folder_uri);
+ vfolder_data->type = vfolder_type;
+
+ mail_get_message (
+ folder, uids->pdata[0],
+ mail_reader_create_vfolder_cb,
+ vfolder_data, mail_msg_unordered_push);
+ }
+
+ em_utils_uids_free (uids);
+}
diff --cc mail/e-mail-reader-utils.h
index 8ec2235,0000000..46c3ea7
mode 100644,000000..100644
--- a/mail/e-mail-reader-utils.h
+++ b/mail/e-mail-reader-utils.h
@@@ -1,56 -1,0 +1,56 @@@
+/*
+ * e-mail-reader-utils.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* Miscellaneous utility functions used by EMailReader actions. */
+
+#ifndef E_MAIL_READER_UTILS_H
+#define E_MAIL_READER_UTILS_H
+
+#include <mail/e-mail-reader.h>
+
+G_BEGIN_DECLS
+
+void e_mail_reader_activate (EMailReader *reader,
+ const gchar *action_name);
+gboolean e_mail_reader_confirm_delete (EMailReader *reader);
+void e_mail_reader_mark_as_read (EMailReader *reader,
+ const gchar *uid);
+guint e_mail_reader_mark_selected (EMailReader *reader,
+ guint32 mask,
+ guint32 set);
+guint e_mail_reader_open_selected (EMailReader *reader);
+void e_mail_reader_print (EMailReader *reader,
+ GtkPrintOperationAction action);
+void e_mail_reader_reply_to_message (EMailReader *reader,
+ gint reply_mode);
+void e_mail_reader_select_next_message
+ (EMailReader *reader,
+ gboolean or_else_previous);
+void e_mail_reader_create_filter_from_selected
+ (EMailReader *reader,
+ gint filter_type);
+void e_mail_reader_create_vfolder_from_selected
+ (EMailReader *reader,
+ gint filter_type);
+
+G_END_DECLS
+
+#endif /* E_MAIL_READER_UTILS_H */
diff --cc mail/e-mail-reader.c
index 3969f4b,0000000..1cf9ff9
mode 100644,000000..100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@@ -1,2738 -1,0 +1,2738 @@@
+/*
+ * e-mail-reader.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-reader.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-stream.h>
+
+#ifdef HAVE_XFREE
+#include <X11/XF86keysym.h>
+#endif
+
+#include "e-util/e-util.h"
+#include "e-util/e-binding.h"
+#include "e-util/gconf-bridge.h"
+#include "shell/e-shell.h"
+#include "widgets/misc/e-charset-picker.h"
+#include "widgets/misc/e-popup-action.h"
+
+#include "mail/e-mail-browser.h"
+#include "mail/e-mail-reader-utils.h"
+#include "mail/e-mail-shell-backend.h"
+#include "mail/em-composer-utils.h"
+#include "mail/em-event.h"
+#include "mail/em-folder-selector.h"
+#include "mail/em-folder-tree.h"
+#include "mail/em-utils.h"
+#include "mail/mail-autofilter.h"
+#include "mail/mail-config.h"
+#include "mail/mail-ops.h"
+
+enum {
+ CHANGED,
+ FOLDER_LOADED,
+ SHOW_SEARCH_BAR,
+ LAST_SIGNAL
+};
+
+/* Remembers the previously selected folder when transferring messages. */
+static gchar *default_xfer_messages_uri;
+
+static guint signals[LAST_SIGNAL];
+
+static void
+action_mail_add_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelMessageInfo *info;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *address;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len != 1)
+ goto exit;
+
+ info = camel_folder_get_message_info (folder, uids->pdata[0]);
+ if (info == NULL)
+ goto exit;
+
+ address = camel_message_info_from (info);
+ if (address == NULL || *address == '\0')
+ goto exit;
+
+ em_utils_add_address (window, address);
+
+exit:
+ em_utils_uids_free (uids);
+}
+
+static void
+action_mail_charset_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ const gchar *charset;
+
+ if (action != current)
+ return;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ charset = g_object_get_data (G_OBJECT (action), "charset");
+
+ /* Charset for "Default" action will be NULL. */
+ em_format_set_charset (EM_FORMAT (html_display), charset);
+}
+
+static void
+action_mail_check_for_junk_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ mail_filter_junk (folder, uids);
+}
+
+static void
+action_mail_clipboard_copy_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_copy (html);
+}
+
+static void
+action_mail_copy_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EShellBackend *shell_backend;
+ MessageList *message_list;
+ EMFolderTreeModel *model;
+ CamelFolder *folder;
+ GtkWidget *folder_tree;
+ GtkWidget *dialog;
+ GPtrArray *selected;
+ const gchar *uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ model = e_mail_shell_backend_get_folder_tree_model (
+ E_MAIL_SHELL_BACKEND (shell_backend));
+
+ folder_tree = em_folder_tree_new_with_model (model);
+ selected = message_list_get_selected (message_list);
+
+ folder = message_list->folder;
+
+ em_folder_tree_set_excluded (
+ EM_FOLDER_TREE (folder_tree),
+ EMFT_EXCLUDE_NOSELECT | EMFT_EXCLUDE_VIRTUAL |
+ EMFT_EXCLUDE_VTRASH);
+
+ dialog = em_folder_selector_new (
+ EM_FOLDER_TREE (folder_tree),
+ EM_FOLDER_SELECTOR_CAN_CREATE,
+ _("Select Folder"), NULL, _("C_opy"));
+
+ if (default_xfer_messages_uri != NULL)
+ em_folder_selector_set_selected (
+ EM_FOLDER_SELECTOR (dialog),
+ default_xfer_messages_uri);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ uri = em_folder_selector_get_selected_uri (
+ EM_FOLDER_SELECTOR (dialog));
+
+ g_free (default_xfer_messages_uri);
+ default_xfer_messages_uri = g_strdup (uri);
+
+ if (uri != NULL) {
+ mail_transfer_messages (
+ folder, selected, FALSE, uri, 0, NULL, NULL);
+ selected = NULL;
+ }
+
+exit:
+ if (selected != NULL)
+ em_utils_uids_free (selected);
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_mail_delete_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
+ guint32 set = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
+
+ if (!e_mail_reader_confirm_delete (reader))
+ return;
+
+ /* FIXME Verify all selected messages are deletable.
+ * But handle it by disabling this action. */
+
+ if (e_mail_reader_mark_selected (reader, mask, set) == 1)
+ e_mail_reader_select_next_message (reader, FALSE);
+}
+
+static void
+action_mail_filter_on_mailing_list_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_filter_from_selected (reader, AUTO_MLIST);
+}
+
+static void
+action_mail_filter_on_recipients_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_filter_from_selected (reader, AUTO_TO);
+}
+
+static void
+action_mail_filter_on_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_filter_from_selected (reader, AUTO_FROM);
+}
+
+static void
+action_mail_filter_on_subject_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_filter_from_selected (reader, AUTO_SUBJECT);
+}
+
+static void
+action_mail_filters_apply_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ mail_filter_on_demand (folder, uids);
+}
+
+static void
+action_mail_find_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_show_search_bar (reader);
+}
+
+static void
+action_mail_flag_clear_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_flag_for_followup_clear (window, folder, uids);
+
+ em_format_redraw (EM_FORMAT (html_display));
+}
+
+static void
+action_mail_flag_completed_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_flag_for_followup_completed (window, folder, uids);
+
+ em_format_redraw (EM_FORMAT (html_display));
+}
+
+static void
+action_mail_flag_for_followup_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_flag_for_followup (window, folder, uids);
+}
+
+static void
+action_mail_forward_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_forward_messages (folder, uids, folder_uri);
+}
+
+static void
+action_mail_forward_attached_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_forward_attached (folder, uids, folder_uri);
+}
+
+static void
+action_mail_forward_inline_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_forward_inline (folder, uids, folder_uri);
+}
+
+static void
+action_mail_forward_quoted_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_forward_quoted (folder, uids, folder_uri);
+}
+
+static void
+action_mail_load_images_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+
+ html_display = e_mail_reader_get_html_display (reader);
+
+ em_format_html_load_images (EM_FORMAT_HTML (html_display));
+}
+
+static void
+action_mail_mark_important_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_DELETED;
+ guint32 set = CAMEL_MESSAGE_FLAGGED;
+
+ e_mail_reader_mark_selected (reader, mask, set);
+}
+
+static void
+action_mail_mark_junk_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_JUNK |
+ CAMEL_MESSAGE_NOTJUNK | CAMEL_MESSAGE_JUNK_LEARN;
+ guint32 set = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_JUNK |
+ CAMEL_MESSAGE_JUNK_LEARN;
+
+ if (e_mail_reader_mark_selected (reader, mask, set) == 1)
+ e_mail_reader_select_next_message (reader, TRUE);
+}
+
+static void
+action_mail_mark_notjunk_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_NOTJUNK |
+ CAMEL_MESSAGE_JUNK_LEARN;
+ guint32 set = CAMEL_MESSAGE_NOTJUNK | CAMEL_MESSAGE_JUNK_LEARN;
+
+ if (e_mail_reader_mark_selected (reader, mask, set) == 1)
+ e_mail_reader_select_next_message (reader, TRUE);
+}
+
+static void
+action_mail_mark_read_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_SEEN;
+ guint32 set = CAMEL_MESSAGE_SEEN;
+
+ e_mail_reader_mark_selected (reader, mask, set);
+}
+
+static void
+action_mail_mark_unimportant_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_FLAGGED;
+ guint32 set = 0;
+
+ e_mail_reader_mark_selected (reader, mask, set);
+}
+
+static void
+action_mail_mark_unread_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ guint32 mask = CAMEL_MESSAGE_SEEN | CAMEL_MESSAGE_DELETED;
+ guint32 set = 0;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ e_mail_reader_mark_selected (reader, mask, set);
+
+ if (message_list->seen_id != 0) {
+ g_source_remove (message_list->seen_id);
+ message_list->seen_id = 0;
+ }
+}
+
+static void
+action_mail_message_edit_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ window = e_mail_reader_get_window (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_edit_messages (folder, uids, FALSE);
+}
+
+static void
+action_mail_message_new_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ GtkWindow *window;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ em_utils_compose_new_message (message_list->folder_uri);
+}
+
+static void
+action_mail_message_open_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_open_selected (reader);
+}
+
+static void
+action_mail_move_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EShellBackend *shell_backend;
+ MessageList *message_list;
+ EMFolderTreeModel *model;
+ CamelFolder *folder;
+ GtkWidget *folder_tree;
+ GtkWidget *dialog;
+ GPtrArray *selected;
+ const gchar *uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ model = e_mail_shell_backend_get_folder_tree_model (
+ E_MAIL_SHELL_BACKEND (shell_backend));
+
+ folder_tree = em_folder_tree_new_with_model (model);
+ selected = message_list_get_selected (message_list);
+
+ folder = message_list->folder;
+
+ em_folder_tree_set_excluded (
+ EM_FOLDER_TREE (folder_tree),
+ EMFT_EXCLUDE_NOSELECT | EMFT_EXCLUDE_VIRTUAL |
+ EMFT_EXCLUDE_VTRASH);
+
+ dialog = em_folder_selector_new (
+ EM_FOLDER_TREE (folder_tree),
+ EM_FOLDER_SELECTOR_CAN_CREATE,
+ _("Select Folder"), NULL, _("C_opy"));
+
+ if (default_xfer_messages_uri != NULL)
+ em_folder_selector_set_selected (
+ EM_FOLDER_SELECTOR (dialog),
+ default_xfer_messages_uri);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ uri = em_folder_selector_get_selected_uri (
+ EM_FOLDER_SELECTOR (dialog));
+
+ g_free (default_xfer_messages_uri);
+ default_xfer_messages_uri = g_strdup (uri);
+
+ if (uri != NULL) {
+ mail_transfer_messages (
+ folder, selected, TRUE, uri, 0, NULL, NULL);
+ selected = NULL;
+ }
+
+exit:
+ if (selected != NULL)
+ em_utils_uids_free (selected);
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_mail_next_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_NEXT;
+ flags = 0;
+ mask = 0;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_next_important_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_NEXT | MESSAGE_LIST_SELECT_WRAP;
+ flags = CAMEL_MESSAGE_FLAGGED;
+ mask = CAMEL_MESSAGE_FLAGGED;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_next_thread_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select_next_thread (message_list);
+}
+
+static void
+action_mail_next_unread_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_NEXT | MESSAGE_LIST_SELECT_WRAP;
+ flags = 0;
+ mask = CAMEL_MESSAGE_SEEN;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_previous_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_PREVIOUS;
+ flags = 0;
+ mask = 0;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_previous_important_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_PREVIOUS | MESSAGE_LIST_SELECT_WRAP;
+ flags = CAMEL_MESSAGE_FLAGGED;
+ mask = CAMEL_MESSAGE_FLAGGED;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_previous_unread_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ MessageListSelectDirection direction;
+ guint32 flags, mask;
+
+ direction = MESSAGE_LIST_SELECT_PREVIOUS | MESSAGE_LIST_SELECT_WRAP;
+ flags = 0;
+ mask = CAMEL_MESSAGE_SEEN;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select (message_list, direction, flags, mask);
+}
+
+static void
+action_mail_print_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ GtkPrintOperationAction print_action;
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG;
+ e_mail_reader_print (reader, print_action);
+}
+
+static void
+action_mail_print_preview_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ GtkPrintOperationAction print_action;
+
+ print_action = GTK_PRINT_OPERATION_ACTION_PREVIEW;
+ e_mail_reader_print (reader, print_action);
+}
+
+static void
+action_mail_redirect_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ const gchar *uid;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uid = message_list->cursor_uid;
+ g_return_if_fail (uid != NULL);
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ em_utils_redirect_message_by_uid (folder, uid);
+}
+
+static void
+action_mail_reply_all_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_reply_to_message (reader, REPLY_MODE_ALL);
+}
+
+static void
+action_mail_reply_list_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_reply_to_message (reader, REPLY_MODE_LIST);
+}
+
+static void
+action_mail_reply_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_reply_to_message (reader, REPLY_MODE_SENDER);
+}
+
+static void
+action_mail_save_as_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWindow *window;
+ GPtrArray *uids;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ window = e_mail_reader_get_window (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ em_utils_save_messages (window, folder, uids);
+}
+
+static void
+action_mail_search_folder_from_mailing_list_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_vfolder_from_selected (reader, AUTO_MLIST);
+}
+
+static void
+action_mail_search_folder_from_recipients_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_vfolder_from_selected (reader, AUTO_TO);
+}
+
+static void
+action_mail_search_folder_from_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_vfolder_from_selected (reader, AUTO_FROM);
+}
+
+static void
+action_mail_search_folder_from_subject_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ e_mail_reader_create_vfolder_from_selected (reader, AUTO_SUBJECT);
+}
+
+static void
+action_mail_select_all_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+ const gchar *action_name;
+ gboolean selection_active;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_select_all (html);
+
+ action_name = "mail-clipboard-copy";
+ action = e_mail_reader_get_action (reader, action_name);
+ selection_active = gtk_html_command (html, "is-selection-active");
+ gtk_action_set_sensitive (action, selection_active);
+}
+
+static void
+action_mail_show_all_headers_cb (GtkToggleAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ em_format_mode_t mode;
+
+ html_display = e_mail_reader_get_html_display (reader);
+
+ if (gtk_toggle_action_get_active (action))
+ mode = EM_FORMAT_ALLHEADERS;
+ else
+ mode = EM_FORMAT_NORMAL;
+
+ em_format_set_mode (EM_FORMAT (html_display), mode);
+}
+
+static void
+action_mail_show_source_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ EMailShellBackend *mail_shell_backend;
+ EShellBackend *shell_backend;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkWidget *browser;
+ GPtrArray *uids;
+ const gchar *folder_uri;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
+
+ folder = message_list->folder;
+ folder_uri = message_list->folder_uri;
+ uids = message_list_get_selected (message_list);
+ g_return_if_fail (uids->len > 0);
+
+ browser = e_mail_browser_new (mail_shell_backend);
+ reader = E_MAIL_READER (browser);
+ html_display = e_mail_reader_get_html_display (reader);
+ em_format_set_mode (EM_FORMAT (html_display), EM_FORMAT_SOURCE);
+ e_mail_reader_set_folder (reader, folder, folder_uri);
+ e_mail_reader_set_message (reader, uids->pdata[0], FALSE);
+ gtk_widget_show (browser);
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_toggle_important_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+ guint ii;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder = message_list->folder;
+ uids = message_list_get_selected (message_list);
+
+ camel_folder_freeze (folder);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ guint32 flags;
+
+ flags = camel_folder_get_message_flags (
+ folder, uids->pdata[ii]);
+ flags ^= CAMEL_MESSAGE_FLAGGED;
+ if (flags & CAMEL_MESSAGE_FLAGGED)
+ flags &= ~CAMEL_MESSAGE_DELETED;
+ camel_folder_set_message_flags (
+ folder, uids->pdata[ii], CAMEL_MESSAGE_FLAGGED |
+ CAMEL_MESSAGE_DELETED, flags);
+ }
+
+ camel_folder_thaw (folder);
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_undelete_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ guint32 mask = CAMEL_MESSAGE_DELETED;
+ guint32 set = 0;
+
+ e_mail_reader_mark_selected (reader, mask, set);
+}
+
+static void
+action_mail_uri_copy_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ /* FIXME */
+ g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
+}
+
+static void
+action_mail_uri_copy_address_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ /* FIXME */
+ g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
+}
+
+static void
+action_mail_uri_to_search_folder_recipient_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ /* FIXME */
+ g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
+}
+
+static void
+action_mail_uri_to_search_folder_sender_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ /* FIXME */
+ g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
+}
+
+static void
+action_mail_zoom_100_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_zoom_reset (html);
+}
+
+static void
+action_mail_zoom_in_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_zoom_out (html);
+}
+
+static void
+action_mail_zoom_out_cb (GtkAction *action,
+ EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ GtkHTML *html;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ gtk_html_zoom_out (html);
+}
+
+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-check-for-junk",
+ "mail-mark-junk",
+ N_("Check for _Junk"),
+ NULL,
+ N_("Filter the selected messages for junk status"),
+ G_CALLBACK (action_mail_check_for_junk_cb) },
+
+ { "mail-clipboard-copy",
+ GTK_STOCK_COPY,
+ NULL,
+ NULL,
+ N_("Copy selected messages to the clipboard"),
+ G_CALLBACK (action_mail_clipboard_copy_cb) },
+
+ { "mail-copy",
+ "mail-copy",
+ N_("_Copy to Folder..."),
+ "<Shift><Control>y",
+ N_("Copy selected messages to another folder"),
+ G_CALLBACK (action_mail_copy_cb) },
+
+ { "mail-delete",
+ "user-trash",
+ N_("_Delete Message"),
+ "<Control>d",
+ N_("Mark the selected messages for deletion"),
+ G_CALLBACK (action_mail_delete_cb) },
+
+ { "mail-filter-on-mailing-list",
+ NULL,
+ N_("Filter on 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-on-recipients",
+ NULL,
+ N_("Filter on _Recipients..."),
+ NULL,
+ N_("Create a rule to filter messages to these recipients"),
+ G_CALLBACK (action_mail_filter_on_recipients_cb) },
+
+ { "mail-filter-on-sender",
+ NULL,
+ N_("Filter on Se_nder..."),
+ NULL,
+ N_("Create a rule to filter messages from this sender"),
+ G_CALLBACK (action_mail_filter_on_sender_cb) },
+
+ { "mail-filter-on-subject",
+ NULL,
+ N_("Filter on _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"),
+ "<Control>y",
+ N_("Apply filter rules to the selected messages"),
+ G_CALLBACK (action_mail_filters_apply_cb) },
+
+ { "mail-find",
+ GTK_STOCK_FIND,
+ N_("_Find in Message..."),
+ "<Shift><Control>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..."),
+ "<Shift><Control>g",
+ N_("Flag the selected messages for follow-up"),
+ G_CALLBACK (action_mail_flag_for_followup_cb) },
+
+ { "mail-forward",
+ "mail-forward",
+ N_("_Forward"),
+ "<Control>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-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-quoted",
+ NULL,
+ N_("_Quoted"),
+ NULL,
+ N_("Forward the selected message quoted like a reply"),
+ G_CALLBACK (action_mail_forward_quoted_cb) },
+
+ { "mail-load-images",
+ "image-x-generic",
+ N_("_Load Images"),
+ "<Control>i",
+ N_("Force images in HTML mail to be loaded"),
+ G_CALLBACK (action_mail_load_images_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"),
+ "<Control>j",
+ N_("Mark the selected messages as junk"),
+ G_CALLBACK (action_mail_mark_junk_cb) },
+
+ { "mail-mark-notjunk",
+ "mail-mark-notjunk",
+ N_("_Not Junk"),
+ "<Shift><Control>j",
+ N_("Mark the selected messasges as not being junk"),
+ G_CALLBACK (action_mail_mark_notjunk_cb) },
+
+ { "mail-mark-read",
+ "mail-mark-read",
+ N_("_Read"),
+ "<Control>k",
+ N_("Mark the selected messages as having been read"),
+ G_CALLBACK (action_mail_mark_read_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"),
+ "<Shift><Control>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"),
+ "<Shift><Control>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"),
+ "<Control>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..."),
+ "<Shift><Control>v",
+ N_("Move selected messages to another folder"),
+ G_CALLBACK (action_mail_move_cb) },
+
+ { "mail-next",
+ GTK_STOCK_GO_FORWARD,
+ N_("_Next Message"),
+ "<Control>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",
+ NULL,
+ N_("Next _Unread Message"),
+ "<Control>bracketright",
+ N_("Display the next unread message"),
+ G_CALLBACK (action_mail_next_unread_cb) },
+
+ { "mail-previous",
+ GTK_STOCK_GO_BACK,
+ N_("_Previous Message"),
+ "<Control>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-unread",
+ NULL,
+ N_("P_revious Unread Message"),
+ "<Control>bracketleft",
+ N_("Display the previous unread message"),
+ G_CALLBACK (action_mail_previous_unread_cb) },
+
+ { "mail-print",
+ GTK_STOCK_PRINT,
+ NULL,
+ "<Control>p",
+ N_("Print this message"),
+ G_CALLBACK (action_mail_print_cb) },
+
+ { "mail-print-preview",
+ GTK_STOCK_PRINT_PREVIEW,
+ NULL,
+ 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-reply-all",
+ "mail-reply-all",
+ N_("Reply to _All"),
+ "<Shift><Control>r",
+ N_("Compose a reply to all the recipients of the selected message"),
+ G_CALLBACK (action_mail_reply_all_cb) },
+
+ { "mail-reply-list",
+ NULL,
+ N_("Reply to _List"),
+ "<Control>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"),
+ "<Control>r",
+ N_("Compose a reply to the sender of the selected message"),
+ G_CALLBACK (action_mail_reply_sender_cb) },
+
+ { "mail-save-as",
+ GTK_STOCK_SAVE_AS,
+ N_("_Save as mbox..."),
+ NULL,
+ N_("Save selected messages as an mbox file"),
+ G_CALLBACK (action_mail_save_as_cb) },
+
+ { "mail-search-folder-from-mailing-list",
+ NULL,
+ N_("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_("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_("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_("Search Folder from S_ubject..."),
+ NULL,
+ N_("Create a search folder for this subject"),
+ G_CALLBACK (action_mail_search_folder_from_subject_cb) },
+
+ { "mail-select-all",
+ NULL,
+ N_("Select _All Text"),
+ "<Shift><Control>x",
+ N_("Select all the text in a message"),
+ G_CALLBACK (action_mail_select_all_cb) },
+
+ { "mail-show-source",
+ NULL,
+ N_("_Message Source"),
+ "<Control>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"),
+ "<Shift><Control>d",
+ N_("Undelete the selected messages"),
+ G_CALLBACK (action_mail_undelete_cb) },
+
+ { "mail-uri-copy",
+ NULL,
+ N_("_Copy Link Location"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_uri_copy_cb) },
+
+ { "mail-uri-copy-address",
+ GTK_STOCK_COPY,
+ N_("Copy _Email Address"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_uri_copy_address_cb) },
+
+ { "mail-uri-to-search-folder-recipient",
+ NULL,
+ N_("_To This Address"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_uri_to_search_folder_recipient_cb) },
+
+ { "mail-uri-to-search-folder-sender",
+ NULL,
+ N_("_From This Address"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_uri_to_search_folder_sender_cb) },
+
+ { "mail-zoom-100",
+ GTK_STOCK_ZOOM_100,
+ N_("_Normal Size"),
+ "<Control>0",
+ N_("Reset the text to its original size"),
+ G_CALLBACK (action_mail_zoom_100_cb) },
+
+ { "mail-zoom-in",
+ GTK_STOCK_ZOOM_IN,
+ N_("_Zoom In"),
+ "<Control>plus",
+ N_("Increase the text size"),
+ G_CALLBACK (action_mail_zoom_in_cb) },
+
+ { "mail-zoom-out",
+ GTK_STOCK_ZOOM_OUT,
+ N_("Zoom _Out"),
+ "<Control>minus",
+ N_("Decrease the text size"),
+ G_CALLBACK (action_mail_zoom_out_cb) },
+
+ /*** Menus ***/
+
+ { "mail-create-rule-menu",
+ NULL,
+ N_("Create R_ule"),
+ 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-goto-menu",
+ GTK_STOCK_JUMP_TO,
+ 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-uri-to-search-folder-menu",
+ NULL,
+ N_("Create _Search Folder"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-zoom-menu",
+ NULL,
+ N_("_Zoom"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry mail_reader_popup_entries[] = {
+
+ { "mail-popup-copy",
+ NULL,
+ "mail-copy" },
+
+ { "mail-popup-delete",
+ NULL,
+ "mail-delete" },
+
+ { "mail-popup-flag-for-followup",
+ N_("Mark for Follo_w Up..."),
+ "mail-flag-for-followup" },
+
+ { "mail-popup-forward",
+ NULL,
+ "mail-forward" },
+
+ { "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_("Mark as _Read"),
+ "mail-mark-read" },
+
+ { "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-reply-all",
+ NULL,
+ "mail-reply-all" },
+
+ { "mail-popup-reply-sender",
+ NULL,
+ "mail-reply-sender" },
+
+ { "mail-popup-save-as",
+ NULL,
+ "mail-save-as" },
+
+ { "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 gboolean
+mail_reader_html_button_release_event_cb (EMailReader *reader,
+ GdkEventButton *button,
+ GtkHTML *html)
+{
+ GtkAction *action;
+ const gchar *action_name;
+ gboolean selection_active;
+
+ action_name = "mail-clipboard-copy";
+ action = e_mail_reader_get_action (reader, action_name);
+ selection_active = gtk_html_command (html, "is-selection-active");
+ gtk_action_set_sensitive (action, selection_active);
+
+ return FALSE;
+}
+
+static void
+mail_reader_double_click_cb (EMailReader *reader,
+ gint row,
+ ETreePath path,
+ gint col,
+ GdkEvent *event)
+{
+ /* Ignore double clicks on columns that handle their own state. */
+ if (MESSAGE_LIST_COLUMN_IS_ACTIVE (col))
+ return;
+
+ e_mail_reader_activate (reader, "mail-message-open");
+}
+
+static gboolean
+mail_reader_key_press_event_cb (EMailReader *reader,
+ GdkEventKey *event)
+{
+ const gchar *action_name;
+
+ if ((event->state & GDK_CONTROL_MASK) != 0)
+ goto ctrl;
+
+ /* <keyval> alone */
+ switch (event->keyval) {
+ case GDK_Delete:
+ case GDK_KP_Delete:
+ action_name = "mail-delete";
+ break;
+
+ case GDK_Return:
+ case GDK_KP_Enter:
+ case GDK_ISO_Enter:
+ action_name = "mail-message-open";
+ break;
+
+ case GDK_period:
+ action_name = "mail-next-unread";
+ break;
+
+ case GDK_comma:
+ 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 '!':
+ action_name = "mail-toggle-important";
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ goto exit;
+
+ctrl:
+
+ /* Ctrl + <keyval> */
+ switch (event->keyval) {
+ case GDK_period:
+ action_name = "mail-next-unread";
+ break;
+
+ case GDK_comma:
+ action_name = "mail-previous-unread";
+ break;
+
+ default:
+ return FALSE;
+ }
+
+exit:
+ e_mail_reader_activate (reader, action_name);
+
+ 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);
+}
+
+static gboolean
+mail_reader_message_read_cb (EMailReader *reader)
+{
+ MessageList *message_list;
+ const gchar *uid;
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ uid = g_object_get_data (G_OBJECT (reader), "mark-read-uid");
+ g_return_val_if_fail (uid != NULL, FALSE);
+
+ if (g_strcmp0 (message_list->cursor_uid, uid) == 0)
+ e_mail_reader_mark_as_read (reader, uid);
+
+ return FALSE;
+}
+
+static void
+mail_reader_message_loaded_cb (CamelFolder *folder,
+ const gchar *message_uid,
+ CamelMimeMessage *message,
+ gpointer user_data,
+ CamelException *ex)
+{
+ EMailReader *reader = user_data;
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ EShellBackend *shell_backend;
+ EShellSettings *shell_settings;
+ EShell *shell;
+ EMEvent *event;
+ EMEventTargetMessage *target;
+ gboolean mark_read;
+ gint timeout_interval;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ /* If the user picked a different message in the time it took
+ * to fetch this message, then don't bother rendering it. */
+ if (g_strcmp0 (message_list->cursor_uid, message_uid) != 0)
+ return;
+
+ /** @Event: message.reading
+ * @Title: Viewing a message
+ * @Target: EMEventTargetMessage
+ *
+ * message.reading is emitted whenever a user views a message.
+ */
+ event = em_event_peek ();
+ target = em_event_target_new_message (
+ event, folder, message, message_uid, 0);
+ e_event_emit (
+ (EEvent *) event, "message.reading",
+ (EEventTarget *) target);
+
+ em_format_format (
+ EM_FORMAT (html_display), folder, message_uid, message);
+
+ /* Reset the shell view icon. */
- e_shell_event (shell, "mail-icon", "evolution-mail");
++ e_shell_event (shell, "mail-icon", (gpointer) "evolution-mail");
+
+ /* Determine whether to mark the message as read. */
+ mark_read = e_shell_settings_get_boolean (
+ shell_settings, "mail-mark-seen");
+ timeout_interval = e_shell_settings_get_int (
+ shell_settings, "mail-mark-seen-timeout");
+
+ g_object_set_data_full (
+ G_OBJECT (reader), "mark-read-uid",
+ g_strdup (message_uid), (GDestroyNotify) g_free);
+
+ if (message_list->seen_id > 0)
+ g_source_remove (message_list->seen_id);
+
+ if (mark_read) {
+ message_list->seen_id = g_timeout_add (
+ timeout_interval, (GSourceFunc)
+ mail_reader_message_read_cb, reader);
+
+ } else if (camel_exception_is_set (ex)) {
+ GtkHTMLStream *stream;
+
+ /* Display the error inline and clear the exception. */
+ stream = gtk_html_begin (
+ EM_FORMAT_HTML (html_display)->html);
+ gtk_html_stream_printf (
+ stream, "<h2>%s</h2><p>%s</p>",
+ _("Unable to retrieve message"),
+ ex->desc);
+ gtk_html_stream_close (stream, GTK_HTML_STREAM_OK);
+ camel_exception_clear (ex);
+ }
+
+ e_mail_reader_update_actions (reader);
+
+ /* We referenced this in the call to mail_get_messagex(). */
+ g_object_unref (reader);
+}
+
+static gboolean
+mail_reader_message_selected_timeout_cb (EMailReader *reader)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ const gchar *cursor_uid;
+ const gchar *format_uid;
+ const gchar *key;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ cursor_uid = message_list->cursor_uid;
+ format_uid = EM_FORMAT (html_display)->uid;
+
+ if (cursor_uid != NULL) {
+ if (g_strcmp0 (cursor_uid, format_uid) != 0)
+ mail_get_messagex (
+ message_list->folder, cursor_uid,
+ mail_reader_message_loaded_cb,
+ g_object_ref (reader),
+ mail_msg_fast_ordered_push);
+ } else
+ em_format_format (EM_FORMAT (html_display), NULL, NULL, NULL);
+
+ key = "message-selected-timeout";
+ g_object_set_data (G_OBJECT (reader), key, NULL);
+
+ return FALSE;
+}
+
+static void
+mail_reader_message_selected_cb (EMailReader *reader,
+ const gchar *uid)
+{
+ const gchar *key;
+ guint source_id;
+ gpointer data;
+
+ /* XXX This is kludgy, but we have no other place to store
+ * timeout state information. */
+
+ key = "message-selected-timeout";
+ data = g_object_get_data (G_OBJECT (reader), key);
+ source_id = GPOINTER_TO_UINT (data);
+
+ if (source_id > 0)
+ g_source_remove (source_id);
+
+ source_id = g_timeout_add (
+ 100, (GSourceFunc)
+ mail_reader_message_selected_timeout_cb, reader);
+
+ data = GUINT_TO_POINTER (source_id);
+ g_object_set_data (G_OBJECT (reader), key, data);
+
+ e_mail_reader_changed (reader);
+}
+
+static void
+mail_reader_emit_folder_loaded (EMailReader *reader)
+{
+ g_signal_emit (reader, signals[FOLDER_LOADED], 0);
+}
+
+static void
+mail_reader_set_folder (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *folder_uri)
+{
+ EMFormatHTMLDisplay *html_display;
+ MessageList *message_list;
+ gboolean outgoing;
+
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ outgoing = folder != NULL && folder_uri != NULL && (
+ em_utils_folder_is_drafts (folder, folder_uri) ||
+ em_utils_folder_is_outbox (folder, folder_uri) ||
+ em_utils_folder_is_sent (folder, folder_uri));
+
+ if (message_list->folder != NULL)
+ mail_sync_folder (message_list->folder, NULL, NULL);
+
+ em_format_format (EM_FORMAT (html_display), NULL, NULL, NULL);
+ message_list_set_folder (message_list, folder, folder_uri, outgoing);
+
+ mail_reader_emit_folder_loaded (reader);
+}
+
+static void
+mail_reader_set_message (EMailReader *reader,
+ const gchar *uid,
+ gboolean mark_read)
+{
+ MessageList *message_list;
+
+ message_list = e_mail_reader_get_message_list (reader);
+ message_list_select_uid (message_list, uid);
+}
+
+static void
+mail_reader_init_charset_actions (EMailReader *reader)
+{
+ GtkActionGroup *action_group;
+ GtkRadioAction *default_action;
+ GSList *radio_group;
+
+ action_group = e_mail_reader_get_action_group (reader);
+
+ 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
+mail_reader_class_init (EMailReaderIface *iface)
+{
+ iface->set_folder = mail_reader_set_folder;
+ iface->set_message = mail_reader_set_message;
+
+ signals[CHANGED] = g_signal_new (
+ "changed",
+ G_OBJECT_CLASS_TYPE (iface),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[FOLDER_LOADED] = g_signal_new (
+ "folder-loaded",
+ G_OBJECT_CLASS_TYPE (iface),
+ G_SIGNAL_RUN_FIRST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[SHOW_SEARCH_BAR] = g_signal_new (
+ "show-search-bar",
+ G_OBJECT_CLASS_TYPE (iface),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EMailReaderIface, show_search_bar),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+GType
+e_mail_reader_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EMailReaderIface),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_reader_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ 0, /* instance_size */
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_INTERFACE, "EMailReader", &type_info, 0);
+
+ g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ }
+
+ return type;
+}
+
+void
+e_mail_reader_init (EMailReader *reader)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+ EShellSettings *shell_settings;
+ EMFormatHTMLDisplay *html_display;
+ GtkActionGroup *action_group;
+ MessageList *message_list;
+ GConfBridge *bridge;
+ GtkAction *action;
+ GtkHTML *html;
+ const gchar *action_name;
+ const gchar *key;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ action_group = e_mail_reader_get_action_group (reader);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ 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);
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ action_name = "mail-caret-mode";
+ key = "/apps/evolution/mail/display/caret_mode";
+ action = e_mail_reader_get_action (reader, action_name);
+ gconf_bridge_bind_property (bridge, key, G_OBJECT (action), "active");
+
+ action_name = "mail-show-all-headers";
+ key = "/apps/evolution/mail/display/show_all_headers";
+ action = e_mail_reader_get_action (reader, action_name);
+ gconf_bridge_bind_property (bridge, key, G_OBJECT (action), "active");
+
+ /* Fine tuning. */
+
+ action_name = "mail-clipboard-copy";
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, FALSE);
+
+ action_name = "mail-delete";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_object_set (action, "short-label", _("Delete"), NULL);
+
+ action_name = "mail-next";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_object_set (action, "short-label", _("Next"), NULL);
+
+ action_name = "mail-previous";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_object_set (action, "short-label", _("Previous"), NULL);
+
+ action_name = "mail-reply-sender";
+ action = e_mail_reader_get_action (reader, action_name);
+ g_object_set (action, "short-label", _("Reply"), NULL);
+
+ /* Bind properties. */
+
+ e_binding_new_full (
+ G_OBJECT (shell_settings), "mail-citation-color",
+ G_OBJECT (html_display), "citation-color",
+ e_binding_transform_string_to_color,
+ NULL, NULL);
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-image-loading-policy",
+ G_OBJECT (html_display), "image-loading-policy");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-only-local-photos",
+ G_OBJECT (html_display), "only-local-photos");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-show-animated-images",
+ G_OBJECT (html), "animate");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "mail-show-sender-photo",
+ G_OBJECT (html_display), "show-sender-photo");
+
+ action_name = "mail-caret-mode";
+ action = e_mail_reader_get_action (reader, action_name);
+
+ e_mutual_binding_new (
+ G_OBJECT (action), "active",
+ G_OBJECT (html), "caret-mode");
+
+ /* Connect signals. */
+
+ g_signal_connect_swapped (
+ html, "button-release-event",
+ G_CALLBACK (mail_reader_html_button_release_event_cb), reader);
+
+ g_signal_connect_swapped (
+ html, "key-press-event",
+ G_CALLBACK (mail_reader_key_press_event_cb), reader);
+
+ g_signal_connect_swapped (
+ message_list, "message-selected",
+ G_CALLBACK (mail_reader_message_selected_cb), reader);
+
+ g_signal_connect_swapped (
+ message_list, "message-list-built",
+ G_CALLBACK (mail_reader_emit_folder_loaded), reader);
+
+ g_signal_connect_swapped (
+ message_list->tree, "double-click",
+ G_CALLBACK (mail_reader_double_click_cb), reader);
+
+ g_signal_connect_swapped (
+ message_list->tree, "key-press",
+ G_CALLBACK (mail_reader_key_press_cb), reader);
+
+ g_signal_connect_swapped (
+ message_list->tree, "selection-change",
+ G_CALLBACK (e_mail_reader_changed), reader);
+}
+
+void
+e_mail_reader_changed (EMailReader *reader)
+{
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ g_signal_emit (reader, signals[CHANGED], 0);
+}
+
+guint32
+e_mail_reader_check_state (EMailReader *reader)
+{
+ MessageList *message_list;
+ GPtrArray *uids;
+ CamelFolder *folder;
+ CamelStore *store = NULL;
+ const gchar *folder_uri;
+ const gchar *tag;
+ gboolean can_clear_flags = FALSE;
+ gboolean can_flag_completed = FALSE;
+ gboolean can_flag_for_followup = FALSE;
+ gboolean has_deleted = FALSE;
+ gboolean has_important = FALSE;
+ gboolean has_junk = FALSE;
+ gboolean has_not_junk = FALSE;
+ gboolean has_read = FALSE;
+ gboolean has_undeleted = FALSE;
+ gboolean has_unimportant = FALSE;
+ gboolean has_unread = FALSE;
+ gboolean drafts_or_outbox;
+ gboolean store_supports_vjunk = FALSE;
+ guint32 state = 0;
+ guint ii;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), 0);
+
+ message_list = e_mail_reader_get_message_list (reader);
+ uids = message_list_get_selected (message_list);
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ if (folder != NULL) {
+ store = CAMEL_STORE (folder->parent_store);
+ store_supports_vjunk = (store->flags & CAMEL_STORE_VJUNK);
+ }
+
+ drafts_or_outbox =
+ em_utils_folder_is_drafts (folder, folder_uri) ||
+ em_utils_folder_is_outbox (folder, folder_uri);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ CamelMessageInfo *info;
+ guint32 flags;
+
+ info = camel_folder_get_message_info (
+ folder, uids->pdata[ii]);
+ if (info == NULL)
+ continue;
+
+ flags = camel_message_info_flags (info);
+
+ if (flags & CAMEL_MESSAGE_SEEN)
+ has_read = TRUE;
+ else
+ has_unread = TRUE;
+
+ if (drafts_or_outbox) {
+ has_junk = FALSE;
+ has_not_junk = FALSE;
+ } else if (store_supports_vjunk) {
+ guint32 bitmask;
+
+ /* XXX Strictly speaking, this logic is correct.
+ * Problem is there's nothing in the message
+ * list that indicates whether a message is
+ * already marked "Not Junk". So the user may
+ * think the "Not Junk" button is enabling and
+ * disabling itself randomly as he reads mail. */
+
+ if (flags & CAMEL_MESSAGE_JUNK)
+ has_junk = TRUE;
+ if (flags & CAMEL_MESSAGE_NOTJUNK)
+ has_not_junk = TRUE;
+
+ bitmask = CAMEL_MESSAGE_JUNK | CAMEL_MESSAGE_NOTJUNK;
+
+ /* If neither junk flag is set, the
+ * message can be marked either way. */
+ if ((flags & bitmask) == 0) {
+ has_junk = TRUE;
+ has_not_junk = TRUE;
+ }
+
+ } else {
+ has_junk = TRUE;
+ has_not_junk = TRUE;
+ }
+
+ if (flags & CAMEL_MESSAGE_DELETED)
+ has_deleted = TRUE;
+ else
+ has_undeleted = TRUE;
+
+ if (flags & CAMEL_MESSAGE_FLAGGED)
+ has_important = TRUE;
+ else
+ has_unimportant = TRUE;
+
+ tag = camel_message_info_user_tag (info, "follow-up");
+ if (tag != NULL && *tag != '\0') {
+ can_clear_flags = TRUE;
+ tag = camel_message_info_user_tag (
+ info, "completed-on");
+ if (tag != NULL && *tag != '\0')
+ can_flag_completed = TRUE;
+ } else
+ can_flag_for_followup = TRUE;
+ }
+
+ if (uids->len == 1)
+ state |= E_MAIL_READER_SELECTION_SINGLE;
+ if (uids->len > 1)
+ state |= E_MAIL_READER_SELECTION_MULTIPLE;
+ if (!drafts_or_outbox && uids->len == 1)
+ state |= E_MAIL_READER_SELECTION_CAN_ADD_SENDER;
+#if 0 /* FIXME */
+ if (can_edit)
+ state |= E_MAIL_READER_SELECTION_CAN_EDIT;
+#endif
+ if (can_clear_flags)
+ state |= E_MAIL_READER_SELECTION_FLAG_CLEAR;
+ if (can_flag_completed)
+ state |= E_MAIL_READER_SELECTION_FLAG_COMPLETED;
+ if (can_flag_for_followup)
+ state |= E_MAIL_READER_SELECTION_FLAG_FOLLOWUP;
+ if (has_deleted)
+ state |= E_MAIL_READER_SELECTION_HAS_DELETED;
+ if (has_important)
+ state |= E_MAIL_READER_SELECTION_HAS_IMPORTANT;
+ if (has_junk)
+ state |= E_MAIL_READER_SELECTION_HAS_JUNK;
+ if (has_not_junk)
+ state |= E_MAIL_READER_SELECTION_HAS_NOT_JUNK;
+ if (has_read)
+ state |= E_MAIL_READER_SELECTION_HAS_READ;
+ if (has_undeleted)
+ state |= E_MAIL_READER_SELECTION_HAS_UNDELETED;
+ if (has_unimportant)
+ state |= E_MAIL_READER_SELECTION_HAS_UNIMPORTANT;
+ if (has_unread)
+ state |= E_MAIL_READER_SELECTION_HAS_UNREAD;
+#if 0 /* FIXME */
+ if (has_callto_uri)
+ state |= E_MAIL_READER_SELECTION_HAS_URI_CALLTO;
+ if (has_http_uri)
+ state |= E_MAIL_READER_SELECTION_HAS_URI_HTTP;
+ if (has_mailto_uri)
+ state |= E_MAIL_READER_SELECTION_HAS_URI_MAILTO;
+ if (is_mailing_list)
+ state |= E_MAIL_READER_SELECTION_IS_MAILING_LIST;
+#endif
+
+ em_utils_uids_free (uids);
+
+ return state;
+
+}
+
+void
+e_mail_reader_update_actions (EMailReader *reader)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+ EShellSettings *shell_settings;
+ GtkAction *action;
+ GtkActionGroup *action_group;
+ const gchar *action_name;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean any_messages_selected;
+ gboolean disable_printing;
+ gboolean enable_flag_clear;
+ gboolean enable_flag_completed;
+ gboolean enable_flag_for_followup;
+ gboolean single_message_selected;
+ gboolean multiple_messages_selected;
+ gboolean selection_has_deleted_messages;
+ gboolean selection_has_important_messages;
+ gboolean selection_has_junk_messages;
+ gboolean selection_has_not_junk_messages;
+ gboolean selection_has_read_messages;
+ gboolean selection_has_undeleted_messages;
+ gboolean selection_has_unimportant_messages;
+ gboolean selection_has_unread_messages;
+ gboolean selection_is_mailing_list;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ action_group = e_mail_reader_get_action_group (reader);
+ state = e_mail_reader_check_state (reader);
+
+ shell_backend = e_mail_reader_get_shell_backend (reader);
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ disable_printing = e_shell_settings_get_boolean (
+ shell_settings, "disable-printing");
+
+ single_message_selected =
+ (state & E_MAIL_READER_SELECTION_SINGLE);
+ multiple_messages_selected =
+ (state & E_MAIL_READER_SELECTION_MULTIPLE);
+ /* FIXME Missing booleans */
+ enable_flag_clear =
+ (state & E_MAIL_READER_SELECTION_FLAG_CLEAR);
+ enable_flag_completed =
+ (state & E_MAIL_READER_SELECTION_FLAG_COMPLETED);
+ enable_flag_for_followup =
+ (state & E_MAIL_READER_SELECTION_FLAG_FOLLOWUP);
+ selection_has_deleted_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_DELETED);
+ selection_has_important_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_IMPORTANT);
+ selection_has_junk_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_JUNK);
+ selection_has_not_junk_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_NOT_JUNK);
+ selection_has_read_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_READ);
+ selection_has_undeleted_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_UNDELETED);
+ selection_has_unimportant_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_UNIMPORTANT);
+ selection_has_unread_messages =
+ (state & E_MAIL_READER_SELECTION_HAS_UNREAD);
+ /* FIXME Missing booleans */
+ selection_is_mailing_list =
+ (state & E_MAIL_READER_SELECTION_IS_MAILING_LIST);
+
+ any_messages_selected =
+ (single_message_selected || multiple_messages_selected);
+
+ 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_name = "mail-copy";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-delete";
+ sensitive = selection_has_undeleted_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (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_name = "mail-forward";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-forward-attached";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-forward-inline";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-forward-quoted";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_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_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_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_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_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_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_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_name = "mail-message-edit";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_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_name = "mail-move";
+ sensitive = any_messages_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_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_name = "mail-next-thread";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-next-unread";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_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_name = "mail-previous-unread";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-print";
+ sensitive = single_message_selected && !disable_printing;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-print-preview";
+ sensitive = single_message_selected && !disable_printing;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-redirect";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-reply-all";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_action_set_sensitive (action, sensitive);
+
+ action_name = "mail-reply-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_name = "mail-reply-sender";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_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_name = "mail-select-all";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_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_name = "mail-undelete";
+ sensitive = selection_has_deleted_messages;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_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_name = "mail-zoom-in";
+ sensitive = single_message_selected;
+ action = e_mail_reader_get_action (reader, action_name);
+ gtk_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);
+}
+
+GtkAction *
+e_mail_reader_get_action (EMailReader *reader,
+ const gchar *action_name)
+{
+ GtkActionGroup *action_group;
+ GtkAction *action;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+ g_return_val_if_fail (action_name != NULL, NULL);
+
+ action_group = e_mail_reader_get_action_group (reader);
+ action = gtk_action_group_get_action (action_group, action_name);
+
+ if (action == NULL)
+ g_critical (
+ "%s: action `%s' not found", G_STRFUNC, action_name);
+
+ return action;
+}
+
+GtkActionGroup *
+e_mail_reader_get_action_group (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_action_group != NULL, NULL);
+
+ return iface->get_action_group (reader);
+}
+
+gboolean
+e_mail_reader_get_hide_deleted (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), FALSE);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_hide_deleted != NULL, FALSE);
+
+ return iface->get_hide_deleted (reader);
+}
+
+EMFormatHTMLDisplay *
+e_mail_reader_get_html_display (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_html_display != NULL, NULL);
+
+ return iface->get_html_display (reader);
+}
+
+MessageList *
+e_mail_reader_get_message_list (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_message_list != NULL, NULL);
+
+ return iface->get_message_list (reader);
+}
+
+EShellBackend *
+e_mail_reader_get_shell_backend (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_shell_backend != NULL, NULL);
+
+ return iface->get_shell_backend (reader);
+}
+
+GtkWindow *
+e_mail_reader_get_window (EMailReader *reader)
+{
+ EMailReaderIface *iface;
+
+ g_return_val_if_fail (E_IS_MAIL_READER (reader), NULL);
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_val_if_fail (iface->get_window != NULL, NULL);
+
+ return iface->get_window (reader);
+}
+
+void
+e_mail_reader_set_folder (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *folder_uri)
+{
+ EMailReaderIface *iface;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_if_fail (iface->set_folder != NULL);
+
+ iface->set_folder (reader, folder, folder_uri);
+}
+
+/* Helper for e_mail_reader_set_folder_uri() */
+static void
+mail_reader_got_folder_cb (gchar *folder_uri,
+ CamelFolder *folder,
+ gpointer user_data)
+{
+ EMailReader *reader = user_data;
+
+ e_mail_reader_set_folder (reader, folder, folder_uri);
+}
+
+void
+e_mail_reader_set_folder_uri (EMailReader *reader,
+ const gchar *folder_uri)
+{
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+ g_return_if_fail (folder_uri != NULL);
+
+ /* Fetch the CamelFolder asynchronously. */
+ mail_get_folder (
+ folder_uri, 0, mail_reader_got_folder_cb,
+ reader, mail_msg_fast_ordered_push);
+}
+
+void
+e_mail_reader_set_message (EMailReader *reader,
+ const gchar *uid,
+ gboolean mark_read)
+{
+ EMailReaderIface *iface;
+
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ iface = E_MAIL_READER_GET_IFACE (reader);
+ g_return_if_fail (iface->set_message != NULL);
+
+ iface->set_message (reader, uid, mark_read);
+}
+
+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)
+{
+ g_return_if_fail (E_IS_MAIL_READER (reader));
+
+ g_signal_emit (reader, signals[SHOW_SEARCH_BAR], 0);
+}
diff --cc mail/e-mail-reader.h
index 13a9ba8,0000000..c55ba92
mode 100644,000000..100644
--- a/mail/e-mail-reader.h
+++ b/mail/e-mail-reader.h
@@@ -1,134 -1,0 +1,134 @@@
+/*
+ * e-mail-reader.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_READER_H
+#define E_MAIL_READER_H
+
+#include <gtk/gtk.h>
+#include <camel/camel-folder.h>
+#include <mail/em-format-html-display.h>
+#include <mail/message-list.h>
+#include <shell/e-shell-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_READER \
+ (e_mail_reader_get_type ())
+#define E_MAIL_READER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_READER, EMailReader))
+#define E_MAIL_READER_IFACE(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_READER, EMailReaderIface))
+#define E_IS_MAIL_READER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_READER))
+#define E_IS_MAIL_READER_IFACE(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_READER))
+#define E_MAIL_READER_GET_IFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE \
+ ((obj), E_TYPE_MAIL_READER, EMailReaderIface))
+
+/* Basename of the UI definition file. */
+#define E_MAIL_READER_UI_DEFINITION "evolution-mail-reader.ui"
+
+G_BEGIN_DECLS
+
+typedef struct _EMailReader EMailReader;
+typedef struct _EMailReaderIface EMailReaderIface;
+
+enum {
+ E_MAIL_READER_SELECTION_SINGLE = 1 << 0,
+ E_MAIL_READER_SELECTION_MULTIPLE = 1 << 1,
+ E_MAIL_READER_SELECTION_CAN_ADD_SENDER = 1 << 2,
+ E_MAIL_READER_SELECTION_CAN_EDIT = 1 << 3,
+ E_MAIL_READER_SELECTION_FLAG_CLEAR = 1 << 4,
+ E_MAIL_READER_SELECTION_FLAG_COMPLETED = 1 << 5,
+ E_MAIL_READER_SELECTION_FLAG_FOLLOWUP = 1 << 6,
+ E_MAIL_READER_SELECTION_HAS_DELETED = 1 << 7,
+ E_MAIL_READER_SELECTION_HAS_IMPORTANT = 1 << 8,
+ E_MAIL_READER_SELECTION_HAS_JUNK = 1 << 9,
+ E_MAIL_READER_SELECTION_HAS_NOT_JUNK = 1 << 10,
+ E_MAIL_READER_SELECTION_HAS_READ = 1 << 11,
+ E_MAIL_READER_SELECTION_HAS_UNDELETED = 1 << 12,
+ E_MAIL_READER_SELECTION_HAS_UNIMPORTANT = 1 << 13,
+ E_MAIL_READER_SELECTION_HAS_UNREAD = 1 << 14,
+ E_MAIL_READER_SELECTION_HAS_URI_CALLTO = 1 << 15,
+ E_MAIL_READER_SELECTION_HAS_URI_HTTP = 1 << 16,
+ E_MAIL_READER_SELECTION_HAS_URI_MAILTO = 1 << 17,
+ E_MAIL_READER_SELECTION_IS_MAILING_LIST = 1 << 18
+};
+
+struct _EMailReaderIface {
+ GTypeInterface parent_iface;
+
+ GtkActionGroup *
+ (*get_action_group) (EMailReader *reader);
+ gboolean (*get_hide_deleted) (EMailReader *reader);
+ EMFormatHTMLDisplay *
+ (*get_html_display) (EMailReader *reader);
+ MessageList * (*get_message_list) (EMailReader *reader);
+ EShellBackend * (*get_shell_backend) (EMailReader *reader);
+ GtkWindow * (*get_window) (EMailReader *reader);
+
+ void (*set_folder) (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *folder_uri);
+ void (*set_message) (EMailReader *reader,
+ const gchar *uid,
+ gboolean mark_read);
+
+ /* Signals */
+ void (*show_search_bar) (EMailReader *reader);
+};
+
+GType e_mail_reader_get_type (void);
+void e_mail_reader_init (EMailReader *reader);
+void e_mail_reader_changed (EMailReader *reader);
+guint32 e_mail_reader_check_state (EMailReader *reader);
+void e_mail_reader_update_actions (EMailReader *reader);
+GtkAction * e_mail_reader_get_action (EMailReader *reader,
+ const gchar *action_name);
+GtkActionGroup *
+ e_mail_reader_get_action_group (EMailReader *reader);
+gboolean e_mail_reader_get_hide_deleted (EMailReader *reader);
+EMFormatHTMLDisplay *
+ e_mail_reader_get_html_display (EMailReader *reader);
+MessageList * e_mail_reader_get_message_list (EMailReader *reader);
+EShellBackend * e_mail_reader_get_shell_backend (EMailReader *reader);
+GtkWindow * e_mail_reader_get_window (EMailReader *reader);
+void e_mail_reader_set_folder (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *folder_uri);
+void e_mail_reader_set_folder_uri (EMailReader *reader,
+ const gchar *folder_uri);
+void e_mail_reader_set_message (EMailReader *reader,
+ const gchar *uid,
+ gboolean mark_read);
+void e_mail_reader_create_charset_menu
+ (EMailReader *reader,
+ GtkUIManager *ui_manager,
+ guint merge_id);
+void e_mail_reader_show_search_bar (EMailReader *reader);
+
+G_END_DECLS
+
+#endif /* E_MAIL_READER_H */
diff --cc mail/e-mail-shell-backend.c
index 3fa066a,0000000..10a99e7
mode 100644,000000..100644
--- a/mail/e-mail-shell-backend.c
+++ b/mail/e-mail-shell-backend.c
@@@ -1,1294 -1,0 +1,1294 @@@
+/*
+ * e-mail-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-backend.h"
+
+#include <glib/gi18n.h>
+#include <camel/camel-disco-store.h>
+#include <camel/camel-offline-store.h>
+#include <camel/camel-session.h>
+#include <camel/camel-url.h>
+
+#include "e-util/e-account-utils.h"
+#include "e-util/e-binding.h"
+#include "e-util/e-import.h"
+#include "e-util/e-util.h"
+#include "shell/e-shell.h"
+#include "shell/e-shell-window.h"
+#include "composer/e-msg-composer.h"
+#include "widgets/misc/e-preferences-window.h"
+
+#include "e-mail-shell-migrate.h"
+#include "e-mail-shell-settings.h"
+#include "e-mail-shell-sidebar.h"
+#include "e-mail-shell-view.h"
+
+#include "e-attachment-handler-mail.h"
+#include "e-mail-browser.h"
+#include "e-mail-reader.h"
+#include "em-account-prefs.h"
+#include "em-composer-prefs.h"
+#include "em-composer-utils.h"
+#include "em-config.h"
+#include "em-event.h"
+#include "em-folder-tree-model.h"
+#include "em-folder-utils.h"
+#include "em-format-hook.h"
+#include "em-format-html-display.h"
+#include "em-junk-hook.h"
+#include "em-mailer-prefs.h"
+#include "em-network-prefs.h"
+#include "em-utils.h"
+#include "mail-config.h"
+#include "mail-folder-cache.h"
+#include "mail-mt.h"
+#include "mail-ops.h"
+#include "mail-send-recv.h"
+#include "mail-session.h"
+#include "mail-vfolder.h"
+#include "importers/mail-importer.h"
+
+#define E_MAIL_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendPrivate))
+
+#define BACKEND_NAME "mail"
+
+typedef struct _StoreInfo StoreInfo;
+
+/* XXX Temporary */
+CamelStore *vfolder_store;
+
+struct _StoreInfo {
+ CamelStore *store;
+ gint ref_count;
+ gchar *name;
+
+ /* Keep a reference to these so they remain around for the session. */
+ CamelFolder *vtrash;
+ CamelFolder *vjunk;
+
+ /* Initialization callback. */
+ void (*done) (CamelStore *store,
+ CamelFolderInfo *info,
+ gpointer user_data);
+ gpointer done_user_data;
+
+ guint removed : 1;
+};
+
+struct _EMailShellBackendPrivate {
+ GHashTable *store_hash;
+ MailAsyncEvent *async_event;
+ EMFolderTreeModel *folder_tree_model;
+ CamelStore *local_store;
+
+ gint mail_sync_in_progress;
+ guint mail_sync_timeout_source_id;
+};
+
+/* XXX Make this a preprocessor definition. */
+const gchar *x_mailer = "Evolution " VERSION SUB_VERSION " " VERSION_COMMENT;
+
+static gpointer parent_class;
+static GType mail_shell_backend_type;
+
+/* The array elements correspond to EMailFolderType. */
+static struct {
- gchar *name;
++ const gchar *name;
+ gchar *uri;
+ CamelFolder *folder;
+} default_local_folders[] = {
+ { N_("Inbox") },
+ { N_("Drafts") },
+ { N_("Outbox") },
+ { N_("Sent") },
+ { N_("Templates") },
+ { "Inbox" } /* "always local" inbox */
+};
+
+/* XXX So many things need the shell backend that it's
+ * just easier for now to make it globally available.
+ * We should fix this, though. */
+EMailShellBackend *global_mail_shell_backend = NULL;
+
+extern gint camel_application_is_exiting;
+
+static StoreInfo *
+store_info_new (CamelStore *store,
+ const gchar *name)
+{
+ CamelService *service;
+ StoreInfo *si;
+
+ g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
+
+ service = CAMEL_SERVICE (store);
+
+ si = g_slice_new0 (StoreInfo);
+ si->ref_count = 1;
+
+ if (name == NULL)
+ si->name = camel_service_get_name (service, TRUE);
+ else
+ si->name = g_strdup (name);
+
+ si->store = store;
+ camel_object_ref (store);
+
+ /* If these are vfolders then they need to be opened now,
+ * otherwise they won't keep track of all folders. */
+ if (store->flags & CAMEL_STORE_VTRASH)
+ si->vtrash = camel_store_get_trash (store, NULL);
+ if (store->flags & CAMEL_STORE_VJUNK)
+ si->vjunk = camel_store_get_junk (store, NULL);
+
+ return si;
+}
+
+static StoreInfo *
+store_info_ref (StoreInfo *si)
+{
+ g_return_val_if_fail (si != NULL, si);
+ g_return_val_if_fail (si->ref_count > 0, si);
+
+ g_atomic_int_add (&si->ref_count, 1);
+
+ return si;
+}
+
+static void
+store_info_unref (StoreInfo *si)
+{
+ g_return_if_fail (si != NULL);
+ g_return_if_fail (si->ref_count > 0);
+
+ if (g_atomic_int_exchange_and_add (&si->ref_count, -1) > 1)
+ return;
+
+ if (si->vtrash != NULL)
+ camel_object_unref (si->vtrash);
+ if (si->vjunk != NULL)
+ camel_object_unref (si->vjunk);
+ camel_object_unref (si->store);
+ g_free (si->name);
+
+ g_slice_free (StoreInfo, si);
+}
+
+static void
+store_hash_free (StoreInfo *si)
+{
+ si->removed = 1;
+ store_info_unref (si);
+}
+
+static gboolean
+mail_shell_backend_add_store_done (CamelStore *store,
+ CamelFolderInfo *info,
+ gpointer user_data)
+{
+ StoreInfo *si = user_data;
+
+ if (si->done != NULL)
+ si->done (store, info, si);
+
+ if (!si->removed) {
+ /* Let the counters know about the already-opened
+ * junk and trash folders. */
+ if (si->vtrash != NULL)
+ mail_note_folder (si->vtrash);
+ if (si->vjunk != NULL)
+ mail_note_folder (si->vjunk);
+ }
+
+ store_info_unref (si);
+
+ return TRUE;
+}
+
+static void
+mail_shell_backend_add_store (EMailShellBackend *mail_shell_backend,
+ CamelStore *store,
+ const gchar *name,
+ void (*done) (CamelStore *store,
+ CamelFolderInfo *info,
+ gpointer user_data))
+{
+ EMFolderTreeModel *folder_tree_model;
+ GHashTable *store_hash;
+ StoreInfo *si;
+
+ store_hash = mail_shell_backend->priv->store_hash;
+ folder_tree_model = mail_shell_backend->priv->folder_tree_model;
+
+ si = store_info_new (store, name);
+ si->done = done;
+ g_hash_table_insert (store_hash, store, si);
+
+ em_folder_tree_model_add_store (folder_tree_model, store, si->name);
+
+ mail_note_store (
+ mail_shell_backend, store, NULL,
+ mail_shell_backend_add_store_done, store_info_ref (si));
+}
+
+static void
+mail_shell_backend_add_local_store_done (CamelStore *store,
+ CamelFolderInfo *info,
+ gpointer unused)
+{
+ gint ii;
+
+ for (ii = 0; ii < G_N_ELEMENTS (default_local_folders); ii++) {
+ if (default_local_folders[ii].folder != NULL)
+ mail_note_folder (default_local_folders[ii].folder);
+ }
+}
+
+static void
+mail_shell_backend_add_local_store (EMailShellBackend *mail_shell_backend,
+ CamelStore *local_store,
+ const gchar *name)
+{
+ mail_shell_backend_add_store (
+ mail_shell_backend, local_store, name,
+ mail_shell_backend_add_local_store_done);
+}
+
+static void
+mail_shell_backend_init_hooks (void)
+{
+ e_plugin_hook_register_type (em_config_hook_get_type ());
+ e_plugin_hook_register_type (em_event_hook_get_type ());
+ e_plugin_hook_register_type (em_junk_hook_get_type ());
+
+ /* EMFormat classes must be registered before EMFormatHook. */
+ em_format_hook_register_type (em_format_get_type ());
+ em_format_hook_register_type (em_format_html_get_type ());
+ em_format_hook_register_type (em_format_html_display_get_type ());
+ e_plugin_hook_register_type (em_format_hook_get_type ());
+
+ em_junk_hook_register_type (emj_get_type ());
+}
+
+static void
+mail_shell_backend_init_importers (void)
+{
+ EImportClass *import_class;
+ EImportImporter *importer;
+
+ import_class = g_type_class_ref (e_import_get_type ());
+
+ importer = mbox_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = elm_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+
+ importer = pine_importer_peek ();
+ e_import_class_add_importer (import_class, importer, NULL, NULL);
+}
+
+static void
+mail_shell_backend_init_local_store (EShellBackend *shell_backend)
+{
+ EMailShellBackendPrivate *priv;
+ CamelException ex;
+ CamelService *service;
+ CamelURL *url;
+ MailAsyncEvent *async_event;
+ const gchar *data_dir;
+ gchar *temp;
+ gint ii;
+
+ priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (shell_backend);
+
+ camel_exception_init (&ex);
+
+ async_event = priv->async_event;
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+
+ url = camel_url_new ("mbox:", NULL);
+ temp = g_build_filename (data_dir, "local", NULL);
+ camel_url_set_path (url, temp);
+ g_free (temp);
+
+ temp = camel_url_to_string (url, 0);
+ service = camel_session_get_service (
+ session, temp, CAMEL_PROVIDER_STORE, &ex);
+ g_free (temp);
+
+ if (service == NULL)
+ goto fail;
+
+ for (ii = 0; ii < G_N_ELEMENTS (default_local_folders); ii++) {
+ /* FIXME Should this URI be account relative? */
+ camel_url_set_fragment (url, default_local_folders[ii].name);
+ default_local_folders[ii].uri = camel_url_to_string (url, 0);
+ default_local_folders[ii].folder = camel_store_get_folder (
+ CAMEL_STORE (service), default_local_folders[ii].name,
+ CAMEL_STORE_FOLDER_CREATE, &ex);
+ camel_exception_clear (&ex);
+ }
+
+ camel_url_free (url);
+
+ camel_object_ref (service);
+ g_object_ref (shell_backend);
+
+ mail_async_event_emit (
+ async_event, MAIL_ASYNC_GUI,
+ (MailAsyncFunc) mail_shell_backend_add_local_store,
+ shell_backend, service, _("On This Computer"));
+
+ priv->local_store = CAMEL_STORE (service);
+
+ return;
+
+fail:
+ g_warning ("Could not initialize local store/folder: %s", ex.desc);
+
+ camel_exception_clear (&ex);
+ camel_url_free (url);
+}
+
+static void
+mail_shell_backend_load_accounts (EShellBackend *shell_backend)
+{
+ EAccountList *account_list;
+ EIterator *iter;
+
+ account_list = e_get_account_list ();
+
+ for (iter = e_list_get_iterator ((EList *) account_list);
+ e_iterator_is_valid (iter); e_iterator_next (iter)) {
+
+ EAccountService *service;
+ EAccount *account;
+ const gchar *name;
+ const gchar *url;
+
+ account = (EAccount *) e_iterator_get (iter);
+ service = account->source;
+ name = account->name;
+ url = service->url;
+
+ if (!account->enabled)
+ continue;
+
+ if (url == NULL || *url == '\0')
+ continue;
+
+ /* HACK: mbox URL's are handled by the local store setup
+ * above. Any that come through as account sources
+ * are really movemail sources! */
+ if (g_str_has_prefix (url, "mbox:"))
+ continue;
+
+ e_mail_shell_backend_load_store_by_uri (
+ E_MAIL_SHELL_BACKEND (shell_backend), url, name);
+ }
+
+ g_object_unref (iter);
+}
+
+static void
+mail_shell_backend_mail_icon_cb (EShellWindow *shell_window,
+ const gchar *icon_name)
+{
+ GtkAction *action;
+
+ action = e_shell_window_get_shell_view_action (
+ shell_window, BACKEND_NAME);
+ g_object_set (action, "icon-name", icon_name, NULL);
+}
+
+static void
+action_mail_folder_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EMFolderTree *folder_tree = NULL;
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ const gchar *view_name;
+
+ /* Take care not to unnecessarily load the mail shell view. */
+ view_name = e_shell_window_get_active_view (shell_window);
+ if (g_strcmp0 (view_name, BACKEND_NAME) != 0)
+ goto exit;
+
+ shell_view = e_shell_window_get_shell_view (shell_window, view_name);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+exit:
+ em_folder_utils_create_folder (
+ NULL, folder_tree, GTK_WINDOW (shell_window));
+}
+
+static void
+action_mail_message_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ GtkWindow *window = GTK_WINDOW (shell_window);
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ EMFolderTree *folder_tree;
+ const gchar *view_name;
+ gchar *uri = NULL;
+
+ if (!em_utils_check_user_can_send_mail (window))
+ return;
+
+ /* Take care not to unnecessarily load the mail shell view. */
+ view_name = e_shell_window_get_active_view (shell_window);
+ if (g_strcmp0 (view_name, BACKEND_NAME) != 0)
+ goto exit;
+
+ shell_view = e_shell_window_get_shell_view (shell_window, view_name);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ uri = em_folder_tree_get_selected_uri (folder_tree);
+
+exit:
+ em_utils_compose_new_message (uri);
+
+ g_free (uri);
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "mail-message-new",
+ "mail-message-new",
+ NC_("New", "_Mail Message"),
+ "<Shift><Control>m",
+ N_("Compose a new mail message"),
+ G_CALLBACK (action_mail_message_new_cb) }
+};
+
+static GtkActionEntry source_entries[] = {
+
+ { "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_init_preferences (EShell *shell)
+{
+ EAccountList *account_list;
+ GtkWidget *preferences_window;
+
+ account_list = e_get_account_list ();
+ preferences_window = e_shell_get_preferences_window (shell);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "mail-accounts",
+ "preferences-mail-accounts",
+ _("Mail Accounts"),
+ em_account_prefs_new (account_list),
+ 100);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "mail",
+ "preferences-mail",
+ _("Mail Preferences"),
+ em_mailer_prefs_new (shell),
+ 300);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "composer",
+ "preferences-composer",
+ _("Composer Preferences"),
+ em_composer_prefs_new (shell),
+ 400);
+
+ e_preferences_window_add_page (
+ E_PREFERENCES_WINDOW (preferences_window),
+ "system-network-proxy",
+ "preferences-system-network-proxy",
+ _("Network Preferences"),
+ em_network_prefs_new (),
+ 500);
+}
+
+static void
+mail_shell_backend_sync_store_done_cb (CamelStore *store,
+ gpointer user_data)
+{
+ EMailShellBackend *mail_shell_backend = user_data;
+
+ mail_shell_backend->priv->mail_sync_in_progress--;
+}
+
+static void
+mail_shell_backend_sync_store_cb (CamelStore *store,
+ EMailShellBackend *mail_shell_backend)
+{
+ if (!camel_application_is_exiting) {
+ mail_shell_backend->priv->mail_sync_in_progress++;
+ mail_sync_store (
+ store, FALSE,
+ mail_shell_backend_sync_store_done_cb,
+ mail_shell_backend);
+ }
+}
+
+static gboolean
+mail_shell_backend_mail_sync (EMailShellBackend *mail_shell_backend)
+{
+ if (camel_application_is_exiting)
+ return FALSE;
+
+ if (mail_shell_backend->priv->mail_sync_in_progress)
+ goto exit;
+
+ if (session == NULL || !camel_session_is_online (session))
+ goto exit;
+
+ e_mail_shell_backend_stores_foreach (
+ mail_shell_backend, (GHFunc)
+ mail_shell_backend_sync_store_cb,
+ mail_shell_backend);
+
+exit:
+ return !camel_application_is_exiting;
+}
+
+static void
+mail_shell_backend_notify_online_cb (EShell *shell,
+ GParamSpec *pspec,
+ EShellBackend *shell_backend)
+{
+ gboolean online;
+
+ online = e_shell_get_online (shell);
+ camel_session_set_online (session, online);
+}
+
+static void
+mail_shell_backend_handle_email_uri_cb (gchar *folder_uri,
+ CamelFolder *folder,
+ gpointer user_data)
+{
+ EMailShellBackend *mail_shell_backend = user_data;
+ CamelURL *url = user_data;
+ const gchar *forward;
+ const gchar *reply;
+ const gchar *uid;
+
+ if (folder == NULL) {
+ g_warning ("Could not open folder '%s'", folder_uri);
+ goto exit;
+ }
+
+ forward = camel_url_get_param (url, "forward");
+ reply = camel_url_get_param (url, "reply");
+ uid = camel_url_get_param (url, "uid");
+
+ if (reply != NULL) {
+ gint mode;
+
+ if (g_strcmp0 (reply, "all") == 0)
+ mode = REPLY_MODE_ALL;
+ else if (g_strcmp0 (reply, "list") == 0)
+ mode = REPLY_MODE_LIST;
+ else
+ mode = REPLY_MODE_SENDER;
+
+ em_utils_reply_to_message (folder, uid, NULL, mode, NULL);
+
+ } else if (forward != NULL) {
+ GPtrArray *uids;
+
+ uids = g_ptr_array_new ();
+ g_ptr_array_add (uids, g_strdup (uid));
+
+ if (g_strcmp0 (forward, "attached") == 0)
+ em_utils_forward_attached (folder, uids, folder_uri);
+ else if (g_strcmp0 (forward, "inline") == 0)
+ em_utils_forward_inline (folder, uids, folder_uri);
+ else if (g_strcmp0 (forward, "quoted") == 0)
+ em_utils_forward_quoted (folder, uids, folder_uri);
+ else
+ em_utils_forward_messages (folder, uids, folder_uri);
+
+ } else {
+ GtkWidget *browser;
+
+ /* FIXME Should pass in the shell module. */
+ browser = e_mail_browser_new (mail_shell_backend);
+ e_mail_reader_set_folder (
+ E_MAIL_READER (browser), folder, folder_uri);
+ e_mail_reader_set_message (
+ E_MAIL_READER (browser), uid, FALSE);
+ gtk_widget_show (browser);
+ }
+
+exit:
+ camel_url_free (url);
+}
+
+static gboolean
+mail_shell_backend_handle_uri_cb (EShell *shell,
+ const gchar *uri,
+ EMailShellBackend *mail_shell_backend)
+{
+ gboolean handled = TRUE;
+
+ if (g_str_has_prefix (uri, "mailto:")) {
+ if (em_utils_check_user_can_send_mail (NULL))
+ em_utils_compose_new_message_with_mailto (uri, NULL);
+
+ } else if (g_str_has_prefix (uri, "email:")) {
+ CamelURL *url;
+
+ url = camel_url_new (uri, NULL);
+ if (camel_url_get_param (url, "uid") != NULL) {
+ gchar *curi = em_uri_to_camel (uri);
+
+ mail_get_folder (
+ curi, 0,
+ mail_shell_backend_handle_email_uri_cb,
+ mail_shell_backend, mail_msg_unordered_push);
+ g_free (curi);
+
+ } else {
+ g_warning ("Email URI's must include a uid parameter");
+ camel_url_free (url);
+ }
+ } else
+ handled = FALSE;
+
+ return TRUE;
+}
+
+/* Helper for mail_shell_backend_prepare_for_[off|on]line_cb() */
+static void
+mail_shell_store_line_transition_done_cb (CamelStore *store,
+ gpointer user_data)
+{
+ EActivity *activity = user_data;
+
+ g_object_unref (activity);
+}
+
+/* Helper for mail_shell_backend_prepare_for_offline_cb() */
+static void
+mail_shell_store_prepare_for_offline_cb (CamelService *service,
+ gpointer unused,
+ EActivity *activity)
+{
+ if (CAMEL_IS_DISCO_STORE (service) || CAMEL_IS_OFFLINE_STORE (service))
+ mail_store_set_offline (
+ CAMEL_STORE (service), TRUE,
+ mail_shell_store_line_transition_done_cb,
+ g_object_ref (activity));
+}
+
+static void
+mail_shell_backend_prepare_for_offline_cb (EShell *shell,
+ EActivity *activity,
+ EMailShellBackend *mail_shell_backend)
+{
+ GList *watched_windows;
+ GtkWidget *parent = NULL;
+ gboolean synchronize = FALSE;
+
+ watched_windows = e_shell_get_watched_windows (shell);
+ if (watched_windows != NULL)
+ parent = GTK_WIDGET (watched_windows->data);
+
+ if (e_shell_get_network_available (shell))
+ synchronize = em_utils_prompt_user (
+ GTK_WINDOW (parent),
+ "/apps/evolution/mail/prompts/quick_offline",
+ "mail:ask-quick-offline", NULL);
+
+ if (!synchronize) {
+ mail_cancel_all ();
+ camel_session_set_network_state (session, FALSE);
+ }
+
+ e_mail_shell_backend_stores_foreach (
+ mail_shell_backend, (GHFunc)
+ mail_shell_store_prepare_for_offline_cb, activity);
+}
+
+/* Helper for mail_shell_backend_prepare_for_online_cb() */
+static void
+mail_shell_store_prepare_for_online_cb (CamelService *service,
+ gpointer unused,
+ EActivity *activity)
+{
+ if (CAMEL_IS_DISCO_STORE (service) || CAMEL_IS_OFFLINE_STORE (service))
+ mail_store_set_offline (
+ CAMEL_STORE (service), FALSE,
+ mail_shell_store_line_transition_done_cb,
+ g_object_ref (activity));
+}
+
+static void
+mail_shell_backend_prepare_for_online_cb (EShell *shell,
+ EActivity *activity,
+ EMailShellBackend *mail_shell_backend)
+{
+ camel_session_set_online (session, TRUE);
+
+ e_mail_shell_backend_stores_foreach (
+ mail_shell_backend, (GHFunc)
+ mail_shell_store_prepare_for_online_cb, activity);
+}
+
+static void
+mail_shell_backend_send_receive_cb (EShell *shell,
+ GtkWindow *parent,
+ EShellBackend *shell_backend)
+{
+ em_utils_clear_get_password_canceled_accounts_flag ();
+ mail_send_receive (parent);
+}
+
+static void
+mail_shell_backend_window_weak_notify_cb (EShell *shell,
+ GObject *where_the_object_was)
+{
+ g_signal_handlers_disconnect_by_func (
+ shell, mail_shell_backend_mail_icon_cb,
+ where_the_object_was);
+}
+
+static void
+mail_shell_backend_window_created_cb (EShell *shell,
+ GtkWindow *window,
+ EShellBackend *shell_backend)
+{
+ EShellSettings *shell_settings;
+ static gboolean first_time = TRUE;
+ const gchar *backend_name;
+
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ /* This applies to both the composer and signature editor. */
+ if (GTKHTML_IS_EDITOR (window)) {
+ GList *spell_languages;
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "composer-inline-spelling",
+ G_OBJECT (window), "inline-spelling");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "composer-magic-links",
+ G_OBJECT (window), "magic-links");
+
+ e_binding_new (
+ G_OBJECT (shell_settings), "composer-magic-smileys",
+ G_OBJECT (window), "magic-smileys");
+
+ spell_languages = e_load_spell_languages ();
+ gtkhtml_editor_set_spell_languages (
+ GTKHTML_EDITOR (window), spell_languages);
+ g_list_free (spell_languages);
+ }
+
+ if (E_IS_MSG_COMPOSER (window)) {
+ /* Integrate the new composer into the mail module. */
+ em_configure_new_composer (E_MSG_COMPOSER (window));
+ return;
+ }
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+
+ g_signal_connect_swapped (
+ shell, "event::mail-icon",
+ G_CALLBACK (mail_shell_backend_mail_icon_cb), window);
+
+ g_object_weak_ref (
+ G_OBJECT (window), (GWeakNotify)
+ mail_shell_backend_window_weak_notify_cb, shell);
+
+ if (first_time) {
+ g_signal_connect (
+ window, "map-event",
+ G_CALLBACK (e_msg_composer_check_autosave), NULL);
+ first_time = FALSE;
+ }
+}
+
+static void
+mail_shell_backend_dispose (GObject *object)
+{
+ EMailShellBackendPrivate *priv;
+
+ priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (object);
+
+ g_hash_table_remove_all (priv->store_hash);
+
+ if (priv->folder_tree_model != NULL) {
+ g_object_unref (priv->folder_tree_model);
+ priv->folder_tree_model = NULL;
+ }
+
+ if (priv->local_store != NULL) {
+ camel_object_unref (priv->local_store);
+ priv->local_store = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_shell_backend_finalize (GObject *object)
+{
+ EMailShellBackendPrivate *priv;
+
+ priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->store_hash);
+ mail_async_event_destroy (priv->async_event);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_shell_backend_constructed (GObject *object)
+{
+ EMailShellBackendPrivate *priv;
+ EShell *shell;
+ EShellBackend *shell_backend;
+
+ priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (object);
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ /* This also initializes Camel, so it needs to happen early. */
+ mail_session_init (E_MAIL_SHELL_BACKEND (shell_backend));
+
+ mail_shell_backend_init_hooks ();
+ mail_shell_backend_init_importers ();
+
+ e_attachment_handler_mail_get_type ();
+
+ /* XXX This never gets unreffed. */
+ global_mail_shell_backend = g_object_ref (shell_backend);
+
+ priv->store_hash = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) store_hash_free);
+
+ priv->async_event = mail_async_event_new ();
+
+ priv->folder_tree_model = em_folder_tree_model_new (
+ E_MAIL_SHELL_BACKEND (shell_backend));
+
+ g_signal_connect (
+ shell, "notify::online",
+ G_CALLBACK (mail_shell_backend_notify_online_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "handle-uri",
+ G_CALLBACK (mail_shell_backend_handle_uri_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "prepare-for-offline",
+ G_CALLBACK (mail_shell_backend_prepare_for_offline_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "prepare-for-online",
+ G_CALLBACK (mail_shell_backend_prepare_for_online_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "send-receive",
+ G_CALLBACK (mail_shell_backend_send_receive_cb),
+ shell_backend);
+
+ g_signal_connect (
+ shell, "window-created",
+ G_CALLBACK (mail_shell_backend_window_created_cb),
+ shell_backend);
+
+ mail_config_init ();
+ mail_msg_init ();
+
+ mail_shell_backend_init_local_store (shell_backend);
+ mail_shell_backend_load_accounts (shell_backend);
+
+ /* Initialize settings before initializing preferences,
+ * since the preferences bind to the shell settings. */
+ e_mail_shell_settings_init (shell);
+ mail_shell_backend_init_preferences (shell);
+}
+
+static void
+mail_shell_backend_start (EShellBackend *shell_backend)
+{
+ EMailShellBackendPrivate *priv;
+ EShell *shell;
+ EShellSettings *shell_settings;
+ gboolean enable_search_folders;
+
+ priv = E_MAIL_SHELL_BACKEND_GET_PRIVATE (shell_backend);
+
+ shell = e_shell_backend_get_shell (shell_backend);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ /* XXX Do we really still need this flag? */
+ mail_session_set_interactive (TRUE);
+
+ enable_search_folders = e_shell_settings_get_boolean (
+ shell_settings, "mail-enable-search-folders");
+ if (enable_search_folders)
+ vfolder_load_storage ();
+
+ mail_autoreceive_init (shell_backend, session);
+
+ if (g_getenv ("CAMEL_FLUSH_CHANGES") != NULL)
+ priv->mail_sync_timeout_source_id = g_timeout_add_seconds (
+ mail_config_get_sync_timeout (),
+ (GSourceFunc) mail_shell_backend_mail_sync,
+ shell_backend);
+}
+
+static void
+mail_shell_backend_class_init (EMailShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = mail_shell_backend_dispose;
+ object_class->finalize = mail_shell_backend_finalize;
+ object_class->constructed = mail_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_MAIL_SHELL_VIEW;
+ shell_backend_class->name = BACKEND_NAME;
+ shell_backend_class->aliases = "";
+ shell_backend_class->schemes = "mailto:email";
+ shell_backend_class->sort_order = 200;
+ shell_backend_class->start = mail_shell_backend_start;
+ shell_backend_class->is_busy = NULL;
+ shell_backend_class->shutdown = NULL;
+ shell_backend_class->migrate = e_mail_shell_migrate;
+}
+
+static void
+mail_shell_backend_init (EMailShellBackend *mail_shell_backend)
+{
+ mail_shell_backend->priv =
+ E_MAIL_SHELL_BACKEND_GET_PRIVATE (mail_shell_backend);
+}
+
+GType
+e_mail_shell_backend_get_type (void)
+{
+ return mail_shell_backend_type;
+}
+
+void
+e_mail_shell_backend_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EMailShellBackendClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_shell_backend_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailShellBackend),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_shell_backend_init,
+ NULL /* value_table */
+ };
+
+ mail_shell_backend_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_BACKEND,
+ "EMailShellBackend", &type_info, 0);
+}
+
+/******************************** Public API *********************************/
+
+CamelFolder *
+e_mail_shell_backend_get_folder (EMailShellBackend *mail_shell_backend,
+ EMailFolderType folder_type)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
+
+ return default_local_folders[folder_type].folder;
+}
+
+const gchar *
+e_mail_shell_backend_get_folder_uri (EMailShellBackend *mail_shell_backend,
+ EMailFolderType folder_type)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
+
+ return default_local_folders[folder_type].uri;
+}
+
+EMFolderTreeModel *
+e_mail_shell_backend_get_folder_tree_model (EMailShellBackend *mail_shell_backend)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
+
+ return mail_shell_backend->priv->folder_tree_model;
+}
+
+void
+e_mail_shell_backend_add_store (EMailShellBackend *mail_shell_backend,
+ CamelStore *store,
+ const gchar *name)
+{
+ g_return_if_fail (E_IS_MAIL_SHELL_BACKEND (mail_shell_backend));
+ g_return_if_fail (CAMEL_IS_STORE (store));
+ g_return_if_fail (name != NULL);
+
+ mail_shell_backend_add_store (mail_shell_backend, store, name, NULL);
+}
+
+CamelStore *
+e_mail_shell_backend_get_local_store (EMailShellBackend *mail_shell_backend)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
+
+ return mail_shell_backend->priv->local_store;
+}
+
+CamelStore *
+e_mail_shell_backend_load_store_by_uri (EMailShellBackend *mail_shell_backend,
+ const gchar *uri,
+ const gchar *name)
+{
+ CamelStore *store;
+ CamelProvider *provider;
+ CamelException ex;
+
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_BACKEND (mail_shell_backend), NULL);
+ g_return_val_if_fail (uri != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ camel_exception_init (&ex);
+
+ /* Load the service, but don't connect. Check its provider,
+ * and if this belongs in the shell's folder list, add it. */
+
+ provider = camel_provider_get (uri, &ex);
+ if (provider == NULL)
+ goto fail;
+
+ if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
+ return NULL;
+
+ store = (CamelStore *) camel_session_get_service (
+ session, uri, CAMEL_PROVIDER_STORE, &ex);
+ if (store == NULL)
+ goto fail;
+
+ e_mail_shell_backend_add_store (mail_shell_backend, store, name);
+
+ camel_object_unref (store);
+
+ return store;
+
+fail:
+ /* FIXME: Show an error dialog. */
+ g_warning (
+ "Couldn't get service: %s: %s", uri,
+ camel_exception_get_description (&ex));
+ camel_exception_clear (&ex);
+
+ return NULL;
+}
+
+/* Helper for e_mail_shell_backend_remove_store() */
+static void
+mail_shell_backend_remove_store_cb (CamelStore *store,
+ gpointer event_data,
+ gpointer user_data)
+{
+ camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL);
+ camel_object_unref (store);
+}
+
+void
+e_mail_shell_backend_remove_store (EMailShellBackend *mail_shell_backend,
+ CamelStore *store)
+{
+ GHashTable *store_hash;
+ MailAsyncEvent *async_event;
+ EMFolderTreeModel *folder_tree_model;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_BACKEND (mail_shell_backend));
+ g_return_if_fail (CAMEL_IS_STORE (store));
+
+ store_hash = mail_shell_backend->priv->store_hash;
+ async_event = mail_shell_backend->priv->async_event;
+ folder_tree_model = mail_shell_backend->priv->folder_tree_model;
+
+ /* Because the store hash holds a reference to each store used
+ * as a key in it, none of them will ever be gc'ed, meaning any
+ * call to camel_session_get_{service,store} with the same URL
+ * will always return the same object. So this works. */
+
+ if (g_hash_table_lookup (store_hash, store) == NULL)
+ return;
+
+ camel_object_ref (store);
+ g_hash_table_remove (store_hash, store);
+ mail_note_store_remove (store);
+ em_folder_tree_model_remove_store (folder_tree_model, store);
+
+ mail_async_event_emit (
+ async_event, MAIL_ASYNC_THREAD,
+ (MailAsyncFunc) mail_shell_backend_remove_store_cb,
+ store, NULL, NULL);
+}
+
+void
+e_mail_shell_backend_remove_store_by_uri (EMailShellBackend *mail_shell_backend,
+ const gchar *uri)
+{
+ CamelStore *store;
+ CamelProvider *provider;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_BACKEND (mail_shell_backend));
+ g_return_if_fail (uri != NULL);
+
+ provider = camel_provider_get (uri, NULL);
+ if (provider == NULL)
+ return;
+
+ if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE))
+ return;
+
+ store = (CamelStore *) camel_session_get_service (
+ session, uri, CAMEL_PROVIDER_STORE, NULL);
+ if (store != NULL) {
+ e_mail_shell_backend_remove_store (mail_shell_backend, store);
+ camel_object_unref (store);
+ }
+}
+
+void
+e_mail_shell_backend_stores_foreach (EMailShellBackend *mail_shell_backend,
+ GHFunc func,
+ gpointer user_data)
+{
+ GHashTable *store_hash;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_BACKEND (mail_shell_backend));
+ g_return_if_fail (func != NULL);
+
+ store_hash = mail_shell_backend->priv->store_hash;
+
+ g_hash_table_iter_init (&iter, store_hash);
+
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ func (key, ((StoreInfo *) value)->name, user_data);
+}
+
+/******************* Code below here belongs elsewhere. *******************/
+
+#include "filter/filter-option.h"
+#include "shell/e-shell-settings.h"
+#include "mail/e-mail-label-list-store.h"
+
+GSList *
+e_mail_labels_get_filter_options (void)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ EMailLabelListStore *list_store;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GSList *list = NULL;
+ gboolean valid;
+
+ shell = e_shell_get_default ();
+ shell_settings = e_shell_get_shell_settings (shell);
+ list_store = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ model = GTK_TREE_MODEL (list_store);
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (valid) {
+ struct _filter_option *option;
+ gchar *name, *tag;
+
+ name = e_mail_label_list_store_get_name (list_store, &iter);
+ tag = e_mail_label_list_store_get_tag (list_store, &iter);
+
+ option = g_new0 (struct _filter_option, 1);
+ option->title = e_str_without_underscores (name);
+ option->value = tag; /* takes ownership */
+
+ g_free (name);
+
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+
+ g_object_unref (list_store);
+
+ return list;
+}
diff --cc mail/e-mail-shell-backend.h
index 7521559,0000000..2487680
mode 100644,000000..100644
--- a/mail/e-mail-shell-backend.h
+++ b/mail/e-mail-shell-backend.h
@@@ -1,122 -1,0 +1,122 @@@
+/*
+ * e-mail-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_BACKEND_H
+#define E_MAIL_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+
+#include <camel/camel-folder.h>
+#include <camel/camel-store.h>
+#include <e-util/e-signature-list.h>
+#include <libedataserver/e-account-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SHELL_BACKEND \
+ (e_mail_shell_backend_get_type ())
+#define E_MAIL_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackend))
+#define E_MAIL_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendClass))
+#define E_IS_MAIL_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_BACKEND))
+#define E_IS_MAIL_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_SHELL_BACKEND))
+#define E_MAIL_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_BACKEND, EMailShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailShellBackend EMailShellBackend;
+typedef struct _EMailShellBackendClass EMailShellBackendClass;
+typedef struct _EMailShellBackendPrivate EMailShellBackendPrivate;
+
+struct _EMailShellBackend {
+ EShellBackend parent;
+ EMailShellBackendPrivate *priv;
+};
+
+struct _EMailShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+typedef enum {
+ E_MAIL_FOLDER_INBOX,
+ E_MAIL_FOLDER_DRAFTS,
+ E_MAIL_FOLDER_OUTBOX,
+ E_MAIL_FOLDER_SENT,
+ E_MAIL_FOLDER_TEMPLATES,
+ E_MAIL_FOLDER_LOCAL_INBOX
+} EMailFolderType;
+
+struct _EMFolderTreeModel;
+
+/* Globally available shell backend.
+ *
+ * XXX I don't like having this globally available but passing it around
+ * to all the various utilities that need to access the backend's data
+ * directory and local folders is too much of a pain for now. */
+extern EMailShellBackend *global_mail_shell_backend;
+
+GType e_mail_shell_backend_get_type (void);
+void e_mail_shell_backend_register_type
+ (GTypeModule *type_module);
+CamelFolder * e_mail_shell_backend_get_folder
+ (EMailShellBackend *mail_shell_backend,
+ EMailFolderType folder_type);
+const gchar * e_mail_shell_backend_get_folder_uri
+ (EMailShellBackend *mail_shell_backend,
+ EMailFolderType folder_type);
+struct _EMFolderTreeModel *
+ e_mail_shell_backend_get_folder_tree_model
+ (EMailShellBackend *mail_shell_backend);
+void e_mail_shell_backend_add_store
+ (EMailShellBackend *mail_shell_backend,
+ CamelStore *store,
+ const gchar *name);
+CamelStore * e_mail_shell_backend_get_local_store
+ (EMailShellBackend *mail_shell_backend);
+CamelStore * e_mail_shell_backend_load_store_by_uri
+ (EMailShellBackend *mail_shell_backend,
+ const gchar *uri,
+ const gchar *name);
+void e_mail_shell_backend_remove_store
+ (EMailShellBackend *mail_shell_backend,
+ CamelStore *store);
+void e_mail_shell_backend_remove_store_by_uri
+ (EMailShellBackend *mail_shell_backend,
+ const gchar *uri);
+void e_mail_shell_backend_stores_foreach
+ (EMailShellBackend *mail_shell_backend,
+ GHFunc func,
+ gpointer user_data);
+
+/* XXX Find a better place for this function. */
+GSList * e_mail_labels_get_filter_options(void);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_BACKEND_H */
diff --cc mail/e-mail-shell-content.c
index de07873,0000000..203876f
mode 100644,000000..100644
--- a/mail/e-mail-shell-content.c
+++ b/mail/e-mail-shell-content.c
@@@ -1,1016 -1,0 +1,1016 @@@
+/*
+ * e-mail-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-content.h"
+
+#include <glib/gi18n.h>
+#include <camel/camel-store.h>
+#include <libedataserver/e-data-server-util.h>
+
+#include "e-util/gconf-bridge.h"
+#include "widgets/menus/gal-view-etable.h"
+#include "widgets/menus/gal-view-instance.h"
+
+#include "em-folder-view.h"
+#include "em-search-context.h"
+#include "em-utils.h"
+#include "mail-config.h"
+#include "mail-ops.h"
+
+#include "e-mail-reader.h"
+#include "e-mail-search-bar.h"
+#include "e-mail-shell-backend.h"
+#include "e-mail-shell-view-actions.h"
+
+#define E_MAIL_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentPrivate))
+
+struct _EMailShellContentPrivate {
+ GtkWidget *paned;
+ GtkWidget *message_list;
+ GtkWidget *search_bar;
+
+ EMFormatHTMLDisplay *html_display;
+ GalViewInstance *view_instance;
+
+ gchar *selected_uid;
+
+ /* ETable scrolling hack */
+ gdouble default_scrollbar_position;
+
+ guint paned_binding_id;
+ guint scroll_timeout_id;
+
+ /* Signal handler IDs */
+ guint message_list_built_id;
+ guint message_list_scrolled_id;
+
+ guint preview_visible : 1;
+ guint suppress_message_selection : 1;
+ guint vertical_view : 1;
+ guint show_deleted : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_PREVIEW_VISIBLE,
+ PROP_SHOW_DELETED,
+ PROP_VERTICAL_VIEW
+};
+
+static gpointer parent_class;
+static GType mail_shell_content_type;
+
+static void
+mail_shell_content_etree_unfreeze (MessageList *message_list,
+ GdkEvent *event)
+{
+ ETableItem *item;
+ GObject *object;
+
+ item = e_tree_get_item (message_list->tree);
+ object = G_OBJECT (((GnomeCanvasItem *) item)->canvas);
+
+ g_object_set_data (object, "freeze-cursor", 0);
+}
+
+static void
+mail_shell_content_message_list_scrolled_cb (EMailShellContent *mail_shell_content,
+ MessageList *message_list)
+{
+ const gchar *key;
+ gdouble position;
+ gchar *value;
+
+ /* Save the scrollbar position for the current folder. */
+
+ if (message_list->folder == NULL)
+ return;
+
+ key = "evolution:list_scroll_position";
+ position = message_list_get_scrollbar_position (message_list);
+ value = g_strdup_printf ("%f", position);
+
+ if (camel_object_meta_set (message_list->folder, key, value))
+ camel_object_state_write (message_list->folder);
+
+ g_free (value);
+}
+
+static gboolean
+mail_shell_content_scroll_timeout_cb (EMailShellContent *mail_shell_content)
+{
+ EMailShellContentPrivate *priv = mail_shell_content->priv;
+ MessageList *message_list;
+ EMailReader *reader;
+ const gchar *key;
+ gdouble position;
+ gchar *value;
+
+ /* Initialize the scrollbar position for the current folder
+ * and setup a callback to handle scrollbar position changes. */
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ position = priv->default_scrollbar_position;
+
+ key = "evolution:list_scroll_position";
+ value = camel_object_meta_get (message_list->folder, key);
+
+ if (value != NULL) {
+ position = strtod (value, NULL);
+ g_free (value);
+ }
+
+ message_list_set_scrollbar_position (message_list, position);
+
+ priv->message_list_scrolled_id = g_signal_connect_swapped (
+ message_list, "message-list-scrolled",
+ G_CALLBACK (mail_shell_content_message_list_scrolled_cb),
+ mail_shell_content);
+
+ priv->scroll_timeout_id = 0;
+
+ return FALSE;
+}
+
+static void
+mail_shell_content_message_list_built_cb (EMailShellContent *mail_shell_content,
+ MessageList *message_list)
+{
+ EMailShellContentPrivate *priv = mail_shell_content->priv;
+ GtkScrolledWindow *scrolled_window;
+ GtkWidget *vscrollbar;
+ gdouble position = 0.0;
+
+ g_signal_handler_disconnect (
+ message_list, priv->message_list_built_id);
+ priv->message_list_built_id = 0;
+
+ if (message_list->cursor_uid == NULL && priv->selected_uid != NULL) {
+ CamelMessageInfo *info;
+
+ /* If the message isn't in the folder yet, keep selected_uid
+ * around, as it could be caught by a set_folder() at some
+ * later date. */
+ info = camel_folder_get_message_info (
+ message_list->folder, priv->selected_uid);
+ if (info != NULL) {
+ camel_folder_free_message_info (
+ message_list->folder, info);
+ e_mail_reader_set_message (
+ E_MAIL_READER (mail_shell_content),
+ priv->selected_uid, TRUE);
+ g_free (priv->selected_uid);
+ priv->selected_uid = NULL;
+ }
+
+ position = message_list_get_scrollbar_position (message_list);
+ }
+
+ priv->default_scrollbar_position = position;
+
+ /* FIXME This is a gross workaround for an ETable bug that I can't
+ * fix (Ximian bug #55303).
+ *
+ * Since e_canvas_item_region_show_relay() uses a timeout,
+ * we have to use a timeout of the same interval but a lower
+ * priority. */
+ priv->scroll_timeout_id = g_timeout_add_full (
+ G_PRIORITY_LOW, 250, (GSourceFunc)
+ mail_shell_content_scroll_timeout_cb,
+ mail_shell_content, NULL);
+
+ /* FIXME This is another ugly hack to hide a side-effect of the
+ * previous workaround. */
+ scrolled_window = GTK_SCROLLED_WINDOW (message_list);
+ vscrollbar = gtk_scrolled_window_get_vscrollbar (scrolled_window);
+ g_signal_connect_swapped (
+ vscrollbar, "button-press-event",
+ G_CALLBACK (mail_shell_content_etree_unfreeze),
+ message_list);
+}
+
+static void
+mail_shell_content_display_view_cb (EMailShellContent *mail_shell_content,
+ GalView *gal_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ if (GAL_IS_VIEW_ETABLE (gal_view))
+ gal_view_etable_attach_tree (
+ GAL_VIEW_ETABLE (gal_view), message_list->tree);
+}
+
+static void
+mail_shell_content_message_selected_cb (EMailShellContent *mail_shell_content,
+ const gchar *selected_uid,
+ MessageList *message_list)
+{
+ const gchar *key = "evolution:selected_uid";
+ CamelFolder *folder;
+
+ folder = message_list->folder;
+
+ /* This also gets triggered when selecting a store name on
+ * the sidebar such as "On This Computer", in which case
+ * 'folder' will be NULL. */
+ if (folder == NULL)
+ return;
+
+ if (camel_object_meta_set (folder, key, selected_uid))
+ camel_object_state_write (folder);
+
+ g_free (mail_shell_content->priv->selected_uid);
+ mail_shell_content->priv->selected_uid = NULL;
+}
+
+static void
+mail_shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_PREVIEW_VISIBLE:
+ e_mail_shell_content_set_preview_visible (
+ E_MAIL_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SHOW_DELETED:
+ e_mail_shell_content_set_show_deleted (
+ E_MAIL_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_VERTICAL_VIEW:
+ e_mail_shell_content_set_vertical_view (
+ E_MAIL_SHELL_CONTENT (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,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_PREVIEW_VISIBLE:
+ g_value_set_boolean (
+ value,
+ e_mail_shell_content_get_preview_visible (
+ E_MAIL_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SHOW_DELETED:
+ g_value_set_boolean (
+ value,
+ e_mail_shell_content_get_show_deleted (
+ E_MAIL_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_VERTICAL_VIEW:
+ g_value_set_boolean (
+ value,
+ e_mail_shell_content_get_vertical_view (
+ E_MAIL_SHELL_CONTENT (object)));
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_shell_content_dispose (GObject *object)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->paned != NULL) {
+ g_object_unref (priv->paned);
+ priv->paned = NULL;
+ }
+
+ if (priv->message_list != NULL) {
+ g_object_unref (priv->message_list);
+ priv->message_list = NULL;
+ }
+
+ if (priv->search_bar != NULL) {
+ g_object_unref (priv->search_bar);
+ priv->search_bar = NULL;
+ }
+
+ if (priv->html_display != NULL) {
+ g_object_unref (priv->html_display);
+ priv->html_display = NULL;
+ }
+
+ if (priv->view_instance != NULL) {
+ g_object_unref (priv->view_instance);
+ priv->view_instance = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_shell_content_finalize (GObject *object)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
+
+ g_free (priv->selected_uid);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_shell_content_constructed (GObject *object)
+{
+ EMailShellContentPrivate *priv;
+ EShellContent *shell_content;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ EMailReader *reader;
+ MessageList *message_list;
+ GConfBridge *bridge;
+ GtkWidget *container;
+ GtkWidget *widget;
+ GtkHTML *html;
+ GalViewCollection *view_collection;
+ const gchar *key;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
+ priv->html_display = em_format_html_display_new ();
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ view_collection = shell_view_class->view_collection;
+
+ html = EM_FORMAT_HTML (priv->html_display)->html;
+
+ /* Build content widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = gtk_vpaned_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->paned = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = message_list_new (shell_backend);
+ gtk_paned_add1 (GTK_PANED (container), widget);
+ priv->message_list = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_vbox_new (FALSE, 1);
+ gtk_paned_add2 (GTK_PANED (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (html));
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ gtk_widget_show (GTK_WIDGET (html));
+ gtk_widget_show (widget);
+
+ widget = e_mail_search_bar_new (html);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->search_bar = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ g_signal_connect_swapped (
+ widget, "changed",
+ G_CALLBACK (em_format_redraw), priv->html_display);
+
+ /* Load the view instance. */
+
+ e_mail_shell_content_update_view_instance (
+ E_MAIL_SHELL_CONTENT (shell_content));
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (priv->paned);
+ key = "/apps/evolution/mail/display/paned_size";
+ gconf_bridge_bind_property_delayed (bridge, key, object, "position");
+
+ object = G_OBJECT (shell_content);
+ key = "/apps/evolution/mail/display/show_deleted";
+ gconf_bridge_bind_property (bridge, key, object, "show-deleted");
+
+ /* Message list customizations. */
+
+ reader = E_MAIL_READER (shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ g_signal_connect_swapped (
+ message_list, "message-selected",
+ G_CALLBACK (mail_shell_content_message_selected_cb),
+ shell_content);
+}
+
+static guint32
+mail_shell_content_check_state (EShellContent *shell_content)
+{
+ return e_mail_reader_check_state (E_MAIL_READER (shell_content));
+}
+
+static GtkActionGroup *
+mail_shell_content_get_action_group (EMailReader *reader)
+{
+ EShellContent *shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ 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);
+
+ return E_SHELL_WINDOW_ACTION_GROUP_MAIL (shell_window);
+}
+
+static gboolean
+mail_shell_content_get_hide_deleted (EMailReader *reader)
+{
+ EMailShellContent *mail_shell_content;
+
+ mail_shell_content = E_MAIL_SHELL_CONTENT (reader);
+
+ return !e_mail_shell_content_get_show_deleted (mail_shell_content);
+}
+
+static EMFormatHTMLDisplay *
+mail_shell_content_get_html_display (EMailReader *reader)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
+
+ return priv->html_display;
+}
+
+static MessageList *
+mail_shell_content_get_message_list (EMailReader *reader)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
+
+ return MESSAGE_LIST (priv->message_list);
+}
+
+static EShellBackend *
+mail_shell_content_get_shell_backend (EMailReader *reader)
+{
+ EShellContent *shell_content;
+ EShellView *shell_view;
+
+ shell_content = E_SHELL_CONTENT (reader);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+
+ return e_shell_view_get_shell_backend (shell_view);
+}
+
+static GtkWindow *
+mail_shell_content_get_window (EMailReader *reader)
+{
+ EShellContent *shell_content;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ 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);
+
+ return GTK_WINDOW (shell_window);
+}
+
+static void
+mail_shell_content_set_folder (EMailReader *reader,
+ CamelFolder *folder,
+ const gchar *folder_uri)
+{
+ EMailShellContentPrivate *priv;
+ EMailReaderIface *default_iface;
+ MessageList *message_list;
+ gboolean different_folder;
+ gchar *meta_data;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
+
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_freeze (message_list);
+
+ different_folder =
+ message_list->folder != NULL &&
+ folder != message_list->folder;
+
+ /* Chain up to interface's default set_folder() method. */
+ default_iface = g_type_default_interface_peek (E_TYPE_MAIL_READER);
+ default_iface->set_folder (reader, folder, folder_uri);
+
+ if (folder == NULL)
+ goto exit;
+
+ mail_refresh_folder (folder, NULL, NULL);
+
+ /* This function gets triggered several times at startup,
+ * so we don't want to reset the message suppression state
+ * unless we're actually switching to a different folder. */
+ if (different_folder)
+ priv->suppress_message_selection = FALSE;
+
+ if (!priv->suppress_message_selection)
+ meta_data = camel_object_meta_get (
+ folder, "evolution:selected_uid");
+ else
+ meta_data = NULL;
+
+ g_free (priv->selected_uid);
+ priv->selected_uid = meta_data;
+
+ /* This is a one-time-only callback. */
+ if (message_list->cursor_uid == NULL && priv->message_list_built_id == 0)
+ priv->message_list_built_id = g_signal_connect_swapped (
+ message_list, "message-list-built",
+ G_CALLBACK (mail_shell_content_message_list_built_cb),
+ reader);
+
+exit:
+ message_list_thaw (message_list);
+}
+
+static void
+mail_shell_content_show_search_bar (EMailReader *reader)
+{
+ EMailShellContentPrivate *priv;
+
+ priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
+
+ gtk_widget_show (priv->search_bar);
+}
+
+static void
+mail_shell_content_class_init (EMailShellContentClass *class)
+{
+ GObjectClass *object_class;
+ EShellContentClass *shell_content_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailShellContentPrivate));
+
+ 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->finalize = mail_shell_content_finalize;
+ object_class->constructed = mail_shell_content_constructed;
+
+ shell_content_class = E_SHELL_CONTENT_CLASS (class);
+ shell_content_class->new_search_context = em_search_context_new;
+ shell_content_class->check_state = mail_shell_content_check_state;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREVIEW_VISIBLE,
+ g_param_spec_boolean (
+ "preview-visible",
+ _("Preview is Visible"),
+ _("Whether the preview pane is visible"),
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_DELETED,
+ g_param_spec_boolean (
+ "show-deleted",
+ "Show Deleted",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_VERTICAL_VIEW,
+ g_param_spec_boolean (
+ "vertical-view",
+ _("Vertical View"),
+ _("Whether vertical view is enabled"),
+ FALSE,
+ G_PARAM_READWRITE));
+}
+
+static void
+mail_shell_content_iface_init (EMailReaderIface *iface)
+{
+ iface->get_action_group = mail_shell_content_get_action_group;
+ iface->get_hide_deleted = mail_shell_content_get_hide_deleted;
+ iface->get_html_display = mail_shell_content_get_html_display;
+ iface->get_message_list = mail_shell_content_get_message_list;
+ iface->get_shell_backend = mail_shell_content_get_shell_backend;
+ iface->get_window = mail_shell_content_get_window;
+ iface->set_folder = mail_shell_content_set_folder;
+ iface->show_search_bar = mail_shell_content_show_search_bar;
+}
+
+static void
+mail_shell_content_init (EMailShellContent *mail_shell_content)
+{
+ mail_shell_content->priv =
+ E_MAIL_SHELL_CONTENT_GET_PRIVATE (mail_shell_content);
+
+ mail_shell_content->priv->preview_visible = TRUE;
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_mail_shell_content_get_type (void)
+{
+ return mail_shell_content_type;
+}
+
+void
+e_mail_shell_content_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EMailShellContentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_shell_content_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailShellContent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_shell_content_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) mail_shell_content_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ mail_shell_content_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_CONTENT,
+ "EMailShellContent", &type_info, 0);
+
+ g_type_module_add_interface (
+ type_module, mail_shell_content_type,
+ E_TYPE_MAIL_READER, &iface_info);
+}
+
+GtkWidget *
+e_mail_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_SHELL_CONTENT,
+ "shell-view", shell_view, NULL);
+}
+
+gboolean
+e_mail_shell_content_get_preview_visible (EMailShellContent *mail_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
+
+ return mail_shell_content->priv->preview_visible;
+}
+
+void
+e_mail_shell_content_set_preview_visible (EMailShellContent *mail_shell_content,
+ gboolean preview_visible)
+{
+ GtkPaned *paned;
+ GtkWidget *child;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ if (preview_visible == mail_shell_content->priv->preview_visible)
+ return;
+
+ paned = GTK_PANED (mail_shell_content->priv->paned);
+ child = gtk_paned_get_child2 (paned);
+
+ if (preview_visible)
+ gtk_widget_show (child);
+ else
+ gtk_widget_hide (child);
+
+ mail_shell_content->priv->preview_visible = preview_visible;
+
+ g_object_notify (G_OBJECT (mail_shell_content), "preview-visible");
+}
+
+gboolean
+e_mail_shell_content_get_show_deleted (EMailShellContent *mail_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
+
+ return mail_shell_content->priv->show_deleted;
+}
+
+void
+e_mail_shell_content_set_show_deleted (EMailShellContent *mail_shell_content,
+ gboolean show_deleted)
+{
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ mail_shell_content->priv->show_deleted = show_deleted;
+
+ g_object_notify (G_OBJECT (mail_shell_content), "show-deleted");
+}
+
+gboolean
+e_mail_shell_content_get_vertical_view (EMailShellContent *mail_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_CONTENT (mail_shell_content), FALSE);
+
+ return mail_shell_content->priv->vertical_view;
+}
+
+void
+e_mail_shell_content_set_vertical_view (EMailShellContent *mail_shell_content,
+ gboolean vertical_view)
+{
+ GConfBridge *bridge;
+ GtkWidget *old_paned;
+ GtkWidget *new_paned;
+ GtkWidget *child1;
+ GtkWidget *child2;
+ guint binding_id;
+ const gchar *key;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ if (vertical_view == mail_shell_content->priv->vertical_view)
+ return;
+
+ bridge = gconf_bridge_get ();
+ old_paned = mail_shell_content->priv->paned;
+ binding_id = mail_shell_content->priv->paned_binding_id;
+
+ child1 = gtk_paned_get_child1 (GTK_PANED (old_paned));
+ child2 = gtk_paned_get_child2 (GTK_PANED (old_paned));
+
+ if (binding_id > 0)
+ gconf_bridge_unbind (bridge, binding_id);
+
+ if (vertical_view) {
+ new_paned = gtk_hpaned_new ();
+ key = "/apps/evolution/mail/display/hpaned_size";
+ } else {
+ new_paned = gtk_vpaned_new ();
+ key = "/apps/evolution/mail/display/paned_size";
+ }
+
+ gtk_widget_reparent (child1, new_paned);
+ gtk_widget_reparent (child2, new_paned);
+ gtk_widget_show (new_paned);
+
+ gtk_widget_destroy (old_paned);
+ gtk_container_add (GTK_CONTAINER (mail_shell_content), new_paned);
+
+ binding_id = gconf_bridge_bind_property_delayed (
+ bridge, key, G_OBJECT (new_paned), "position");
+
+ mail_shell_content->priv->vertical_view = vertical_view;
+ mail_shell_content->priv->paned_binding_id = binding_id;
+ mail_shell_content->priv->paned = g_object_ref (new_paned);
+
+ e_mail_shell_content_update_view_instance (mail_shell_content);
+
+ g_object_notify (G_OBJECT (mail_shell_content), "vertical-view");
+}
+
+GalViewInstance *
+e_mail_shell_content_get_view_instance (EMailShellContent *mail_shell_content)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_CONTENT (mail_shell_content), NULL);
+
+ return mail_shell_content->priv->view_instance;
+}
+
+void
+e_mail_shell_content_set_search_strings (EMailShellContent *mail_shell_content,
+ GSList *search_strings)
+{
+ EMailSearchBar *search_bar;
+ ESearchingTokenizer *tokenizer;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ search_bar = E_MAIL_SEARCH_BAR (mail_shell_content->priv->search_bar);
+ tokenizer = e_mail_search_bar_get_tokenizer (search_bar);
+
+ e_searching_tokenizer_set_secondary_case_sensitivity (tokenizer, FALSE);
+ e_searching_tokenizer_set_secondary_search_string (tokenizer, NULL);
+
+ while (search_strings != NULL) {
+ e_searching_tokenizer_add_secondary_search_string (
+ tokenizer, search_strings->data);
+ search_strings = g_slist_next (search_strings);
+ }
+
+ e_mail_search_bar_changed (search_bar);
+}
+
+void
+e_mail_shell_content_update_view_instance (EMailShellContent *mail_shell_content)
+{
+ EMailReader *reader;
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ GalViewCollection *view_collection;
+ GalViewInstance *view_instance;
+ MessageList *message_list;
+ gboolean outgoing_folder;
+ gboolean show_vertical_view;
+ gchar *view_id;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
+
+ shell_content = E_SHELL_CONTENT (mail_shell_content);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ view_collection = shell_view_class->view_collection;
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ /* If no folder is selected, return silently. */
+ if (message_list->folder == NULL)
+ return;
+
+ /* If we have a folder, we should also have a URI. */
+ g_return_if_fail (message_list->folder_uri != NULL);
+
+ if (mail_shell_content->priv->view_instance != NULL) {
+ g_object_unref (mail_shell_content->priv->view_instance);
+ mail_shell_content->priv->view_instance = NULL;
+ }
+
+ view_id = mail_config_folder_to_safe_url (message_list->folder);
+ view_instance = e_shell_view_new_view_instance (shell_view, view_id);
+ mail_shell_content->priv->view_instance = view_instance;
+
+ show_vertical_view =
+ e_mail_shell_content_get_vertical_view (mail_shell_content);
+
+ if (show_vertical_view) {
+ gchar *filename;
+ gchar *safe_view_id;
+
+ /* Force the view instance into vertical view. */
+
+ g_free (view_instance->custom_filename);
+ g_free (view_instance->current_view_filename);
+
+ safe_view_id = g_strdup (view_id);
+ e_filename_make_safe (safe_view_id);
+
+ filename = g_strdup_printf (
+ "custom_wide_view-%s.xml", safe_view_id);
+ view_instance->custom_filename = g_build_filename (
+ view_collection->local_dir, filename, NULL);
+ g_free (filename);
+
+ filename = g_strdup_printf (
+ "current_wide_view-%s.xml", safe_view_id);
+ view_instance->current_view_filename = g_build_filename (
+ view_collection->local_dir, filename, NULL);
+ g_free (filename);
+
+ g_free (safe_view_id);
+ }
+
+ g_free (view_id);
+
+ outgoing_folder =
+ em_utils_folder_is_drafts (
+ message_list->folder, message_list->folder_uri) ||
+ em_utils_folder_is_outbox (
+ message_list->folder, message_list->folder_uri) ||
+ em_utils_folder_is_sent (
+ message_list->folder, message_list->folder_uri);
+
+ if (outgoing_folder) {
+ if (show_vertical_view)
+ gal_view_instance_set_default_view (
+ view_instance, "Wide_View_Sent");
+ else
+ gal_view_instance_set_default_view (
+ view_instance, "As_Sent_Folder");
+ } else if (show_vertical_view) {
+ gal_view_instance_set_default_view (
+ view_instance, "Wide_View_Normal");
+ }
+
+ gal_view_instance_load (view_instance);
+
+ if (!gal_view_instance_exists (view_instance)) {
+ gchar *state_filename;
+
+ state_filename = mail_config_folder_to_cachename (
+ message_list->folder, "et-header-");
+
+ if (g_file_test (state_filename, G_FILE_TEST_IS_REGULAR)) {
+ ETableSpecification *spec;
+ ETableState *state;
+ GalView *view;
+ gchar *spec_filename;
+
+ spec = e_table_specification_new ();
+ spec_filename = g_build_filename (
+ EVOLUTION_ETSPECDIR,
+ "message-list.etspec",
+ NULL);
+ e_table_specification_load_from_file (
+ spec, spec_filename);
+ g_free (spec_filename);
+
+ state = e_table_state_new ();
+ view = gal_view_etable_new (spec, "");
+
+ e_table_state_load_from_file (
+ state, state_filename);
+ gal_view_etable_set_state (
+ GAL_VIEW_ETABLE (view), state);
+ gal_view_instance_set_custom_view (
+ view_instance, view);
+
+ g_object_unref (state);
+ g_object_unref (view);
+ g_object_unref (spec);
+ }
+
+ g_free (state_filename);
+ }
+
+ g_signal_connect (
+ view_instance, "display-view",
+ G_CALLBACK (mail_shell_content_display_view_cb),
+ mail_shell_content);
+
+ mail_shell_content_display_view_cb (
+ mail_shell_content,
+ gal_view_instance_get_current_view (view_instance));
+}
diff --cc mail/e-mail-shell-content.h
index 2c5da1b,0000000..57d2438
mode 100644,000000..100644
--- a/mail/e-mail-shell-content.h
+++ b/mail/e-mail-shell-content.h
@@@ -1,94 -1,0 +1,94 @@@
+/*
+ * e-mail-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_CONTENT_H
+#define E_MAIL_SHELL_CONTENT_H
+
+#include <shell/e-shell-content.h>
+#include <shell/e-shell-view.h>
+
+#include <mail/em-format-html-display.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SHELL_CONTENT \
+ (e_mail_shell_content_get_type ())
+#define E_MAIL_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContent))
+#define E_MAIL_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentClass))
+#define E_IS_MAIL_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT))
+#define E_IS_MAIL_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_SHELL_CONTENT))
+#define E_MAIL_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_SHELL_CONTENT, EMailShellContentClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailShellContent EMailShellContent;
+typedef struct _EMailShellContentClass EMailShellContentClass;
+typedef struct _EMailShellContentPrivate EMailShellContentPrivate;
+
+struct _EMailShellContent {
+ EShellContent parent;
+ EMailShellContentPrivate *priv;
+};
+
+struct _EMailShellContentClass {
+ EShellContentClass parent_class;
+};
+
+GType e_mail_shell_content_get_type (void);
+void e_mail_shell_content_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_mail_shell_content_new(EShellView *shell_view);
+gboolean e_mail_shell_content_get_preview_visible
+ (EMailShellContent *mail_shell_content);
+void e_mail_shell_content_set_preview_visible
+ (EMailShellContent *mail_shell_content,
+ gboolean preview_visible);
+gboolean e_mail_shell_content_get_show_deleted
+ (EMailShellContent *mail_shell_content);
+void e_mail_shell_content_set_show_deleted
+ (EMailShellContent *mail_shell_content,
+ gboolean show_deleted);
+gboolean e_mail_shell_content_get_vertical_view
+ (EMailShellContent *mail_shell_content);
+void e_mail_shell_content_set_vertical_view
+ (EMailShellContent *mail_shell_content,
+ gboolean vertical_view);
+GalViewInstance *
+ e_mail_shell_content_get_view_instance
+ (EMailShellContent *mail_shell_content);
+void e_mail_shell_content_set_search_strings
+ (EMailShellContent *mail_shell_content,
+ GSList *search_strings);
+void e_mail_shell_content_update_view_instance
+ (EMailShellContent *mail_shell_content);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_CONTENT_H */
diff --cc mail/e-mail-shell-migrate.c
index 9a31f67,0000000..6202224
mode 100644,000000..100644
--- a/mail/e-mail-shell-migrate.c
+++ b/mail/e-mail-shell-migrate.c
@@@ -1,2989 -1,0 +1,3105 @@@
+/*
+ * e-mail-shell-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-migrate.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utime.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <regex.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <gtk/gtk.h>
+
+#include <gconf/gconf-client.h>
+
+#include <camel/camel.h>
+#include <camel/camel-store.h>
+#include <camel/camel-session.h>
+#include <camel/camel-file-utils.h>
+#include <camel/camel-disco-folder.h>
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+
+#include <e-util/e-util.h>
++#include <libedataserver/e-xml-utils.h>
+#include <libedataserver/e-data-server-util.h>
+#include <e-util/e-xml-utils.h>
+
+#include "e-util/e-account-utils.h"
+#include "e-util/e-bconf-map.h"
+#include "e-util/e-error.h"
+#include "e-util/e-util-private.h"
+#include "e-util/e-plugin.h"
+#include "e-util/e-signature-utils.h"
+
+#include "e-mail-shell-backend.h"
+#include "shell/e-shell-migrate.h"
+
+#include "mail-config.h"
+#include "em-utils.h"
+
+#define d(x) x
+
+#ifndef G_OS_WIN32
+/* No versions previous to 2.8 or thereabouts have been available on
+ * Windows, so don't bother with upgrade support from earlier versions
+ * on Win32. Do try to support upgrades from 2.12 and later to the
+ * current version.
+ */
+
+/* upgrade helper functions */
+static xmlDocPtr
+emm_load_xml (const char *dirname, const char *filename)
+{
+ xmlDocPtr doc;
+ struct stat st;
+ char *path;
+
+ path = g_strdup_printf ("%s/%s", dirname, filename);
+ if (stat (path, &st) == -1 || !(doc = xmlParseFile (path))) {
+ g_free (path);
+ return NULL;
+ }
+
+ g_free (path);
+
+ return doc;
+}
+
+static int
+emm_save_xml (xmlDocPtr doc, const char *dirname, const char *filename)
+{
+ char *path;
+ int retval;
+
+ path = g_strdup_printf ("%s/%s", dirname, filename);
+ retval = e_xml_save_file (path, doc);
+ g_free (path);
+
+ return retval;
+}
+
+static xmlNodePtr
+xml_find_node (xmlNodePtr parent, const char *name)
+{
+ xmlNodePtr node;
+
+ node = parent->children;
+ while (node != NULL) {
+ if (node->name && !strcmp ((char *)node->name, name))
+ return node;
+
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+static void
+upgrade_xml_uris (xmlDocPtr doc, char * (* upgrade_uri) (const char *uri))
+{
+ xmlNodePtr root, node;
+ char *uri, *new;
+
+ if (!doc || !(root = xmlDocGetRootElement (doc)))
+ return;
+
+ if (!root->name || strcmp ((char *)root->name, "filteroptions") != 0) {
+ /* root node is not <filteroptions>, nothing to upgrade */
+ return;
+ }
+
+ if (!(node = xml_find_node (root, "ruleset"))) {
+ /* no ruleset node, nothing to upgrade */
+ return;
+ }
+
+ node = node->children;
+ while (node != NULL) {
+ if (node->name && !strcmp ((char *)node->name, "rule")) {
+ xmlNodePtr actionset, part, val, n;
+
+ if ((actionset = xml_find_node (node, "actionset"))) {
+ /* filters.xml */
+ part = actionset->children;
+ while (part != NULL) {
+ if (part->name && !strcmp ((char *)part->name, "part")) {
+ val = part->children;
+ while (val != NULL) {
+ if (val->name && !strcmp ((char *)val->name, "value")) {
+ char *type;
+
+ type = (char *)xmlGetProp (val, (const unsigned char *)"type");
+ if (type && !strcmp ((char *)type, "folder")) {
+ if ((n = xml_find_node (val, "folder"))) {
+ uri = (char *)xmlGetProp (n, (const unsigned char *)"uri");
+ new = upgrade_uri (uri);
+ xmlFree (uri);
+
+ xmlSetProp (n, (const unsigned char *)"uri", (unsigned char *)new);
+ g_free (new);
+ }
+ }
+
+ xmlFree (type);
+ }
+
+ val = val->next;
+ }
+ }
+
+ part = part->next;
+ }
+ } else if ((actionset = xml_find_node (node, "sources"))) {
+ /* vfolders.xml */
+ n = actionset->children;
+ while (n != NULL) {
+ if (n->name && !strcmp ((char *)n->name, "folder")) {
+ uri = (char *)xmlGetProp (n, (const unsigned char *)"uri");
+ new = upgrade_uri (uri);
+ xmlFree (uri);
+
+ xmlSetProp (n, (const unsigned char *)"uri", (unsigned char *)new);
+ g_free (new);
+ }
+
+ n = n->next;
+ }
+ }
+ }
+
+ node = node->next;
+ }
+}
+
+/* 1.0 upgrade functions & data */
+
+/* as much info as we have on a given account */
+struct _account_info_1_0 {
+ char *name;
+ char *uri;
+ char *base_uri;
+ union {
+ struct {
+ /* for imap */
+ char *namespace;
+ char *namespace_full;
+ guint32 capabilities;
+ GHashTable *folders;
+ char dir_sep;
+ } imap;
+ } u;
+};
+
+struct _imap_folder_info_1_0 {
+ char *folder;
+ /* encoded? decoded? canonicalised? */
+ char dir_sep;
+};
+
+static GHashTable *accounts_1_0 = NULL;
+static GHashTable *accounts_name_1_0 = NULL;
+
+static void
+imap_folder_info_1_0_free (struct _imap_folder_info_1_0 *fi)
+{
+ g_free(fi->folder);
+ g_free(fi);
+}
+
+static void
+account_info_1_0_free (struct _account_info_1_0 *ai)
+{
+ g_free(ai->name);
+ g_free(ai->uri);
+ g_free(ai->base_uri);
+ g_free(ai->u.imap.namespace);
+ g_free(ai->u.imap.namespace_full);
+ g_hash_table_destroy(ai->u.imap.folders);
+ g_free(ai);
+}
+
+static char *
+get_base_uri(const char *val)
+{
+ const char *tmp;
+
+ tmp = strchr(val, ':');
+ if (tmp) {
+ tmp++;
+ if (strncmp(tmp, "//", 2) == 0)
+ tmp += 2;
+ tmp = strchr(tmp, '/');
+ }
+
+ if (tmp)
+ return g_strndup(val, tmp-val);
+ else
+ return g_strdup(val);
+}
+
+static char *
+upgrade_xml_uris_1_0 (const char *uri)
+{
+ char *out = NULL;
+
+ /* upgrades camel uri's */
+ if (strncmp (uri, "imap:", 5) == 0) {
+ char *base_uri, dir_sep, *folder, *p;
+ struct _account_info_1_0 *ai;
+
+ /* add namespace, canonicalise dir_sep to / */
+ base_uri = get_base_uri (uri);
+ ai = g_hash_table_lookup (accounts_1_0, base_uri);
+
+ if (ai == NULL) {
+ g_free (base_uri);
+ return NULL;
+ }
+
+ dir_sep = ai->u.imap.dir_sep;
+ if (dir_sep == 0) {
+ /* no dir_sep listed, try get it from the namespace, if set */
+ if (ai->u.imap.namespace != NULL) {
+ p = ai->u.imap.namespace;
+ while ((dir_sep = *p++)) {
+ if (dir_sep < '0'
+ || (dir_sep > '9' && dir_sep < 'A')
+ || (dir_sep > 'Z' && dir_sep < 'a')
+ || (dir_sep > 'z')) {
+ break;
+ }
+ p++;
+ }
+ }
+
+ /* give up ... */
+ if (dir_sep == 0) {
+ g_free (base_uri);
+ return NULL;
+ }
+ }
+
+ folder = g_strdup (uri + strlen (base_uri) + 1);
+
+ /* Add the namespace before the mailbox name, unless the mailbox is INBOX */
+ if (ai->u.imap.namespace && strcmp ((char *)folder, "INBOX") != 0)
+ out = g_strdup_printf ("%s/%s/%s", base_uri, ai->u.imap.namespace, folder);
+ else
+ out = g_strdup_printf ("%s/%s", base_uri, folder);
+
+ p = out;
+ while (*p) {
+ if (*p == dir_sep)
+ *p = '/';
+ p++;
+ }
+
+ g_free (folder);
+ g_free (base_uri);
+ } else if (strncmp (uri, "exchange:", 9) == 0) {
+ char *base_uri, *folder, *p;
+
+ /* exchange://user host/exchange/ * -> exchange://user host/personal/ * */
+ /* Any url encoding (%xx) in the folder name is also removed */
+ base_uri = get_base_uri (uri);
+ uri += strlen (base_uri) + 1;
+ if (strncmp (uri, "exchange/", 9) == 0) {
+ folder = e_bconf_url_decode (uri + 9);
+ p = strchr (folder, '/');
+ out = g_strdup_printf ("%s/personal%s", base_uri, p ? p : "/");
+ g_free (folder);
+ }
+ } else if (strncmp (uri, "exchanget:", 10) == 0) {
+ /* these should be converted in the accounts table when it is loaded */
+ g_warning ("exchanget: uri not converted: '%s'", uri);
+ }
+
+ return out;
+}
+
+static char *
+parse_lsub (const char *lsub, char *dir_sep)
+{
+ static int comp;
+ static regex_t pat;
+ regmatch_t match[3];
- char *m = "^\\* LSUB \\([^)]*\\) \"?([^\" ]+)\"? \"?(.*)\"?$";
++ const gchar *m = "^\\* LSUB \\([^)]*\\) \"?([^\" ]+)\"? \"?(.*)\"?$";
+
+ if (!comp) {
+ if (regcomp (&pat, m, REG_EXTENDED|REG_ICASE) == -1) {
+ g_warning ("reg comp '%s' failed: %s", m, g_strerror (errno));
+ return NULL;
+ }
+ comp = 1;
+ }
+
+ if (regexec (&pat, lsub, 3, match, 0) == 0) {
+ if (match[1].rm_so != -1 && match[2].rm_so != -1) {
+ if (dir_sep)
+ *dir_sep = (match[1].rm_eo - match[1].rm_so == 1) ? lsub[match[1].rm_so] : 0;
+ return g_strndup (lsub + match[2].rm_so, match[2].rm_eo - match[2].rm_so);
+ }
+ }
+
+ return NULL;
+}
+
+static gboolean
+read_imap_storeinfo (struct _account_info_1_0 *si)
+{
+ FILE *storeinfo;
+ guint32 tmp;
+ char *buf, *folder, dir_sep, *path, *name, *p;
+ struct _imap_folder_info_1_0 *fi;
+
+ si->u.imap.folders = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) imap_folder_info_1_0_free);
+
+ /* get details from uri first */
+ name = strstr (si->uri, ";override_namespace");
+ if (name) {
+ name = strstr (si->uri, ";namespace=");
+ if (name) {
+ char *end;
+
+ name += strlen (";namespace=");
+ if (*name == '\"') {
+ name++;
+ end = strchr (name, '\"');
+ } else {
+ end = strchr (name, ';');
+ }
+
+ if (end) {
+ /* try get the dir_sep from the namespace */
+ si->u.imap.namespace = g_strndup (name, end-name);
+
+ p = si->u.imap.namespace;
+ while ((dir_sep = *p++)) {
+ if (dir_sep < '0'
+ || (dir_sep > '9' && dir_sep < 'A')
+ || (dir_sep > 'Z' && dir_sep < 'a')
+ || (dir_sep > 'z')) {
+ si->u.imap.dir_sep = dir_sep;
+ break;
+ }
+ p++;
+ }
+ }
+ }
+ }
+
+ /* now load storeinfo if it exists */
+ path = g_build_filename (g_get_home_dir (), "evolution", "mail", "imap", si->base_uri + 7, "storeinfo", NULL);
+ storeinfo = fopen (path, "r");
+ g_free (path);
+ if (storeinfo == NULL) {
+ g_warning ("could not find imap store info '%s'", path);
+ return FALSE;
+ }
+
+ /* ignore version */
+ camel_file_util_decode_uint32 (storeinfo, &tmp);
+ camel_file_util_decode_uint32 (storeinfo, &si->u.imap.capabilities);
+ g_free (si->u.imap.namespace);
+ camel_file_util_decode_string (storeinfo, &si->u.imap.namespace);
+ camel_file_util_decode_uint32 (storeinfo, &tmp);
+ si->u.imap.dir_sep = tmp;
+ /* strip trailing dir_sep or / */
+ if (si->u.imap.namespace
+ && (si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] == si->u.imap.dir_sep
+ || si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] == '/')) {
+ si->u.imap.namespace[strlen (si->u.imap.namespace) - 1] = 0;
+ }
+
+ d(printf ("namespace '%s' dir_sep '%c'\n", si->u.imap.namespace, si->u.imap.dir_sep ? si->u.imap.dir_sep : '?'));
+
+ while (camel_file_util_decode_string (storeinfo, &buf) == 0) {
+ folder = parse_lsub (buf, &dir_sep);
+ if (folder) {
+ fi = g_new0 (struct _imap_folder_info_1_0, 1);
+ fi->folder = folder;
+ fi->dir_sep = dir_sep;
+#if d(!)0
+ printf (" add folder '%s' ", folder);
+ if (dir_sep)
+ printf ("'%c'\n", dir_sep);
+ else
+ printf ("NIL\n");
+#endif
+ g_hash_table_insert (si->u.imap.folders, fi->folder, fi);
+ } else {
+ g_warning ("Could not parse LIST result '%s'\n", buf);
+ }
+ }
+
+ fclose (storeinfo);
+
+ return TRUE;
+}
+
+static gboolean
+load_accounts_1_0 (xmlDocPtr doc)
+{
+ xmlNodePtr source;
+ char *val, *tmp;
+ int count = 0, i;
+ char key[32];
+
+ if (!(source = e_bconf_get_path (doc, "/Mail/Accounts")))
+ return TRUE;
+
+ if ((val = e_bconf_get_value (source, "num"))) {
+ count = atoi (val);
+ xmlFree (val);
+ }
+
+ /* load account upgrade info for each account */
+ for (i = 0; i < count; i++) {
+ struct _account_info_1_0 *ai;
+ char *rawuri;
+
+ sprintf (key, "source_url_%d", i);
+ if (!(rawuri = e_bconf_get_value (source, key)))
+ continue;
+
+ ai = g_malloc0 (sizeof (struct _account_info_1_0));
+ ai->uri = e_bconf_hex_decode (rawuri);
+ ai->base_uri = get_base_uri (ai->uri);
+ sprintf (key, "account_name_%d", i);
+ ai->name = e_bconf_get_string (source, key);
+
+ d(printf("load account '%s'\n", ai->uri));
+
+ if (!strncmp (ai->uri, "imap:", 5)) {
+ read_imap_storeinfo (ai);
+ } else if (!strncmp (ai->uri, "exchange:", 9)) {
+ xmlNodePtr node;
+
+ d(printf (" upgrade exchange account\n"));
+ /* small hack, poke the source_url into the transport_url for exchanget: transports
+ - this will be picked up later in the conversion */
+ sprintf (key, "transport_url_%d", i);
+ node = e_bconf_get_entry (source, key);
+ if (node && (val = (char *)xmlGetProp (node, (const unsigned char *)"value"))) {
+ tmp = e_bconf_hex_decode (val);
+ xmlFree (val);
+ if (strncmp (tmp, "exchanget:", 10) == 0)
+ xmlSetProp (node, (const unsigned char *)"value", (unsigned char *)rawuri);
+ g_free (tmp);
+ } else {
+ d(printf (" couldn't find transport uri?\n"));
+ }
+ }
+ xmlFree (rawuri);
+
+ g_hash_table_insert (accounts_1_0, ai->base_uri, ai);
+ if (ai->name)
+ g_hash_table_insert (accounts_name_1_0, ai->name, ai);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+em_migrate_1_0 (const char *data_dir, xmlDocPtr config_xmldb, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
+{
+ accounts_1_0 = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) account_info_1_0_free);
+ accounts_name_1_0 = g_hash_table_new (g_str_hash, g_str_equal);
+ load_accounts_1_0 (config_xmldb);
+
+ upgrade_xml_uris(filters, upgrade_xml_uris_1_0);
+ upgrade_xml_uris(vfolders, upgrade_xml_uris_1_0);
+
+ g_hash_table_destroy (accounts_1_0);
+ g_hash_table_destroy (accounts_name_1_0);
+
+ return TRUE;
+}
+
+/* 1.2 upgrade functions */
+static gboolean
+is_xml1encoded (const char *txt)
+{
+ const unsigned char *p;
+ int isxml1 = FALSE;
+ int is8bit = FALSE;
+
+ p = (const unsigned char *)txt;
+ while (*p) {
+ if (p[0] == '\\' && p[1] == 'U' && p[2] == '+'
+ && isxdigit (p[3]) && isxdigit (p[4]) && isxdigit (p[5]) && isxdigit (p[6])
+ && p[7] == '\\') {
+ isxml1 = TRUE;
+ p+=7;
+ } else if (p[0] >= 0x80)
+ is8bit = TRUE;
+ p++;
+ }
+
+ /* check for invalid utf8 that needs cleaning */
+ if (is8bit && !isxml1)
+ isxml1 = !g_utf8_validate (txt, -1, NULL);
+
+ return isxml1;
+}
+
+static char *
+decode_xml1 (const char *txt)
+{
+ GString *out = g_string_new ("");
+ const unsigned char *p;
+ char *res;
+
+ /* convert:
+ \U+XXXX\ -> utf8
+ 8 bit characters -> utf8 (iso-8859-1) */
+
+ p = (const unsigned char *) txt;
+ while (*p) {
+ if (p[0] > 0x80
+ || (p[0] == '\\' && p[1] == 'U' && p[2] == '+'
+ && isxdigit (p[3]) && isxdigit (p[4]) && isxdigit (p[5]) && isxdigit (p[6])
+ && p[7] == '\\')) {
+ char utf8[8];
+ gunichar u;
+
+ if (p[0] == '\\') {
+ memcpy (utf8, p + 3, 4);
+ utf8[4] = 0;
+ u = strtoul (utf8, NULL, 16);
+ p+=7;
+ } else
+ u = p[0];
+ utf8[g_unichar_to_utf8 (u, utf8)] = 0;
+ g_string_append (out, utf8);
+ } else {
+ g_string_append_c (out, *p);
+ }
+ p++;
+ }
+
+ res = out->str;
+ g_string_free (out, FALSE);
+
+ return res;
+}
+
+static char *
+utf8_reencode (const char *txt)
+{
+ GString *out = g_string_new ("");
+ gchar *p;
+ char *res;
+
+ /* convert:
+ libxml1 8 bit utf8 converted to xml entities byte-by-byte chars -> utf8 */
+
+ p = (gchar *)txt;
+
+ while (*p) {
+ g_string_append_c (out, (gchar)g_utf8_get_char ((const gchar *)p));
+ p = (gchar *)g_utf8_next_char (p);
+ }
+
+ res = out->str;
+ if (g_utf8_validate (res, -1, NULL)) {
+ g_string_free (out, FALSE);
+ return res;
+ } else {
+ g_string_free (out, TRUE);
+ return g_strdup (txt);
+ }
+}
+
+static gboolean
+upgrade_xml_1_2_rec (xmlNodePtr node)
+{
+ const char *value_tags[] = { "string", "address", "regex", "file", "command", NULL };
+ const char *rule_tags[] = { "title", NULL };
+ const char *item_props[] = { "name", NULL };
+ struct {
+ const char *name;
+ const char **tags;
+ const char **props;
+ } tags[] = {
+ { "value", value_tags, NULL },
+ { "rule", rule_tags, NULL },
+ { "item", NULL, item_props },
+ { 0 },
+ };
+ xmlNodePtr work;
+ int i,j;
+ char *txt, *tmp;
+
+ /* upgrades the content of a node, if the node has a specific parent/node name */
+
+ for (i = 0; tags[i].name; i++) {
+ if (!strcmp ((char *)node->name, tags[i].name)) {
+ if (tags[i].tags != NULL) {
+ work = node->children;
+ while (work) {
+ for (j = 0; tags[i].tags[j]; j++) {
+ if (!strcmp ((char *)work->name, tags[i].tags[j])) {
+ txt = (char *)xmlNodeGetContent (work);
+ if (is_xml1encoded (txt)) {
+ tmp = decode_xml1 (txt);
+ d(printf ("upgrading xml node %s/%s '%s' -> '%s'\n",
+ tags[i].name, tags[i].tags[j], txt, tmp));
+ xmlNodeSetContent (work, (unsigned char *)tmp);
+ g_free (tmp);
+ }
+ xmlFree (txt);
+ }
+ }
+ work = work->next;
+ }
+ break;
+ }
+
+ if (tags[i].props != NULL) {
+ for (j = 0; tags[i].props[j]; j++) {
+ txt = (char *)xmlGetProp (node, (unsigned char *)tags[i].props[j]);
+ tmp = utf8_reencode (txt);
+ d(printf ("upgrading xml property %s on node %s '%s' -> '%s'\n",
+ tags[i].props[j], tags[i].name, txt, tmp));
+ xmlSetProp (node, (const unsigned char *)tags[i].props[j], (unsigned char *)tmp);
+ g_free (tmp);
+ xmlFree (txt);
+ }
+ }
+ }
+ }
+
+ node = node->children;
+ while (node) {
+ upgrade_xml_1_2_rec (node);
+ node = node->next;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+em_upgrade_xml_1_2 (xmlDocPtr doc)
+{
+ xmlNodePtr root;
+
+ if (!doc || !(root = xmlDocGetRootElement (doc)))
+ return TRUE;
+
+ return upgrade_xml_1_2_rec (root);
+}
+
+/* ********************************************************************** */
+/* Tables for converting flat bonobo conf -> gconf xml blob */
+/* ********************************************************************** */
+
+/* Mail/Accounts/ * */
+static e_bconf_map_t cc_map[] = {
+ { "account_always_cc_%i", "always", E_BCONF_MAP_BOOL },
+ { "account_always_cc_addrs_%i", "recipients", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t bcc_map[] = {
+ { "account_always_cc_%i", "always", E_BCONF_MAP_BOOL },
+ { "account_always_bcc_addrs_%i", "recipients", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t pgp_map[] = {
+ { "account_pgp_encrypt_to_self_%i", "encrypt-to-self", E_BCONF_MAP_BOOL },
+ { "account_pgp_always_trust_%i", "always-trust", E_BCONF_MAP_BOOL },
+ { "account_pgp_always_sign_%i", "always-sign", E_BCONF_MAP_BOOL },
+ { "account_pgp_no_imip_sign_%i", "no-imip-sign", E_BCONF_MAP_BOOL },
+ { "account_pgp_key_%i", "key-id", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t smime_map[] = {
+ { "account_smime_encrypt_to_self_%i", "encrypt-to-self", E_BCONF_MAP_BOOL },
+ { "account_smime_always_sign_%i", "always-sign", E_BCONF_MAP_BOOL },
+ { "account_smime_key_%i", "key-id", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t identity_sig_map[] = {
+ { "identity_autogenerated_signature_%i", "auto", E_BCONF_MAP_BOOL },
+ { "identity_def_signature_%i", "default", E_BCONF_MAP_LONG },
+ { NULL },
+};
+
+static e_bconf_map_t identity_map[] = {
+ { "identity_name_%i", "name", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "identity_address_%i", "addr-spec", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "identity_reply_to_%i", "reply-to", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "identity_organization_%i", "organization", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL, "signature", E_BCONF_MAP_CHILD, identity_sig_map },
+ { NULL },
+};
+
+static e_bconf_map_t source_map[] = {
+ { "source_save_passwd_%i", "save-passwd", E_BCONF_MAP_BOOL },
+ { "source_keep_on_server_%i", "keep-on-server", E_BCONF_MAP_BOOL },
+ { "source_auto_check_%i", "auto-check", E_BCONF_MAP_BOOL },
+ { "source_auto_check_time_%i", "auto-check-timeout", E_BCONF_MAP_LONG },
+ { "source_url_%i", "url", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t transport_map[] = {
+ { "transport_save_passwd_%i", "save-passwd", E_BCONF_MAP_BOOL },
+ { "transport_url_%i", "url", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+static e_bconf_map_t account_map[] = {
+ { "account_name_%i", "name", E_BCONF_MAP_STRING },
+ { "source_enabled_%i", "enabled", E_BCONF_MAP_BOOL },
+ { NULL, "identity", E_BCONF_MAP_CHILD, identity_map },
+ { NULL, "source", E_BCONF_MAP_CHILD, source_map },
+ { NULL, "transport", E_BCONF_MAP_CHILD, transport_map },
+ { "account_drafts_folder_uri_%i", "drafts-folder", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "account_sent_folder_uri_%i", "sent-folder", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL, "auto-cc", E_BCONF_MAP_CHILD, cc_map },
+ { NULL, "auto-bcc", E_BCONF_MAP_CHILD, bcc_map },
+ { NULL, "pgp", E_BCONF_MAP_CHILD, pgp_map },
+ { NULL, "smime", E_BCONF_MAP_CHILD, smime_map },
+ { NULL },
+};
+
+/* /Mail/Signatures/ * */
+static e_bconf_map_t signature_format_map[] = {
+ { "text/plain", },
+ { "text/html", },
+ { NULL }
+};
+
+static e_bconf_map_t signature_map[] = {
+ { "name_%i", "name", E_BCONF_MAP_STRING },
+ { "html_%i", "format", E_BCONF_MAP_ENUM, signature_format_map },
+ { "filename_%i", "filename", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { "script_%i", "script", E_BCONF_MAP_STRING|E_BCONF_MAP_CONTENT },
+ { NULL },
+};
+
+/* ********************************************************************** */
+/* Tables for bonobo conf -> gconf conversion */
+/* ********************************************************************** */
+
+static e_gconf_map_t mail_accounts_map[] = {
+ /* /Mail/Accounts - most entries are processed via the xml blob routine */
+ /* This also works because the initial uid mapping is 1:1 with the list order */
+ { "default_account", "mail/default_account", E_GCONF_MAP_SIMPLESTRING },
+ { 0 },
+};
+
+static e_gconf_map_t mail_display_map[] = {
+ /* /Mail/Display */
+ { "side_bar_search", "mail/display/side_bar_search", E_GCONF_MAP_BOOL },
+ { "thread_list", "mail/display/thread_list", E_GCONF_MAP_BOOL },
+ { "thread_subject", "mail/display/thread_subject", E_GCONF_MAP_BOOL },
+ { "hide_deleted", "mail/display/show_deleted", E_GCONF_MAP_BOOLNOT },
+ { "preview_pane", "mail/display/show_preview", E_GCONF_MAP_BOOL },
+ { "paned_size", "mail/display/paned_size", E_GCONF_MAP_INT },
+ { "seen_timeout", "mail/display/mark_seen_timeout", E_GCONF_MAP_INT },
+ { "do_seen_timeout", "mail/display/mark_seen", E_GCONF_MAP_BOOL },
+ { "http_images", "mail/display/load_http_images", E_GCONF_MAP_INT },
+ { "citation_highlight", "mail/display/mark_citations", E_GCONF_MAP_BOOL },
+ { "citation_color", "mail/display/citation_colour", E_GCONF_MAP_COLOUR },
+ { 0 },
+};
+
+static e_gconf_map_t mail_format_map[] = {
+ /* /Mail/Format */
+ { "message_display_style", "mail/display/message_style", E_GCONF_MAP_INT },
+ { "send_html", "mail/composer/send_html", E_GCONF_MAP_BOOL },
+ { "default_reply_style", "mail/format/reply_style", E_GCONF_MAP_INT },
+ { "default_forward_style", "mail/format/forward_style", E_GCONF_MAP_INT },
+ { "default_charset", "mail/composer/charset", E_GCONF_MAP_STRING },
+ { "confirm_unwanted_html", "mail/prompts/unwanted_html", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+static e_gconf_map_t mail_trash_map[] = {
+ /* /Mail/Trash */
+ { "empty_on_exit", "mail/trash/empty_on_exit", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+static e_gconf_map_t mail_prompts_map[] = {
+ /* /Mail/Prompts */
+ { "confirm_expunge", "mail/prompts/expunge", E_GCONF_MAP_BOOL },
+ { "empty_subject", "mail/prompts/empty_subject", E_GCONF_MAP_BOOL },
+ { "only_bcc", "mail/prompts/only_bcc", E_GCONF_MAP_BOOL },
+ { 0 }
+};
+
+static e_gconf_map_t mail_filters_map[] = {
+ /* /Mail/Filters */
+ { "log", "mail/filters/log", E_GCONF_MAP_BOOL },
+ { "log_path", "mail/filters/logfile", E_GCONF_MAP_STRING },
+ { 0 }
+};
+
+static e_gconf_map_t mail_notify_map[] = {
+ /* /Mail/Notify */
+ { "new_mail_notification", "mail/notify/type", E_GCONF_MAP_INT },
+ { "new_mail_notification_sound_file", "mail/notify/sound", E_GCONF_MAP_STRING },
+ { 0 }
+};
+
+static e_gconf_map_t mail_filesel_map[] = {
+ /* /Mail/Filesel */
+ { "last_filesel_dir", "mail/save_dir", E_GCONF_MAP_STRING },
+ { 0 }
+};
+
+static e_gconf_map_t mail_composer_map[] = {
+ /* /Mail/Composer */
+ { "ViewFrom", "mail/composer/view/From", E_GCONF_MAP_BOOL },
+ { "ViewReplyTo", "mail/composer/view/ReplyTo", E_GCONF_MAP_BOOL },
+ { "ViewCC", "mail/composer/view/Cc", E_GCONF_MAP_BOOL },
+ { "ViewBCC", "mail/composer/view/Bcc", E_GCONF_MAP_BOOL },
+ { "ViewSubject", "mail/composer/view/Subject", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static e_gconf_map_t importer_elm_map[] = {
+ /* /Importer/Elm */
+ { "mail", "importer/elm/mail", E_GCONF_MAP_BOOL },
+ { "mail-imported", "importer/elm/mail-imported", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+static e_gconf_map_t importer_pine_map[] = {
+ /* /Importer/Pine */
+ { "mail", "importer/elm/mail", E_GCONF_MAP_BOOL },
+ { "address", "importer/elm/address", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+static e_gconf_map_t importer_netscape_map[] = {
+ /* /Importer/Netscape */
+ { "mail", "importer/netscape/mail", E_GCONF_MAP_BOOL },
+ { "settings", "importer/netscape/settings", E_GCONF_MAP_BOOL },
+ { "filters", "importer/netscape/filters", E_GCONF_MAP_BOOL },
+ { 0 },
+};
+
+/* ********************************************************************** */
+
+static e_gconf_map_list_t gconf_remap_list[] = {
+ { "/Mail/Accounts", mail_accounts_map },
+ { "/Mail/Display", mail_display_map },
+ { "/Mail/Format", mail_format_map },
+ { "/Mail/Trash", mail_trash_map },
+ { "/Mail/Prompts", mail_prompts_map },
+ { "/Mail/Filters", mail_filters_map },
+ { "/Mail/Notify", mail_notify_map },
+ { "/Mail/Filesel", mail_filesel_map },
+ { "/Mail/Composer", mail_composer_map },
+
+ { "/Importer/Elm", importer_elm_map },
+ { "/Importer/Pine", importer_pine_map },
+ { "/Importer/Netscape", importer_netscape_map },
+
+ { 0 },
+};
+
+static struct {
- char *label;
- char *colour;
++ const gchar *label;
++ const gchar *colour;
+} label_default[5] = {
+ { N_("Important"), "#EF2929" }, /* red */
+ { N_("Work"), "#F57900" }, /* orange */
+ { N_("Personal"), "#4E9A06" }, /* green */
+ { N_("To Do"), "#3465A4" }, /* blue */
+ { N_("Later"), "#75507B" } /* purple */
+};
+
+/* remaps mail config from bconf to gconf */
+static gboolean
+bconf_import(GConfClient *gconf, xmlDocPtr config_xmldb)
+{
+ xmlNodePtr source;
+ char labx[16], colx[16];
+ char *val, *lab, *col;
+ GSList *list, *l;
+ int i;
+
+ e_bconf_import(gconf, config_xmldb, gconf_remap_list);
+
+ /* Labels:
+ label string + label colour as integer
+ -> label string:# colour as hex */
+ source = e_bconf_get_path(config_xmldb, "/Mail/Labels");
+ if (source) {
+ list = NULL;
+ for (i = 0; i < 5; i++) {
+ sprintf(labx, "label_%d", i);
+ sprintf(colx, "color_%d", i);
+ lab = e_bconf_get_string(source, labx);
+ if ((col = e_bconf_get_value(source, colx))) {
+ sprintf(colx, "#%06x", atoi(col) & 0xffffff);
+ g_free(col);
+ } else
+ strcpy(colx, label_default[i].colour);
+
+ val = g_strdup_printf("%s:%s", lab ? lab : label_default[i].label, colx);
+ list = g_slist_append(list, val);
+ g_free(lab);
+ }
+
+ gconf_client_set_list(gconf, "/apps/evolution/mail/labels", GCONF_VALUE_STRING, list, NULL);
+ while (list) {
+ l = list->next;
+ g_free(list->data);
+ g_slist_free_1(list);
+ list = l;
+ }
+ } else {
+ g_warning("could not find /Mail/Labels in old config database, skipping");
+ }
+
+ /* Accounts: The flat bonobo-config structure is remapped to a list of xml blobs. Upgrades as necessary */
+ e_bconf_import_xml_blob(gconf, config_xmldb, account_map, "/Mail/Accounts",
+ "/apps/evolution/mail/accounts", "account", "uid");
+
+ /* Same for signatures */
+ e_bconf_import_xml_blob(gconf, config_xmldb, signature_map, "/Mail/Signatures",
+ "/apps/evolution/mail/signatures", "signature", NULL);
+
+ return TRUE;
+}
+
+static gboolean
+em_migrate_1_2(const char *data_dir, xmlDocPtr config_xmldb, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
+{
+ GConfClient *gconf;
+
+ gconf = gconf_client_get_default();
+ bconf_import(gconf, config_xmldb);
+ g_object_unref(gconf);
+
+ em_upgrade_xml_1_2(filters);
+ em_upgrade_xml_1_2(vfolders);
+
+ return TRUE;
+}
+
+/* 1.4 upgrade functions */
+
+#define EM_MIGRATE_SESSION_TYPE (em_migrate_session_get_type ())
+#define EM_MIGRATE_SESSION(obj) (CAMEL_CHECK_CAST((obj), EM_MIGRATE_SESSION_TYPE, EMMigrateSession))
+#define EM_MIGRATE_SESSION_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), EM_MIGRATE_SESSION_TYPE, EMMigrateSessionClass))
+#define EM_MIGRATE_IS_SESSION(o) (CAMEL_CHECK_TYPE((o), EM_MIGRATE_SESSION_TYPE))
+
+typedef struct _EMMigrateSession {
+ CamelSession parent_object;
+
+ CamelStore *store; /* new folder tree store */
+ char *srcdir; /* old folder tree path */
+} EMMigrateSession;
+
+typedef struct _EMMigrateSessionClass {
+ CamelSessionClass parent_class;
+
+} EMMigrateSessionClass;
+
+static CamelType em_migrate_session_get_type (void);
+static CamelSession *em_migrate_session_new (const char *path);
+
+static void
+class_init (EMMigrateSessionClass *klass)
+{
+ ;
+}
+
+static CamelType
+em_migrate_session_get_type (void)
+{
+ static CamelType type = CAMEL_INVALID_TYPE;
+
+ if (type == CAMEL_INVALID_TYPE) {
+ type = camel_type_register (
+ camel_session_get_type (),
+ "EMMigrateSession",
+ sizeof (EMMigrateSession),
+ sizeof (EMMigrateSessionClass),
+ (CamelObjectClassInitFunc) class_init,
+ NULL,
+ NULL,
+ NULL);
+ }
+
+ return type;
+}
+
+static CamelSession *
+em_migrate_session_new (const char *path)
+{
+ CamelSession *session;
+
+ session = CAMEL_SESSION (camel_object_new (EM_MIGRATE_SESSION_TYPE));
+
+ camel_session_construct (session, path);
+
+ return session;
+}
+
+
+#endif /* !G_OS_WIN32 */
+
+static GtkWidget *window;
+static GtkLabel *label;
+static GtkProgressBar *progress;
+
+static void
- em_migrate_setup_progress_dialog (const char *desc)
++em_migrate_setup_progress_dialog (const char *title, const char *desc)
+{
+ GtkWidget *vbox, *hbox, *w;
++ gchar *markup;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title ((GtkWindow *) window, _("Migrating..."));
+ gtk_window_set_modal ((GtkWindow *) window, TRUE);
+ gtk_container_set_border_width ((GtkContainer *) window, 6);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_widget_show (vbox);
+ gtk_container_add ((GtkContainer *) window, vbox);
+
+ w = gtk_label_new (desc);
+
+ gtk_label_set_line_wrap ((GtkLabel *) w, TRUE);
+ gtk_widget_show (w);
+ gtk_box_pack_start_defaults ((GtkBox *) vbox, w);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start_defaults ((GtkBox *) vbox, hbox);
+
+ label = (GtkLabel *) gtk_label_new ("");
+ gtk_widget_show ((GtkWidget *) label);
+ gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) label);
+
+ progress = (GtkProgressBar *) gtk_progress_bar_new ();
+ gtk_widget_show ((GtkWidget *) progress);
+ gtk_box_pack_start_defaults ((GtkBox *) hbox, (GtkWidget *) progress);
+
++ /* Prepare the message */
++ vbox = gtk_vbox_new (FALSE, 12);
++ gtk_widget_show (vbox);
++ gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
++
++ w = gtk_label_new (NULL);
++ gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0);
++ markup = g_strconcat ("<big><b>", title ? title : _("Migration"), "</b></big>", NULL);
++ gtk_label_set_markup (GTK_LABEL (w), markup);
++ gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
++ g_free (markup);
++
++ w = gtk_label_new (desc);
++ gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.0);
++ gtk_label_set_line_wrap (GTK_LABEL (w), TRUE);
++ gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
++
++ /* Progress bar */
++ w = gtk_vbox_new (FALSE, 6);
++ gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
++
++ label = GTK_LABEL (gtk_label_new (""));
++ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
++ gtk_label_set_line_wrap (label, TRUE);
++ gtk_widget_show (GTK_WIDGET (label));
++ gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (label), TRUE, TRUE, 0);
++
++ progress = GTK_PROGRESS_BAR (gtk_progress_bar_new ());
++ gtk_widget_show (GTK_WIDGET (progress));
++ gtk_box_pack_start (GTK_BOX (w), GTK_WIDGET (progress), TRUE, TRUE, 0);
++
++ gtk_container_add (GTK_CONTAINER (window), hbox);
++ gtk_widget_show_all (hbox);
+ gtk_widget_show (window);
+}
+
+static void
+em_migrate_close_progress_dialog (void)
+{
+ gtk_widget_destroy ((GtkWidget *) window);
+}
+
+static void
+em_migrate_set_folder_name (const char *folder_name)
+{
+ char *text;
+
+ text = g_strdup_printf (_("Migrating '%s':"), folder_name);
+ gtk_label_set_text (label, text);
+ g_free (text);
+
+ gtk_progress_bar_set_fraction (progress, 0.0);
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+static void
+em_migrate_set_progress (double percent)
+{
+ char text[5];
+
+ snprintf (text, sizeof (text), "%d%%", (int) (percent * 100.0f));
+
+ gtk_progress_bar_set_fraction (progress, percent);
+ gtk_progress_bar_set_text (progress, text);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+#ifndef G_OS_WIN32
+
+static gboolean
+is_mail_folder (const char *metadata)
+{
+ xmlNodePtr node;
+ xmlDocPtr doc;
+ char *type;
+
+ if (!(doc = xmlParseFile (metadata))) {
+ g_warning ("Cannot parse `%s'", metadata);
+ return FALSE;
+ }
+
+ if (!(node = xmlDocGetRootElement (doc))) {
+ g_warning ("`%s' corrupt: document contains no root node", metadata);
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ if (!node->name || strcmp ((char *)node->name, "efolder") != 0) {
+ g_warning ("`%s' corrupt: root node is not 'efolder'", metadata);
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ node = node->children;
+ while (node != NULL) {
+ if (node->name && !strcmp ((char *)node->name, "type")) {
+ type = (char *)xmlNodeGetContent (node);
+ if (!strcmp ((char *)type, "mail")) {
+ xmlFreeDoc (doc);
+ xmlFree (type);
+
+ return TRUE;
+ }
+
+ xmlFree (type);
+
+ break;
+ }
+
+ node = node->next;
+ }
+
+ xmlFreeDoc (doc);
+
+ return FALSE;
+}
+
+static gboolean
+get_local_et_expanded (const char *dirname)
+{
+ xmlNodePtr node;
+ xmlDocPtr doc;
+ struct stat st;
+ char *buf, *p;
+ int thread_list;
+
+ buf = g_strdup_printf ("%s/evolution/config/file:%s", g_get_home_dir (), dirname);
+ p = buf + strlen (g_get_home_dir ()) + strlen ("/evolution/config/file:");
+ e_filename_make_safe (p);
+
+ if (stat (buf, &st) == -1) {
+ g_free (buf);
+ return FALSE;
+ }
+
+ if (!(doc = xmlParseFile (buf))) {
+ g_free (buf);
+ return FALSE;
+ }
+
+ g_free (buf);
+
+ if (!(node = xmlDocGetRootElement (doc)) || strcmp ((char *)node->name, "expanded_state") != 0) {
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ if (!(buf = (char *)xmlGetProp (node, (const unsigned char *)"default"))) {
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ thread_list = strcmp (buf, "0") == 0 ? 0 : 1;
+ xmlFree (buf);
+
+ xmlFreeDoc (doc);
+
+ return thread_list;
+}
+
+static char *
+get_local_store_uri (const char *dirname, char **namep, int *indexp)
+{
- char *protocol, *name, *metadata, *tmp;
++ gchar *name, *protocol, *metadata, *tmp;
+ int index;
+ struct stat st;
+ xmlNodePtr node;
+ xmlDocPtr doc;
+
+ metadata = g_build_filename(dirname, "local-metadata.xml", NULL);
+
+ /* in 1.4, any errors are treated as defaults, this function cannot fail */
+
+ /* defaults */
- name = "mbox";
- protocol = "mbox";
++ name = (gchar *) "mbox";
++ protocol = (gchar *) "mbox";
+ index = TRUE;
+
+ if (stat (metadata, &st) == -1 || !S_ISREG (st.st_mode))
+ goto nofile;
+
+ doc = xmlParseFile(metadata);
+ if (doc == NULL)
+ goto nofile;
+
+ node = doc->children;
+ if (strcmp((char *)node->name, "folderinfo"))
+ goto dodefault;
+
+ for (node = node->children; node; node = node->next) {
+ if (node->name && !strcmp ((char *)node->name, "folder")) {
+ tmp = (char *)xmlGetProp (node, (const unsigned char *)"type");
+ if (tmp) {
+ protocol = alloca(strlen(tmp)+1);
+ strcpy(protocol, tmp);
+ xmlFree(tmp);
+ }
+ tmp = (char *)xmlGetProp (node, (const unsigned char *)"name");
+ if (tmp) {
+ name = alloca(strlen(tmp)+1);
+ strcpy(name, tmp);
+ xmlFree(tmp);
+ }
+ tmp = (char *)xmlGetProp (node, (const unsigned char *)"index");
+ if (tmp) {
+ index = atoi(tmp);
+ xmlFree(tmp);
+ }
+ }
+ }
+dodefault:
+ xmlFreeDoc (doc);
+nofile:
+ g_free(metadata);
+
+ *namep = g_strdup(name);
+ *indexp = index;
+
+ return g_strdup_printf("%s:%s", protocol, dirname);
+}
+
+#endif /* !G_OS_WIN32 */
+
+enum {
+ CP_UNIQUE = 0,
+ CP_OVERWRITE,
+ CP_APPEND
+};
+
+static int open_flags[3] = {
+ O_WRONLY | O_CREAT | O_TRUNC,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ O_WRONLY | O_CREAT | O_APPEND,
+};
+
+static gboolean
+cp (const char *src, const char *dest, gboolean show_progress, int mode)
+{
+ unsigned char readbuf[65536];
+ ssize_t nread, nwritten;
+ int errnosav, readfd, writefd;
+ size_t total = 0;
+ struct stat st;
+ struct utimbuf ut;
+
+ /* if the dest file exists and has content, abort - we don't
+ * want to corrupt their existing data */
+ if (g_stat (dest, &st) == 0 && st.st_size > 0 && mode == CP_UNIQUE) {
+ errno = EEXIST;
+ return FALSE;
+ }
+
+ if (g_stat (src, &st) == -1
+ || (readfd = g_open (src, O_RDONLY | O_BINARY, 0)) == -1)
+ return FALSE;
+
+ if ((writefd = g_open (dest, open_flags[mode] | O_BINARY, 0666)) == -1) {
+ errnosav = errno;
+ close (readfd);
+ errno = errnosav;
+ return FALSE;
+ }
+
+ do {
+ do {
+ nread = read (readfd, readbuf, sizeof (readbuf));
+ } while (nread == -1 && errno == EINTR);
+
+ if (nread == 0)
+ break;
+ else if (nread < 0)
+ goto exception;
+
+ do {
+ nwritten = write (writefd, readbuf, nread);
+ } while (nwritten == -1 && errno == EINTR);
+
+ if (nwritten < nread)
+ goto exception;
+
+ total += nwritten;
+ if (show_progress)
+ em_migrate_set_progress (((double) total) / ((double) st.st_size));
+ } while (total < st.st_size);
+
+ if (fsync (writefd) == -1)
+ goto exception;
+
+ close (readfd);
+ if (close (writefd) == -1)
+ goto failclose;
+
+ ut.actime = st.st_atime;
+ ut.modtime = st.st_mtime;
+ utime (dest, &ut);
+ chmod (dest, st.st_mode);
+
+ return TRUE;
+
+ exception:
+
+ errnosav = errno;
+ close (readfd);
+ close (writefd);
+ errno = errnosav;
+
+ failclose:
+
+ errnosav = errno;
+ unlink (dest);
+ errno = errnosav;
+
+ return FALSE;
+}
+
+#ifndef G_OS_WIN32
+
+static gboolean
+cp_r (const char *src, const char *dest, const char *pattern, int mode)
+{
+ GString *srcpath, *destpath;
+ struct dirent *dent;
+ size_t slen, dlen;
+ struct stat st;
+ DIR *dir;
+
+ if (g_mkdir_with_parents (dest, 0777) == -1)
+ return FALSE;
+
+ if (!(dir = opendir (src)))
+ return FALSE;
+
+ srcpath = g_string_new (src);
+ g_string_append_c (srcpath, '/');
+ slen = srcpath->len;
+
+ destpath = g_string_new (dest);
+ g_string_append_c (destpath, '/');
+ dlen = destpath->len;
+
+ while ((dent = readdir (dir))) {
+ if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, ".."))
+ continue;
+
+ g_string_truncate (srcpath, slen);
+ g_string_truncate (destpath, dlen);
+
+ g_string_append (srcpath, dent->d_name);
+ g_string_append (destpath, dent->d_name);
+
+ if (stat (srcpath->str, &st) == -1)
+ continue;
+
+ if (S_ISDIR (st.st_mode)) {
+ cp_r (srcpath->str, destpath->str, pattern, mode);
+ } else if (!pattern || !strcmp (dent->d_name, pattern)) {
+ cp (srcpath->str, destpath->str, FALSE, mode);
+ }
+ }
+
+ closedir (dir);
+
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+
+ return TRUE;
+}
+
+static void
+mbox_build_filename (GString *path, const char *toplevel_dir, const char *full_name)
+{
+ const char *start, *inptr = full_name;
+ int subdirs = 0;
+
+ while (*inptr != '\0') {
+ if (*inptr == '/')
+ subdirs++;
+ inptr++;
+ }
+
+ g_string_assign(path, toplevel_dir);
+ g_string_append_c (path, '/');
+
+ inptr = full_name;
+ while (*inptr != '\0') {
+ start = inptr;
+ while (*inptr != '/' && *inptr != '\0')
+ inptr++;
+
+ g_string_append_len (path, start, inptr - start);
+
+ if (*inptr == '/') {
+ g_string_append (path, ".sbd/");
+ inptr++;
+
+ /* strip extranaeous '/'s */
+ while (*inptr == '/')
+ inptr++;
+ }
+ }
+}
+
+static gboolean
+em_migrate_folder(EMMigrateSession *session, const char *dirname, const char *full_name, GError **error)
+{
+ CamelFolder *old_folder = NULL, *new_folder = NULL;
+ CamelStore *local_store = NULL;
+ CamelException ex;
+ char *name, *uri;
+ GPtrArray *uids;
+ struct stat st;
+ gboolean thread_list;
+ int index, i;
+ GString *src, *dest;
+ gboolean success = FALSE;
+
+ camel_exception_init (&ex);
+
+ src = g_string_new("");
+
+ g_string_printf(src, "%s/folder-metadata.xml", dirname);
+ if (stat (src->str, &st) == -1
+ || !S_ISREG (st.st_mode)
+ || !is_mail_folder(src->str)) {
+ /* Not an evolution mail folder */
+ g_string_free(src, TRUE);
+ return TRUE;
+ }
+
+ dest = g_string_new("");
+ uri = get_local_store_uri(dirname, &name, &index);
+ em_migrate_set_folder_name (full_name);
+ thread_list = get_local_et_expanded (dirname);
+
+ /* Manually copy local mbox files, its much faster */
+ if (!strncmp (uri, "mbox:", 5)) {
- static char *meta_ext[] = { ".summary", ".ibex.index", ".ibex.index.data" };
++ static const gchar *meta_ext[] = { ".summary", ".ibex.index", ".ibex.index.data" };
+ size_t slen, dlen;
+ FILE *fp;
+ char *p;
+ int mode;
+
+ g_string_printf (src, "%s/%s", uri + 5, name);
+ mbox_build_filename (dest, ((CamelService *)session->store)->url->path, full_name);
+ p = strrchr (dest->str, '/');
+ *p = '\0';
+
+ slen = src->len;
+ dlen = dest->len;
+
+ if (g_mkdir_with_parents (dest->str, 0777) == -1 && errno != EEXIST) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to create new folder `%s': %s"),
+ dest->str, g_strerror (errno));
+ goto fatal;
+ }
+
+ *p = '/';
+ mode = CP_UNIQUE;
+ retry_copy:
+ if (!cp (src->str, dest->str, TRUE, mode)) {
+ if (errno == EEXIST) {
+ int save = errno;
+
+ switch (e_error_run(NULL, "mail:ask-migrate-existing", src->str, dest->str, NULL)) {
+ case GTK_RESPONSE_ACCEPT:
+ mode = CP_OVERWRITE;
+ goto retry_copy;
+ case GTK_RESPONSE_OK:
+ mode = CP_APPEND;
+ goto retry_copy;
+ case GTK_RESPONSE_REJECT:
+ goto ignore;
+ }
+
+ errno = save;
+ }
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to copy folder `%s' to `%s': %s"),
+ src->str, dest->str, g_strerror (errno));
+ goto fatal;
+ }
+ ignore:
+
+ /* create a .cmeta file specifying to index and/or thread the folder */
+ g_string_truncate (dest, dlen);
+ g_string_append (dest, ".cmeta");
+ if ((fp = fopen (dest->str, "w")) != NULL) {
+ int fd = fileno (fp);
+
+ /* write the magic string */
+ if (fwrite ("CLMD", 4, 1, fp) != 1)
+ goto cmeta_err;
+
+ /* write the version (1) */
+ if (camel_file_util_encode_uint32 (fp, 1) == -1)
+ goto cmeta_err;
+
+ /* write the meta count */
+ if (camel_file_util_encode_uint32 (fp, thread_list ? 1 : 0) == -1)
+ goto cmeta_err;
+
+ if (!thread_list) {
+ if (camel_file_util_encode_string (fp, "evolution:thread_list") == -1)
+ goto cmeta_err;
+
+ if (camel_file_util_encode_string (fp, !thread_list ? "1" : "0") == -1)
+ goto cmeta_err;
+ }
+
+ /* write the prop count (only prop is the index prop) */
+ if (camel_file_util_encode_uint32 (fp, 1) == -1)
+ goto cmeta_err;
+
+ /* write the index prop tag (== CAMEL_FOLDER_ARG_LAST|CAMEL_ARG_BOO) */
+ if (camel_file_util_encode_uint32 (fp, CAMEL_FOLDER_ARG_LAST|CAMEL_ARG_BOO) == -1)
+ goto cmeta_err;
+
+ /* write the index prop value */
+ if (camel_file_util_encode_uint32 (fp, 1) == -1)
+ goto cmeta_err;
+
+ fflush (fp);
+
+ if (fsync (fd) == -1) {
+ cmeta_err:
+ fclose (fp);
+ unlink (dest->str);
+ } else {
+ fclose (fp);
+ }
+ }
+
+ /* copy over the metadata files */
+ for (i = 0; i < sizeof(meta_ext)/sizeof(meta_ext[0]); i++) {
+ g_string_truncate (src, slen);
+ g_string_truncate (dest, dlen);
+
+ g_string_append (src, meta_ext[i]);
+ g_string_append (dest, meta_ext[i]);
+ cp (src->str, dest->str, FALSE, CP_OVERWRITE);
+ }
+ } else {
+ guint32 flags = CAMEL_STORE_FOLDER_CREATE;
+
+ if (!(local_store = camel_session_get_store ((CamelSession *) session, uri, &ex))
+ || !(old_folder = camel_store_get_folder (local_store, name, 0, &ex)))
+ goto fatal;
+
+ flags |= (index ? CAMEL_STORE_FOLDER_BODY_INDEX : 0);
+ if (!(new_folder = camel_store_get_folder (session->store, full_name, flags, &ex)))
+ goto fatal;
+
+ if (!thread_list) {
+ camel_object_meta_set (new_folder, "evolution:thread_list", !thread_list ? "1" : "0");
+ camel_object_state_write (new_folder);
+ }
+
+ uids = camel_folder_get_uids (old_folder);
+ for (i = 0; i < uids->len; i++) {
+ CamelMimeMessage *message;
+ CamelMessageInfo *info;
+
+ if (!(info = camel_folder_get_message_info (old_folder, uids->pdata[i])))
+ continue;
+
+ if (!(message = camel_folder_get_message (old_folder, uids->pdata[i], &ex))) {
+ camel_folder_free_message_info (old_folder, info);
+ camel_folder_free_uids (old_folder, uids);
+ goto fatal;
+ }
+
+ camel_folder_append_message (new_folder, message, info, NULL, &ex);
+ camel_folder_free_message_info (old_folder, info);
+ camel_object_unref (message);
+
+ if (camel_exception_is_set (&ex))
+ break;
+
+ em_migrate_set_progress (((double) i + 1) / ((double) uids->len));
+ }
+
+ camel_folder_free_uids (old_folder, uids);
+
+ if (camel_exception_is_set (&ex))
+ goto fatal;
+ }
+ success = TRUE;
+fatal:
+ g_free (uri);
+ g_free (name);
+ g_string_free(src, TRUE);
+ g_string_free(dest, TRUE);
+ if (local_store)
+ camel_object_unref(local_store);
+ if (old_folder)
+ camel_object_unref(old_folder);
+ if (new_folder)
+ camel_object_unref(new_folder);
+
+ if (camel_exception_is_set (&ex)) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ "%s", camel_exception_get_description (&ex));
+ camel_exception_clear (&ex);
+ }
+
+ return success;
+}
+
+static gboolean
+em_migrate_dir (EMMigrateSession *session, const char *dirname, const char *full_name, GError **error)
+{
+ char *path;
+ DIR *dir;
+ struct stat st;
+ struct dirent *dent;
+ gboolean success = TRUE;
+
+ if (!em_migrate_folder(session, dirname, full_name, error))
+ return FALSE;
+
+ /* no subfolders, not readable, don't care */
+ path = g_strdup_printf ("%s/subfolders", dirname);
+ if (stat (path, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_free (path);
+ return TRUE;
+ }
+
+ if (!(dir = opendir (path))) {
+ g_free (path);
+ return TRUE;
+ }
+
+ while (success && (dent = readdir (dir))) {
+ char *full_path;
+ char *name;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ full_path = g_strdup_printf ("%s/%s", path, dent->d_name);
+ if (stat (full_path, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_free (full_path);
+ continue;
+ }
+
+ name = g_strdup_printf ("%s/%s", full_name, dent->d_name);
+ success = em_migrate_dir (session, full_path, name, error);
+ g_free (full_path);
+ g_free (name);
+ }
+
+ closedir (dir);
+
+ g_free (path);
+
+ return success;
+}
+
+static gboolean
+em_migrate_local_folders_1_4 (EMMigrateSession *session, GError **error)
+{
+ struct dirent *dent;
+ struct stat st;
+ DIR *dir;
+ gboolean success = TRUE;
+
+ if (!(dir = opendir (session->srcdir))) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to scan for existing mailboxes at "
+ "`%s': %s"), session->srcdir, g_strerror (errno));
+ return FALSE;
+ }
+
- em_migrate_setup_progress_dialog (_("The location and hierarchy of the Evolution mailbox "
- "folders has changed since Evolution 1.x.\n\nPlease be "
- "patient while Evolution migrates your folders..."));
++ em_migrate_setup_progress_dialog (
++ _("Migrating Folders"),
++ _("The location and hierarchy of the Evolution mailbox "
++ "folders has changed since Evolution 1.x.\n\nPlease be "
++ "patient while Evolution migrates your folders..."));
+
+ while (success && (dent = readdir (dir))) {
+ char *full_path;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ full_path = g_strdup_printf ("%s/%s", session->srcdir, dent->d_name);
+ if (stat (full_path, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_free (full_path);
+ continue;
+ }
+
+ success = em_migrate_dir (session, full_path, dent->d_name, error);
+ g_free (full_path);
+ }
+
+ closedir (dir);
+
+ em_migrate_close_progress_dialog ();
+
+ return success;
+}
+
+static char *
+upgrade_xml_uris_1_4 (const char *uri)
+{
+ char *path, *prefix, *p;
+ CamelURL *url;
+
+ if (!strncmp (uri, "file:", 5)) {
+ url = camel_url_new (uri, NULL);
+ camel_url_set_protocol (url, "email");
+ camel_url_set_user (url, "local");
+ camel_url_set_host (url, "local");
+
+ prefix = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+ if (strncmp (url->path, prefix, strlen (prefix)) != 0) {
+ /* uri is busticated - user probably copied from another user's home directory */
+ camel_url_free (url);
+ g_free (prefix);
+
+ return g_strdup (uri);
+ }
+ path = g_strdup (url->path + strlen (prefix));
+ g_free (prefix);
+
+ /* modify the path in-place */
+ p = path + strlen (path) - 12;
+ while (p > path) {
+ if (!strncmp (p, "/subfolders/", 12))
+ memmove (p, p + 11, strlen (p + 11) + 1);
+
+ p--;
+ }
+
+ camel_url_set_path (url, path);
+ g_free (path);
+
+ path = camel_url_to_string (url, 0);
+ camel_url_free (url);
+
+ return path;
+ } else {
+ return em_uri_from_camel (uri);
+ }
+}
+
+static void
+upgrade_vfolder_sources_1_4 (xmlDocPtr doc)
+{
+ xmlNodePtr root, node;
+
+ if (!doc || !(root = xmlDocGetRootElement (doc)))
+ return;
+
+ if (!root->name || strcmp ((char *)root->name, "filteroptions") != 0) {
+ /* root node is not <filteroptions>, nothing to upgrade */
+ return;
+ }
+
+ if (!(node = xml_find_node (root, "ruleset"))) {
+ /* no ruleset node, nothing to upgrade */
+ return;
+ }
+
+ node = node->children;
+ while (node != NULL) {
+ if (node->name && !strcmp ((char *)node->name, "rule")) {
+ xmlNodePtr sources;
+ char *src;
+
+ if (!(src = (char *)xmlGetProp (node, (const unsigned char *)"source")))
+ src = (char *)xmlStrdup ((const unsigned char *)"local"); /* default to all local folders? */
+
+ xmlSetProp (node, (const unsigned char *)"source", (const unsigned char *)"incoming");
+
+ if (!(sources = xml_find_node (node, "sources")))
+ sources = xmlNewChild (node, NULL, (const unsigned char *)"sources", NULL);
+
+ xmlSetProp (sources, (const unsigned char *)"with", (unsigned char *)src);
+ xmlFree (src);
+ }
+
+ node = node->next;
+ }
+}
+
+static char *
+get_nth_sig (int id)
+{
+ ESignatureList *list;
+ ESignature *sig;
+ EIterator *iter;
+ char *uid = NULL;
+ int i = 0;
+
+ list = e_get_signature_list ();
+ iter = e_list_get_iterator ((EList *) list);
+
+ while (e_iterator_is_valid (iter) && i < id) {
+ e_iterator_next (iter);
+ i++;
+ }
+
+ if (i == id && e_iterator_is_valid (iter)) {
+ sig = (ESignature *) e_iterator_get (iter);
+ uid = g_strdup (sig->uid);
+ }
+
+ g_object_unref (iter);
+
+ return uid;
+}
+
+static void
+em_upgrade_accounts_1_4 (void)
+{
+ EAccountList *accounts;
+ EIterator *iter;
+
+ if (!(accounts = e_get_account_list ()))
+ return;
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ EAccount *account = (EAccount *) e_iterator_get (iter);
+ char *url;
+
+ if (account->drafts_folder_uri) {
+ url = upgrade_xml_uris_1_4 (account->drafts_folder_uri);
+ g_free (account->drafts_folder_uri);
+ account->drafts_folder_uri = url;
+ }
+
+ if (account->sent_folder_uri) {
+ url = upgrade_xml_uris_1_4 (account->sent_folder_uri);
+ g_free (account->sent_folder_uri);
+ account->sent_folder_uri = url;
+ }
+
+ if (account->id->sig_uid && !strncmp (account->id->sig_uid, "::", 2)) {
+ int sig_id;
+
+ sig_id = strtol (account->id->sig_uid + 2, NULL, 10);
+ g_free (account->id->sig_uid);
+ account->id->sig_uid = get_nth_sig (sig_id);
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ e_account_list_save (accounts);
+}
+
+static gboolean
+em_migrate_pop_uid_caches_1_4 (const char *data_dir, GError **error)
+{
+ GString *oldpath, *newpath;
+ struct dirent *dent;
+ size_t olen, nlen;
+ char *cache_dir;
+ DIR *dir;
+ gboolean success = TRUE;
+
+ /* Sigh, too many unique strings to translate, for cases which shouldn't ever happen */
+
+ /* open the old cache dir */
+ cache_dir = g_build_filename (g_get_home_dir (), "evolution", "mail", "pop3", NULL);
+ if (!(dir = opendir (cache_dir))) {
+ if (errno == ENOENT) {
+ g_free(cache_dir);
+ return TRUE;
+ }
+
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to open old POP keep-on-server data "
+ "`%s': %s"), cache_dir, g_strerror (errno));
+ g_free (cache_dir);
+ return FALSE;
+ }
+
+ oldpath = g_string_new (cache_dir);
+ g_string_append_c (oldpath, '/');
+ olen = oldpath->len;
+ g_free (cache_dir);
+
+ cache_dir = g_build_filename (data_dir, "pop", NULL);
+ if (g_mkdir_with_parents (cache_dir, 0777) == -1) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to create POP3 keep-on-server data "
+ "directory `%s': %s"), cache_dir,
+ g_strerror (errno));
+ g_string_free (oldpath, TRUE);
+ g_free (cache_dir);
+ closedir (dir);
+ return FALSE;
+ }
+
+ newpath = g_string_new (cache_dir);
+ g_string_append_c (newpath, '/');
+ nlen = newpath->len;
+ g_free (cache_dir);
+
+ while (success && (dent = readdir (dir))) {
+ if (strncmp (dent->d_name, "cache-pop:__", 12) != 0)
+ continue;
+
+ g_string_truncate (oldpath, olen);
+ g_string_truncate (newpath, nlen);
+
+ g_string_append (oldpath, dent->d_name);
+ g_string_append (newpath, dent->d_name + 12);
+
+ /* strip the trailing '_' */
+ g_string_truncate (newpath, newpath->len - 1);
+
+ if (g_mkdir_with_parents (newpath->str, 0777) == -1
+ || !cp(oldpath->str, (g_string_append(newpath, "/uid-cache"))->str, FALSE, CP_UNIQUE)) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to copy POP3 keep-on-server data "
+ "`%s': %s"), oldpath->str,
+ g_strerror (errno));
+ success = FALSE;
+ }
+
+ }
+
+ g_string_free (oldpath, TRUE);
+ g_string_free (newpath, TRUE);
+
+ closedir (dir);
+
+ return success;
+}
+
+static gboolean
+em_migrate_imap_caches_1_4 (const char *data_dir, GError **error)
+{
+ char *src, *dest;
+ struct stat st;
+
+ src = g_build_filename (g_get_home_dir (), "evolution", "mail", "imap", NULL);
+ if (stat (src, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_free (src);
+ return TRUE;
+ }
+
+ dest = g_build_filename (data_dir, "imap", NULL);
+
+ /* we don't care if this fails, it's only a cache... */
+ cp_r (src, dest, "summary", CP_OVERWRITE);
+
+ g_free (dest);
+ g_free (src);
+
+ return TRUE;
+}
+
+static gboolean
+em_migrate_folder_expand_state_1_4 (const char *data_dir, GError **error)
+{
+ GString *srcpath, *destpath;
+ size_t slen, dlen, rlen;
+ char *evo14_mbox_root;
+ struct dirent *dent;
+ struct stat st;
+ DIR *dir;
+
+ srcpath = g_string_new (g_get_home_dir ());
+ g_string_append (srcpath, "/evolution/config");
+ if (stat (srcpath->str, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_string_free (srcpath, TRUE);
+ return TRUE;
+ }
+
+ destpath = g_string_new (data_dir);
+ g_string_append (destpath, "/config");
+ if (g_mkdir_with_parents (destpath->str, 0777) == -1 || !(dir = opendir (srcpath->str))) {
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+ return TRUE;
+ }
+
+ g_string_append (srcpath, "/et-expanded-");
+ slen = srcpath->len;
+ g_string_append (destpath, "/et-expanded-");
+ dlen = destpath->len;
+
+ evo14_mbox_root = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+ e_filename_make_safe (evo14_mbox_root);
+ rlen = strlen (evo14_mbox_root);
+ evo14_mbox_root = g_realloc (evo14_mbox_root, rlen + 2);
+ evo14_mbox_root[rlen++] = '_';
+ evo14_mbox_root[rlen] = '\0';
+
+ while ((dent = readdir (dir))) {
+ char *full_name, *inptr, *buf = NULL;
+ const char *filename;
+ GString *new;
+
+ if (strncmp (dent->d_name, "et-expanded-", 12) != 0)
+ continue;
+
+ if (!strncmp (dent->d_name + 12, "file:", 5)) {
+ /* need to munge the filename */
+ inptr = dent->d_name + 17;
+
+ if (!strncmp (inptr, evo14_mbox_root, rlen)) {
+ /* this should always be the case afaik... */
+ inptr += rlen;
+ new = g_string_new ("mbox:");
+ g_string_append_printf (new, "%s/local#", data_dir);
+
+ full_name = g_strdup (inptr);
+ inptr = full_name + strlen (full_name) - 12;
+ while (inptr > full_name) {
+ if (!strncmp (inptr, "_subfolders_", 12))
+ memmove (inptr, inptr + 11, strlen (inptr + 11) + 1);
+
+ inptr--;
+ }
+
+ g_string_append (new, full_name);
+ g_free (full_name);
+
+ filename = buf = new->str;
+ g_string_free (new, FALSE);
+ e_filename_make_safe (buf);
+ } else {
+ /* but just in case... */
+ filename = dent->d_name + 12;
+ }
+ } else {
+ /* no munging needed */
+ filename = dent->d_name + 12;
+ }
+
+ g_string_append (srcpath, dent->d_name + 12);
+ g_string_append (destpath, filename);
+ g_free (buf);
+
+ cp (srcpath->str, destpath->str, FALSE, CP_UNIQUE);
+
+ g_string_truncate (srcpath, slen);
+ g_string_truncate (destpath, dlen);
+ }
+
+ closedir (dir);
+
+ g_free (evo14_mbox_root);
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+
+ return TRUE;
+}
+
+static gboolean
+em_migrate_folder_view_settings_1_4 (const char *data_dir, GError **error)
+{
+ GString *srcpath, *destpath;
+ size_t slen, dlen, rlen;
+ char *evo14_mbox_root;
+ struct dirent *dent;
+ struct stat st;
+ DIR *dir;
+
+ srcpath = g_string_new (g_get_home_dir ());
+ g_string_append (srcpath, "/evolution/views/mail");
+ if (stat (srcpath->str, &st) == -1 || !S_ISDIR (st.st_mode)) {
+ g_string_free (srcpath, TRUE);
+ return TRUE;
+ }
+
+ destpath = g_string_new (data_dir);
+ g_string_append (destpath, "/views");
+ if (g_mkdir_with_parents (destpath->str, 0777) == -1 || !(dir = opendir (srcpath->str))) {
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+ return TRUE;
+ }
+
+ g_string_append_c (srcpath, '/');
+ slen = srcpath->len;
+ g_string_append_c (destpath, '/');
+ dlen = destpath->len;
+
+ evo14_mbox_root = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+ e_filename_make_safe (evo14_mbox_root);
+ rlen = strlen (evo14_mbox_root);
+ evo14_mbox_root = g_realloc (evo14_mbox_root, rlen + 2);
+ evo14_mbox_root[rlen++] = '_';
+ evo14_mbox_root[rlen] = '\0';
+
+ while ((dent = readdir (dir))) {
+ char *full_name, *inptr, *buf = NULL;
+ const char *filename, *ext;
+ size_t prelen = 0;
+ GString *new;
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ if (!(ext = strrchr (dent->d_name, '.')))
+ continue;
+
+ if (!strcmp (ext, ".galview") || !strcmp ((char *)dent->d_name, "galview.xml")) {
+ /* just copy the file */
+ filename = dent->d_name;
+ goto copy;
+ } else if (strcmp (ext, ".xml") != 0) {
+ continue;
+ }
+
+ if (!strncmp ((const char *)dent->d_name, "current_view-", 13)) {
+ prelen = 13;
+ } else if (!strncmp ((const char *)dent->d_name, "custom_view-", 12)) {
+ prelen = 12;
+ } else {
+ /* huh? wtf is this file? */
+ continue;
+ }
+
+ if (!strncmp (dent->d_name + prelen, "file:", 5)) {
+ /* need to munge the filename */
+ inptr = dent->d_name + prelen + 5;
+
+ if (!strncmp (inptr, evo14_mbox_root, rlen)) {
+ /* this should always be the case afaik... */
+ inptr += rlen;
+ new = g_string_new ("mbox:");
+ g_string_append_printf (new, "%s/local#", data_dir);
+
+ full_name = g_strdup (inptr);
+ inptr = full_name + strlen (full_name) - 12;
+ while (inptr > full_name) {
+ if (!strncmp (inptr, "_subfolders_", 12))
+ memmove (inptr, inptr + 11, strlen (inptr + 11) + 1);
+
+ inptr--;
+ }
+
+ g_string_append (new, full_name);
+ g_free (full_name);
+
+ filename = buf = new->str;
+ g_string_free (new, FALSE);
+ e_filename_make_safe (buf);
+ } else {
+ /* but just in case... */
+ filename = dent->d_name + prelen;
+ }
+ } else {
+ /* no munging needed */
+ filename = dent->d_name + prelen;
+ }
+
+ copy:
+ g_string_append (srcpath, dent->d_name);
+ if (prelen > 0)
+ g_string_append_len (destpath, dent->d_name, prelen);
+ g_string_append (destpath, filename);
+ g_free (buf);
+
+ cp (srcpath->str, destpath->str, FALSE, CP_UNIQUE);
+
+ g_string_truncate (srcpath, slen);
+ g_string_truncate (destpath, dlen);
+ }
+
+ closedir (dir);
+
+ g_free (evo14_mbox_root);
+ g_string_free (destpath, TRUE);
+ g_string_free (srcpath, TRUE);
+
+ return TRUE;
+}
+
+#define SUBFOLDER_DIR_NAME "subfolders"
+#define SUBFOLDER_DIR_NAME_LEN 10
+
+static char *
+e_path_to_physical (const char *prefix, const char *vpath)
+{
+ const char *p, *newp;
+ char *dp;
+ char *ppath;
+ int ppath_len;
+ int prefix_len;
+
+ while (*vpath == '/')
+ vpath++;
+ if (!prefix)
+ prefix = "";
+
+ /* Calculate the length of the real path. */
+ ppath_len = strlen (vpath);
+ ppath_len++; /* For the ending zero. */
+
+ prefix_len = strlen (prefix);
+ ppath_len += prefix_len;
+ ppath_len++; /* For the separating slash. */
+
+ /* Take account of the fact that we need to translate every
+ * separator into `subfolders/'.
+ */
+ p = vpath;
+ while (1) {
+ newp = strchr (p, '/');
+ if (newp == NULL)
+ break;
+
+ ppath_len += SUBFOLDER_DIR_NAME_LEN;
+ ppath_len++; /* For the separating slash. */
+
+ /* Skip consecutive slashes. */
+ while (*newp == '/')
+ newp++;
+
+ p = newp;
+ };
+
+ ppath = g_malloc (ppath_len);
+ dp = ppath;
+
+ memcpy (dp, prefix, prefix_len);
+ dp += prefix_len;
+ *(dp++) = '/';
+
+ /* Copy the mangled path. */
+ p = vpath;
+ while (1) {
+ newp = strchr (p, '/');
+ if (newp == NULL) {
+ strcpy (dp, p);
+ break;
+ }
+
+ memcpy (dp, p, newp - p + 1); /* `+ 1' to copy the slash too. */
+ dp += newp - p + 1;
+
+ memcpy (dp, SUBFOLDER_DIR_NAME, SUBFOLDER_DIR_NAME_LEN);
+ dp += SUBFOLDER_DIR_NAME_LEN;
+
+ *(dp++) = '/';
+
+ /* Skip consecutive slashes. */
+ while (*newp == '/')
+ newp++;
+
+ p = newp;
+ }
+
+ return ppath;
+}
+
+static gboolean
+em_migrate_imap_cmeta_1_4(const char *data_dir, GError **error)
+{
+ GConfClient *gconf;
+ GSList *paths, *p;
+ EAccountList *accounts;
+ const EAccount *account;
+
+ if (!(accounts = e_get_account_list ()))
+ return TRUE;
+
+ gconf = gconf_client_get_default();
+ paths = gconf_client_get_list(gconf, "/apps/evolution/shell/offline/folder_paths", GCONF_VALUE_STRING, NULL);
+ for (p = paths;p;p = g_slist_next(p)) {
+ char *name, *path;
+
+ name = p->data;
+ if (*name)
+ name++;
+ path = strchr(name, '/');
+ if (path) {
+ *path++ = 0;
+ account = e_account_list_find(accounts, E_ACCOUNT_FIND_NAME, name);
+ if (account && !strncmp(account->source->url, "imap:", 5)) {
+ CamelURL *url = camel_url_new(account->source->url, NULL);
+
+ if (url) {
+ char *dir, *base;
+
+ base = g_strdup_printf("%s/imap/%s %s/folders",
+ data_dir,
+ url->user?url->user:"",
+ url->host?url->host:"");
+
+ dir = e_path_to_physical(base, path);
+ if (g_mkdir_with_parents(dir, 0777) == 0) {
+ char *cmeta;
+ FILE *fp;
+
+ cmeta = g_build_filename(dir, "cmeta", NULL);
+ fp = fopen(cmeta, "w");
+ if (fp) {
+ /* header/version */
+ fwrite("CLMD", 4, 1, fp);
+ camel_file_util_encode_uint32(fp, 1);
+ /* meta count, do we have any metadata? */
+ camel_file_util_encode_uint32(fp, 0);
+ /* prop count */
+ camel_file_util_encode_uint32(fp, 1);
+ /* sync offline property */
+ camel_file_util_encode_uint32(fp, CAMEL_DISCO_FOLDER_OFFLINE_SYNC);
+ camel_file_util_encode_uint32(fp, 1);
+ fclose(fp);
+ } else {
+ g_warning("couldn't create imap folder cmeta file '%s'", cmeta);
+ }
+ g_free(cmeta);
+ } else {
+ g_warning("couldn't create imap folder directory '%s'", dir);
+ }
+ g_free(dir);
+ g_free(base);
+ camel_url_free(url);
+ }
+ } else
+ g_warning("can't find offline folder '%s' '%s'", name, path);
+ }
+ g_free(p->data);
+ }
+ g_slist_free(paths);
+ g_object_unref(gconf);
+
+ /* we couldn't care less if this doesn't work */
+
+ return TRUE;
+}
+
+static void
+remove_system_searches(xmlDocPtr searches)
+{
+ xmlNodePtr node;
+
+ /* in pre 2.0, system searches were stored in the user
+ * searches.xml file with the source set to 'demand'. In 2.0+
+ * the system searches are stored in the system
+ * searchtypes.xml file instead */
+
+ node = xmlDocGetRootElement(searches);
+ if (!node->name || strcmp((char *)node->name, "filteroptions"))
+ return;
+
+ if (!(node = xml_find_node(node, "ruleset")))
+ return;
+
+ node = node->children;
+ while (node != NULL) {
+ xmlNodePtr nnode = node->next;
+
+ if (node->name && !strcmp ((char *)node->name, "rule")) {
+ char *src;
+
+ src = (char *)xmlGetProp(node, (unsigned char *)"source");
+ if (src && !strcmp((char *)src, "demand")) {
+ xmlUnlinkNode(node);
+ xmlFreeNodeList(node);
+ }
+ xmlFree (src);
+ }
+
+ node = nnode;
+ }
+}
+
+static gboolean
+em_migrate_1_4 (const char *data_dir, xmlDocPtr filters, xmlDocPtr vfolders, GError **error)
+{
+ EMMigrateSession *session;
+ CamelException lex;
+ struct stat st;
+ gchar *path;
+ xmlDocPtr searches;
+
+ camel_init (data_dir, TRUE);
+ camel_provider_init();
+ session = (EMMigrateSession *) em_migrate_session_new (data_dir);
+
+ session->srcdir = g_build_filename (g_get_home_dir (), "evolution", "local", NULL);
+
+ path = g_strdup_printf ("mbox:%s/.evolution/mail/local", g_get_home_dir ());
+ if (stat (path + 5, &st) == -1) {
+ if (errno != ENOENT || g_mkdir_with_parents (path + 5, 0777) == -1) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Failed to create local mail storage "
+ "`%s': %s"), path + 5, g_strerror (errno));
+ g_free (session->srcdir);
+ camel_object_unref (session);
+ g_free (path);
+ return FALSE;
+ }
+ }
+
+ camel_exception_init (&lex);
+ if (!(session->store = camel_session_get_store ((CamelSession *) session, path, &lex))) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Failed to create local mail storage `%s': %s"),
+ path, lex.desc);
+ g_free (session->srcdir);
+ camel_object_unref (session);
+ camel_exception_clear (&lex);
+ g_free (path);
+ return FALSE;
+ }
+ g_free (path);
+
+ if (!em_migrate_local_folders_1_4 (session, error))
+ return FALSE;
+
+ camel_object_unref (session->store);
+ g_free (session->srcdir);
+
+ camel_object_unref (session);
+
+ em_upgrade_accounts_1_4();
+
+ upgrade_xml_uris(filters, upgrade_xml_uris_1_4);
+ upgrade_vfolder_sources_1_4(vfolders);
+ upgrade_xml_uris(vfolders, upgrade_xml_uris_1_4);
+
+ path = g_build_filename(g_get_home_dir(), "evolution", NULL);
+ searches = emm_load_xml(path, "searches.xml");
+ g_free(path);
+ if (searches) {
+ remove_system_searches(searches);
+ emm_save_xml(searches, data_dir, "searches.xml");
+ xmlFreeDoc(searches);
+ }
+
+ if (!em_migrate_pop_uid_caches_1_4 (data_dir, error))
+ return FALSE;
+
+ /* these are non-fatal */
+ em_migrate_imap_caches_1_4 (data_dir, error);
+ g_clear_error (error);
+ em_migrate_folder_expand_state_1_4 (data_dir, error);
+ g_clear_error (error);
+ em_migrate_folder_view_settings_1_4 (data_dir, error);
+ g_clear_error (error);
+ em_migrate_imap_cmeta_1_4 (data_dir, error);
+ g_clear_error (error);
+
+ return TRUE;
+}
+
+static void
+em_update_accounts_2_11 (void)
+{
+ EAccountList *accounts;
+ EIterator *iter;
+ gboolean changed = FALSE;
+
+ if (!(accounts = e_get_account_list ()))
+ return;
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ while (e_iterator_is_valid (iter)) {
+ EAccount *account = (EAccount *) e_iterator_get (iter);
+
+ if (g_str_has_prefix (account->source->url, "spool://")) {
+ if (g_file_test (account->source->url + 8, G_FILE_TEST_IS_DIR)) {
+ char *str = g_strdup_printf ("spooldir://%s", account->source->url + 8);
+
+ g_free (account->source->url);
+ account->source->url = str;
+ changed = TRUE;
+ }
+ }
+
+ e_iterator_next (iter);
+ }
+
+ g_object_unref (iter);
+
+ if (changed)
+ e_account_list_save (accounts);
+}
+
+#endif /* !G_OS_WIN32 */
+
+static gboolean
+emm_setup_initial(const gchar *data_dir)
+{
+ GDir *dir;
+ const char *d;
+ char *local = NULL, *base;
+ const gchar * const *language_names;
+
+ /* special-case - this means brand new install of evolution */
+ /* FIXME: create default folders and stuff... */
+
+ d(printf("Setting up initial mail tree\n"));
+
+ base = g_build_filename(data_dir, "local", NULL);
+ if (g_mkdir_with_parents(base, 0777) == -1 && errno != EEXIST) {
+ g_free(base);
+ return FALSE;
+ }
+
+ /* e.g. try en-AU then en, etc */
+ language_names = g_get_language_names ();
+ while (*language_names != NULL) {
+ local = g_build_filename (
+ EVOLUTION_PRIVDATADIR, "default",
+ *language_names, "mail", "local", NULL);
+ if (g_file_test (local, G_FILE_TEST_EXISTS))
+ break;
+ g_free (local);
+ language_names++;
+ }
+
+ /* Make sure we found one. */
+ g_return_val_if_fail (*language_names != NULL, FALSE);
+
+ dir = g_dir_open(local, 0, NULL);
+ if (dir) {
+ while ((d = g_dir_read_name(dir))) {
+ char *src, *dest;
+
+ src = g_build_filename(local, d, NULL);
+ dest = g_build_filename(base, d, NULL);
+
+ cp(src, dest, FALSE, CP_UNIQUE);
+ g_free(dest);
+ g_free(src);
+ }
+ g_dir_close(dir);
+ }
+
+ g_free(local);
+ g_free(base);
+
+ return TRUE;
+}
+
+static gboolean
+is_in_plugs_list (GSList *list, const gchar *value)
+{
+ GSList *l;
+
+ for (l = list; l; l = l->next) {
+ if (l->data && !strcmp (l->data, value))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * em_update_message_notify_settings_2_21
+ * DBus plugin and sound email notification was merged to mail-notification plugin,
+ * so move these options to new locations.
+ */
+static void
+em_update_message_notify_settings_2_21 (void)
+{
+ GConfClient *client;
+ GConfValue *is_key;
+ gboolean dbus, status;
+ GSList *list;
+ gchar *str;
+ gint val;
+
+ client = gconf_client_get_default ();
+
+ is_key = gconf_client_get (client, "/apps/evolution/eplugin/mail-notification/dbus-enabled", NULL);
+ if (is_key) {
+ /* already migrated, so do not migrate again */
+ gconf_value_free (is_key);
+ g_object_unref (client);
+
+ return;
+ }
+
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-blink-icon",
+ gconf_client_get_bool (client, "/apps/evolution/mail/notification/blink-status-icon", NULL), NULL);
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-notification",
+ gconf_client_get_bool (client, "/apps/evolution/mail/notification/notification", NULL), NULL);
+
+ list = gconf_client_get_list (client, "/apps/evolution/eplugin/disabled", GCONF_VALUE_STRING, NULL);
+ dbus = !is_in_plugs_list (list, "org.gnome.evolution.new_mail_notify");
+ status = !is_in_plugs_list (list, "org.gnome.evolution.mail_notification");
+
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/dbus-enabled", dbus, NULL);
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/status-enabled", status, NULL);
+
+ if (!status) {
+ /* enable this plugin, because it holds all those other things */
+ GSList *plugins, *l;
+
+ plugins = e_plugin_list_plugins ();
+
+ for (l = plugins; l; l = l->next) {
+ EPlugin *p = l->data;
+
+ if (p && p->id && !strcmp (p->id, "org.gnome.evolution.mail_notification")) {
+ e_plugin_enable (p, 1);
+ break;
+ }
+ }
+
+ g_slist_foreach (plugins, (GFunc)g_object_unref, NULL);
+ g_slist_free (plugins);
+ }
+
+ g_slist_foreach (list, (GFunc) g_free, NULL);
+ g_slist_free (list);
+
+ val = gconf_client_get_int (client, "/apps/evolution/mail/notify/type", NULL);
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/sound-enabled", val == 1 || val == 2, NULL);
+ gconf_client_set_bool (client, "/apps/evolution/eplugin/mail-notification/sound-beep", val == 0 || val == 1, NULL);
+
+ str = gconf_client_get_string (client, "/apps/evolution/mail/notify/sound", NULL);
+ gconf_client_set_string (client, "/apps/evolution/eplugin/mail-notification/sound-file", str ? str : "", NULL);
+ g_free (str);
+
+ g_object_unref (client);
+}
+
+/* fixing typo in SpamAssassin name */
+static void
+em_update_sa_junk_setting_2_23 (void)
+{
+ GConfClient *client;
+ GConfValue *key;
+
+ client = gconf_client_get_default ();
+
+ key = gconf_client_get (client, "/apps/evolution/mail/junk/default_plugin", NULL);
+ if (key) {
+ const char *str = gconf_value_get_string (key);
+
+ if (str && strcmp (str, "Spamassasin") == 0)
+ gconf_client_set_string (client, "/apps/evolution/mail/junk/default_plugin", "SpamAssassin", NULL);
+
+ gconf_value_free (key);
+ g_object_unref (client);
+
+ return;
+ }
+
+ g_object_unref (client);
+}
+
++static gboolean
++update_progress_in_main_thread (double *progress)
++{
++ em_migrate_set_progress (*progress);
++ return FALSE;
++}
+
+static void
- migrate_folders(CamelStore *store, CamelFolderInfo *fi, const char *acc, CamelException *ex)
++migrate_folders(CamelStore *store, gboolean is_local, CamelFolderInfo *fi, const char *acc, CamelException *ex, gboolean *done, int *nth_folder, int total_folders)
+{
+ CamelFolder *folder;
+
+ while (fi) {
- char *tmp = g_strdup_printf ("%s/%s", acc, fi->full_name);
++ double progress;
++ char *tmp;
++
++ *nth_folder = *nth_folder + 1;
++
++ tmp = g_strdup_printf ("%s/%s", acc, fi->full_name);
+ em_migrate_set_folder_name (tmp);
+ g_free (tmp);
- folder = camel_store_get_folder (store, fi->full_name, 0, ex);
++
++ progress = (double) (*nth_folder) / total_folders;
++ g_idle_add ((GSourceFunc) update_progress_in_main_thread, &progress);
++
++ if (is_local)
++ folder = camel_store_get_folder (store, fi->full_name, CAMEL_STORE_IS_MIGRATING, ex);
++ else
++ folder = camel_store_get_folder (store, fi->full_name, 0, ex);
++
+ if (folder != NULL)
+ camel_folder_summary_migrate_infos (folder->summary);
- migrate_folders(store, fi->child, acc, ex);
++ migrate_folders(store, is_local, fi->child, acc, ex, done, nth_folder, total_folders);
++ fi = fi->next;
++ }
++
++ if ((*nth_folder) == (total_folders - 1))
++ *done = TRUE;
++}
++
++/* This could be in CamelStore.ch */
++static void
++count_folders (CamelFolderInfo *fi, int *count)
++{
++ while (fi) {
++ *count = *count + 1;
++ count_folders (fi->child, count);
+ fi = fi->next;
+ }
+}
+
+static CamelStore *
+setup_local_store (EShellBackend *shell_backend,
+ EMMigrateSession *session)
+{
+ CamelURL *url;
+ const gchar *data_dir;
+ char *tmp;
+ CamelStore *store;
+
+ url = camel_url_new("mbox:", NULL);
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ tmp = g_build_filename (data_dir, "local", NULL);
+ camel_url_set_path(url, tmp);
+ g_free(tmp);
+ tmp = camel_url_to_string(url, 0);
+ store = (CamelStore *)camel_session_get_service(CAMEL_SESSION (session), tmp, CAMEL_PROVIDER_STORE, NULL);
+ g_free(tmp);
+
+ return store;
++}
++
++struct migrate_folders_to_db_structure {
++ char *account_name;
++ CamelException ex;
++ CamelStore *store;
++ CamelFolderInfo *info;
++ gboolean done;
++ gboolean is_local_store;
++};
+
++static void
++migrate_folders_to_db_thread (struct migrate_folders_to_db_structure *migrate_dbs)
++{
++ int num_of_folders = 0, nth_folder = 0;
++ count_folders (migrate_dbs->info, &num_of_folders);
++ migrate_folders (migrate_dbs->store, migrate_dbs->is_local_store, migrate_dbs->info,
++ migrate_dbs->account_name, &(migrate_dbs->ex), &(migrate_dbs->done),
++ &nth_folder, num_of_folders);
+}
++
+static void
+migrate_to_db (EShellBackend *shell_backend)
+{
+ EMMigrateSession *session;
+ EAccountList *accounts;
+ EIterator *iter;
+ int i=0, len;
+ CamelStore *store = NULL;
+ CamelFolderInfo *info;
+ const gchar *data_dir;
+
+ if (!(accounts = e_get_account_list ()))
+ return;
+
+ iter = e_list_get_iterator ((EList *) accounts);
+ len = e_list_length ((EList *) accounts);
+
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ session = (EMMigrateSession *) em_migrate_session_new (data_dir);
+ camel_session_set_online ((CamelSession *) session, FALSE);
- em_migrate_setup_progress_dialog (_("The summary format of the Evolution mailbox "
- "folders has been moved to SQLite since Evolution 2.24.\n\nPlease be "
- "patient while Evolution migrates your folders..."));
++ em_migrate_setup_progress_dialog (
++ _("Migrating Folders"),
++ _("The summary format of the Evolution mailbox "
++ "folders has been moved to SQLite since Evolution 2.24.\n\nPlease be "
++ "patient while Evolution migrates your folders..."));
+
+ em_migrate_set_progress ( (double)i/(len+1));
+ store = setup_local_store (shell_backend, session);
+ info = camel_store_get_folder_info (store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST|CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, NULL);
+ if (info) {
- migrate_folders(store, info, _("On This Computer"), NULL);
++ GThread *thread;
++ struct migrate_folders_to_db_structure migrate_dbs;
++
++ if (g_str_has_suffix (((CamelService *)store)->url->path, ".evolution/mail/local"))
++ migrate_dbs.is_local_store = TRUE;
++ else
++ migrate_dbs.is_local_store = FALSE;
++ camel_exception_init (&migrate_dbs.ex);
++ migrate_dbs.account_name = _("On This Computer");
++ migrate_dbs.info = info;
++ migrate_dbs.store = store;
++ migrate_dbs.done = FALSE;
++
++ thread = g_thread_create ((GThreadFunc) migrate_folders_to_db_thread, &migrate_dbs, TRUE, NULL);
++ while (!migrate_dbs.done)
++ g_main_context_iteration (NULL, TRUE);
+ }
+ i++;
+ em_migrate_set_progress ( (double)i/(len+1));
+
+
+ while (e_iterator_is_valid (iter)) {
+ EAccount *account = (EAccount *) e_iterator_get (iter);
+ EAccountService *service;
+ const char *name;
+
+
+ service = account->source;
+ name = account->name;
+ em_migrate_set_progress ( (double)i/(len+1));
+ if (account->enabled
+ && service->url != NULL
+ && service->url[0]
+ && strncmp(service->url, "mbox:", 5) != 0) {
+
+ CamelException ex;
+
+ camel_exception_init (&ex);
+ e_mail_shell_backend_load_store_by_uri (
+ E_MAIL_SHELL_BACKEND (shell_backend),
+ service->url, name);
+
+ store = (CamelStore *) camel_session_get_service (CAMEL_SESSION (session), service->url, CAMEL_PROVIDER_STORE, &ex);
+ info = camel_store_get_folder_info (store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE|CAMEL_STORE_FOLDER_INFO_FAST|CAMEL_STORE_FOLDER_INFO_SUBSCRIBED, &ex);
+ if (info) {
- migrate_folders(store, info, account->name, &ex);
-
++ GThread *thread;
++ struct migrate_folders_to_db_structure migrate_dbs;
++
++ migrate_dbs.ex = ex;
++ migrate_dbs.account_name = account->name;
++ migrate_dbs.info = info;
++ migrate_dbs.store = store;
++ migrate_dbs.done = FALSE;
++
++ thread = g_thread_create ((GThreadFunc) migrate_folders_to_db_thread, &migrate_dbs, TRUE, NULL);
++ while (!migrate_dbs.done)
++ g_main_context_iteration (NULL, TRUE);
+ } else
+ printf("%s:%s: failed to get folder infos \n", G_STRLOC, G_STRFUNC);
+ camel_exception_clear(&ex);
+
+ }
+ i++;
+ e_iterator_next (iter);
+
+ }
+
+ //camel_session_set_online ((CamelSession *) session, TRUE);
+
+ g_object_unref (iter);
+ em_migrate_close_progress_dialog ();
+
+ g_object_unref (session);
+}
+
+gboolean
+e_mail_shell_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ struct stat st;
+ const gchar *data_dir;
+ gchar *path;
+
+ /* make sure ~/.evolution/mail exists */
+ data_dir = e_shell_backend_get_data_dir (shell_backend);
+ if (g_stat (data_dir, &st) == -1) {
+ if (errno != ENOENT || g_mkdir_with_parents (data_dir, 0777) == -1) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to create local mail folders at "
+ "`%s': %s"), data_dir, g_strerror (errno));
+ return FALSE;
+ }
+ }
+
+ if (major == 0)
+ return emm_setup_initial (data_dir);
+
+ if (major == 1 && minor < 5) {
+#ifndef G_OS_WIN32
+ xmlDocPtr config_xmldb = NULL, filters, vfolders;
+
+ path = g_build_filename (g_get_home_dir (), "evolution", NULL);
+ if (minor <= 2 && !(config_xmldb = emm_load_xml (path, "config.xmldb"))) {
+ g_set_error (
+ error, E_SHELL_MIGRATE_ERROR,
+ E_SHELL_MIGRATE_ERROR_FAILED,
+ _("Unable to read settings from previous "
+ "Evolution install, `evolution/config.xmldb' "
+ "does not exist or is corrupt."));
+ return FALSE;
+ }
+ filters = emm_load_xml (path, "filters.xml");
+ vfolders = emm_load_xml (path, "vfolders.xml");
+ g_free (path);
+
+ if (minor == 0) {
+ if (!em_migrate_1_0 (data_dir, config_xmldb, filters, vfolders, error)) {
+ xmlFreeDoc (config_xmldb);
+ xmlFreeDoc (filters);
+ xmlFreeDoc (vfolders);
+ return FALSE;
+ }
+ }
+
+ if (minor <= 2) {
+ if (!em_migrate_1_2 (data_dir, config_xmldb, filters, vfolders, error)) {
+ xmlFreeDoc (config_xmldb);
+ xmlFreeDoc (filters);
+ xmlFreeDoc (vfolders);
+ return FALSE;
+ }
+
+ xmlFreeDoc (config_xmldb);
+ }
+
+ if (minor <= 4) {
+ if (!em_migrate_1_4 (data_dir, filters, vfolders, error)) {
+ xmlFreeDoc (filters);
+ xmlFreeDoc (vfolders);
+ return FALSE;
+ }
+ }
+
+ if (filters) {
+ emm_save_xml (filters, path, "filters.xml");
+ xmlFreeDoc (filters);
+ }
+
+ if (vfolders) {
+ emm_save_xml (vfolders, path, "vfolders.xml");
+ xmlFreeDoc (vfolders);
+ }
+
+ g_free (path);
+#else
+ g_error ("Upgrading from ancient versions not supported on Windows");
+#endif
+ }
+
+ if (major < 2 || (major == 2 && minor < 12)) {
+#ifndef G_OS_WIN32
+ em_update_accounts_2_11 ();
+#else
+ g_error ("Upgrading from ancient versions not supported on Windows");
+#endif
+ }
+
+
+ if (major < 2 || (major == 2 && minor < 22))
+ em_update_message_notify_settings_2_21 ();
+
+ if (major < 2 || (major == 2 && minor < 24)) {
+ em_update_sa_junk_setting_2_23 ();
+ migrate_to_db (shell_backend);
+ }
+
+ return TRUE;
+}
diff --cc mail/e-mail-shell-migrate.h
index c5fb08f,0000000..8f3057e
mode 100644,000000..100644
--- a/mail/e-mail-shell-migrate.h
+++ b/mail/e-mail-shell-migrate.h
@@@ -1,38 -1,0 +1,38 @@@
+/*
+ * e-mail-shell-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_BACKEND_MIGRATE_H
+#define E_MAIL_SHELL_BACKEND_MIGRATE_H
+
+#include <glib.h>
+#include <shell/e-shell-backend.h>
+
+G_BEGIN_DECLS
+
+gboolean e_mail_shell_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_BACKEND_MIGRATE_H */
diff --cc mail/e-mail-shell-sidebar.c
index 6f6bdf7,0000000..1b090fa
mode 100644,000000..100644
--- a/mail/e-mail-shell-sidebar.c
+++ b/mail/e-mail-shell-sidebar.c
@@@ -1,347 -1,0 +1,347 @@@
+/*
+ * e-mail-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-sidebar.h"
+
+#include <string.h>
+#include <camel/camel.h>
+
+#include "em-utils.h"
+#include "em-folder-utils.h"
+
+#include "e-mail-shell-backend.h"
+
+#define E_MAIL_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarPrivate))
+
+struct _EMailShellSidebarPrivate {
+ GtkWidget *folder_tree;
+};
+
+enum {
+ PROP_0,
+ PROP_FOLDER_TREE
+};
+
+static gpointer parent_class;
+static GType mail_shell_sidebar_type;
+
+static void
+mail_shell_sidebar_selection_changed_cb (EShellSidebar *shell_sidebar,
+ GtkTreeSelection *selection)
+{
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ const gchar *icon_name;
+ gchar *display_name = NULL;
+ gboolean is_folder = FALSE;
+ guint flags = 0;
+
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ gtk_tree_model_get (
+ model, &iter,
+ COL_STRING_DISPLAY_NAME, &display_name,
+ COL_BOOL_IS_FOLDER, &is_folder,
+ COL_UINT_FLAGS, &flags, -1);
+
+ if (is_folder)
+ icon_name = em_folder_utils_get_icon_name (flags);
+ else {
+ icon_name = shell_view_class->icon_name;
+ display_name = g_strdup (shell_view_class->label);
+ }
+
+ e_shell_sidebar_set_icon_name (shell_sidebar, icon_name);
+ e_shell_sidebar_set_primary_text (shell_sidebar, display_name);
+
+ g_free (display_name);
+}
+
+static void
+mail_shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FOLDER_TREE:
+ g_value_set_object (
+ value, e_mail_shell_sidebar_get_folder_tree (
+ E_MAIL_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_shell_sidebar_dispose (GObject *object)
+{
+ EMailShellSidebarPrivate *priv;
+
+ priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->folder_tree != NULL) {
+ g_object_unref (priv->folder_tree);
+ priv->folder_tree = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_shell_sidebar_finalize (GObject *object)
+{
+ EMailShellSidebarPrivate *priv;
+
+ priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_shell_sidebar_constructed (GObject *object)
+{
+ EMailShellSidebarPrivate *priv;
+ EMailShellBackend *mail_shell_backend;
+ EShellSidebar *shell_sidebar;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ priv = E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ /* Chain up to parent's constructed method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ shell_sidebar = E_SHELL_SIDEBAR (object);
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
+
+ /* Build sidebar widgets. */
+
+ container = GTK_WIDGET (object);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = em_folder_tree_new (mail_shell_backend);
+ em_folder_tree_set_excluded (EM_FOLDER_TREE (widget), 0);
+ em_folder_tree_enable_drag_and_drop (EM_FOLDER_TREE (widget));
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->folder_tree = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ tree_view = GTK_TREE_VIEW (priv->folder_tree);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (mail_shell_sidebar_selection_changed_cb),
+ shell_sidebar);
+}
+
+static guint32
+mail_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ EMailShellBackend *mail_shell_backend;
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ EMFolderTree *folder_tree;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ CamelFolder *folder;
+ CamelStore *local_store;
+ CamelStore *store;
+ gchar *full_name;
+ gchar *uri;
+ gboolean allows_children = TRUE;
+ gboolean can_delete = TRUE;
+ gboolean is_junk = FALSE;
+ gboolean is_outbox = FALSE;
+ gboolean is_store;
+ gboolean is_trash = FALSE;
+ guint32 folder_flags = 0;
+ guint32 state = 0;
+
+ shell_view = e_shell_sidebar_get_shell_view (shell_sidebar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ mail_shell_backend = E_MAIL_SHELL_BACKEND (shell_backend);
+ local_store = e_mail_shell_backend_get_local_store (mail_shell_backend);
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ tree_view = GTK_TREE_VIEW (folder_tree);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return 0;
+
+ gtk_tree_model_get (
+ model, &iter,
+ COL_POINTER_CAMEL_STORE, &store,
+ COL_STRING_FULL_NAME, &full_name,
+ COL_BOOL_IS_STORE, &is_store,
+ COL_UINT_FLAGS, &folder_flags,
+ COL_STRING_URI, &uri, -1);
+
+ if (!is_store) {
+ is_junk = (strcmp (full_name, CAMEL_VJUNK_NAME) == 0);
+ is_trash = (strcmp (full_name, CAMEL_VTRASH_NAME) == 0);
+ allows_children = !(is_junk || is_trash);
+
+ /* Don't allow deletion of special local folders. */
+ if (store == local_store)
+ can_delete =
+ (strcmp (full_name, "Drafts") != 0) &&
+ (strcmp (full_name, "Inbox") != 0) &&
+ (strcmp (full_name, "Outbox") != 0) &&
+ (strcmp (full_name, "Sent") != 0) &&
+ (strcmp (full_name, "Templates") != 0);
+
+ folder = em_folder_tree_get_selected_folder (folder_tree);
+ is_outbox = em_utils_folder_is_outbox (folder, NULL);
+ can_delete &= !(folder_flags & CAMEL_FOLDER_SYSTEM);
+ }
+
+ if (allows_children)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN;
+ if (can_delete)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE;
+ if (is_junk)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK;
+ if (is_outbox)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX;
+ if (is_store)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE;
+ if (is_trash)
+ state |= E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH;
+
+ return state;
+}
+
+static void
+mail_shell_sidebar_class_init (EMailShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ EShellSidebarClass *shell_sidebar_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = mail_shell_sidebar_get_property;
+ object_class->dispose = mail_shell_sidebar_dispose;
+ object_class->finalize = mail_shell_sidebar_finalize;
+ object_class->constructed = mail_shell_sidebar_constructed;
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_CLASS (class);
+ shell_sidebar_class->check_state = mail_shell_sidebar_check_state;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FOLDER_TREE,
+ g_param_spec_object (
+ "folder-tree",
+ NULL,
+ NULL,
+ EM_TYPE_FOLDER_TREE,
+ G_PARAM_READABLE));
+}
+
+static void
+mail_shell_sidebar_init (EMailShellSidebar *mail_shell_sidebar)
+{
+ mail_shell_sidebar->priv =
+ E_MAIL_SHELL_SIDEBAR_GET_PRIVATE (mail_shell_sidebar);
+
+ /* Postpone widget construction until we have a shell view. */
+}
+
+GType
+e_mail_shell_sidebar_get_type (void)
+{
+ return mail_shell_sidebar_type;
+}
+
+void
+e_mail_shell_sidebar_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EMailShellSidebarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_shell_sidebar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailShellSidebar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_shell_sidebar_init,
+ NULL /* value_table */
+ };
+
+ mail_shell_sidebar_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_SIDEBAR,
+ "EMailShellSidebar", &type_info, 0);
+}
+
+GtkWidget *
+e_mail_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_MAIL_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+EMFolderTree *
+e_mail_shell_sidebar_get_folder_tree (EMailShellSidebar *mail_shell_sidebar)
+{
+ g_return_val_if_fail (
+ E_IS_MAIL_SHELL_SIDEBAR (mail_shell_sidebar), NULL);
+
+ return EM_FOLDER_TREE (mail_shell_sidebar->priv->folder_tree);
+}
diff --cc mail/e-mail-shell-sidebar.h
index 5075225,0000000..10a2ff6
mode 100644,000000..100644
--- a/mail/e-mail-shell-sidebar.h
+++ b/mail/e-mail-shell-sidebar.h
@@@ -1,81 -1,0 +1,81 @@@
+/*
+ * e-mail-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_SIDEBAR_H
+#define E_MAIL_SHELL_SIDEBAR_H
+
+#include <shell/e-shell-sidebar.h>
+#include <shell/e-shell-view.h>
+#include <mail/em-folder-tree.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SHELL_SIDEBAR \
+ (e_mail_shell_sidebar_get_type ())
+#define E_MAIL_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebar))
+#define E_MAIL_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarClass))
+#define E_IS_MAIL_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_SIDEBAR))
+#define E_IS_MAIL_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_SIDEBAR))
+#define E_MAIL_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_SHELL_SIDEBAR, EMailShellSidebarClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailShellSidebar EMailShellSidebar;
+typedef struct _EMailShellSidebarClass EMailShellSidebarClass;
+typedef struct _EMailShellSidebarPrivate EMailShellSidebarPrivate;
+
+enum {
+ E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN = 1 << 0,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE = 1 << 1,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK = 1 << 2,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX = 1 << 3,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE = 1 << 4,
+ E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH = 1 << 5
+};
+
+struct _EMailShellSidebar {
+ EShellSidebar parent;
+ EMailShellSidebarPrivate *priv;
+};
+
+struct _EMailShellSidebarClass {
+ EShellSidebarClass parent_class;
+};
+
+GType e_mail_shell_sidebar_get_type (void);
+void e_mail_shell_sidebar_register_type
+ (GTypeModule *type_module);
+GtkWidget * e_mail_shell_sidebar_new(EShellView *shell_view);
+EMFolderTree * e_mail_shell_sidebar_get_folder_tree
+ (EMailShellSidebar *mail_shell_sidebar);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_SIDEBAR_H */
diff --cc mail/e-mail-shell-view-actions.c
index 33d497c,0000000..3d0b76d
mode 100644,000000..100644
--- a/mail/e-mail-shell-view-actions.c
+++ b/mail/e-mail-shell-view-actions.c
@@@ -1,1713 -1,0 +1,1713 @@@
+/*
+ * e-mail-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-view-private.h"
+
+static void
+action_gal_save_custom_view_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ EShellView *shell_view;
+ GalViewInstance *view_instance;
+
+ /* All shell views repond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with saving the custom view. */
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ view_instance = e_mail_shell_content_get_view_instance (mail_shell_content);
+ gal_view_instance_save_as (view_instance);
+}
+
+static void
+action_mail_account_disable_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellBackend *mail_shell_backend;
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ EAccountList *account_list;
+ EAccount *account;
+ gchar *folder_uri;
+
+ mail_shell_backend = mail_shell_view->priv->mail_shell_backend;
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_uri = em_folder_tree_get_selected_uri (folder_tree);
+ g_return_if_fail (folder_uri != NULL);
+
+ account_list = e_get_account_list ();
+ account = mail_config_get_account_by_source_url (folder_uri);
+ g_return_if_fail (account != NULL);
+
+ if (e_account_list_account_has_proxies (account_list, account))
+ e_account_list_remove_account_proxies (account_list, account);
+
+ account->enabled = !account->enabled;
+ e_account_list_change (account_list, account);
+ e_mail_shell_backend_remove_store_by_uri (
+ mail_shell_backend, folder_uri);
+
+ if (account->parent_uid != NULL)
+ e_account_list_remove (account_list, account);
+
+ e_account_list_save (account_list);
+
+ g_free (folder_uri);
+}
+
+static void
+action_mail_create_search_folder_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ /* FIXME */
+ g_print ("Action: %s\n", gtk_action_get_name (GTK_ACTION (action)));
+}
+
+static void
+action_mail_download_foreach_cb (CamelService *service)
+{
+ if (CAMEL_IS_DISCO_STORE (service) ||
+ CAMEL_IS_OFFLINE_STORE (service))
+ mail_store_prepare_offline (CAMEL_STORE (service));
+}
+
+static void
+action_mail_download_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellBackend *mail_shell_backend;
+
+ mail_shell_backend = mail_shell_view->priv->mail_shell_backend;
+
+ e_mail_shell_backend_stores_foreach (
+ mail_shell_backend, (GHFunc)
+ action_mail_download_foreach_cb, NULL);
+}
+
+static void
+action_mail_empty_trash_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ em_utils_empty_trash (GTK_WIDGET (shell_window));
+}
+
+static void
+action_mail_flush_outbox_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ mail_send ();
+}
+
+static void
+action_mail_folder_copy_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ CamelFolderInfo *folder_info;
+ EMFolderTree *folder_tree;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
+ g_return_if_fail (folder_info != NULL);
+
+ /* XXX Leaking folder_info? */
+ em_folder_utils_copy_folder (folder_info, FALSE);
+}
+
+static void
+action_mail_folder_delete_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ CamelFolder *folder;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder = em_folder_tree_get_selected_folder (folder_tree);
+ g_return_if_fail (folder != NULL);
+
+ em_folder_utils_delete_folder (folder);
+}
+
+static void
+action_mail_folder_expunge_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ g_return_if_fail (message_list->folder != NULL);
+
+ em_utils_expunge_folder (
+ GTK_WIDGET (shell_window), message_list->folder);
+}
+
+static void
+action_mail_folder_mark_all_as_read_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ CamelFolder *folder;
+ GtkWindow *parent;
+ GPtrArray *uids;
+ const gchar *key;
+ const gchar *prompt;
+ guint ii;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ parent = GTK_WINDOW (shell_window);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder = message_list->folder;
+ g_return_if_fail (folder != NULL);
+
+ key = "/apps/evolution/mail/prompts/mark_all_read";
+ prompt = "mail:ask-mark-all-read";
+
+ if (!em_utils_prompt_user (parent, key, prompt, NULL))
+ return;
+
+ uids = message_list_get_uids (message_list);
+
+ camel_folder_freeze (folder);
+ for (ii = 0; ii < uids->len; ii++)
+ camel_folder_set_message_flags (
+ folder, uids->pdata[ii],
+ CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN);
+ camel_folder_thaw (folder);
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_folder_move_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ CamelFolderInfo *folder_info;
+ EMFolderTree *folder_tree;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
+ g_return_if_fail (folder_info != NULL);
+
+ /* XXX Leaking folder_info? */
+ em_folder_utils_copy_folder (folder_info, TRUE);
+}
+
+static void
+action_mail_folder_new_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EMailShellSidebar *mail_shell_sidebar;
+ CamelFolderInfo *folder_info;
+ EMFolderTree *folder_tree;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder_info = em_folder_tree_get_selected_folder_info (folder_tree);
+ g_return_if_fail (folder_info != NULL);
+
+ em_folder_utils_create_folder (
+ folder_info, folder_tree, GTK_WINDOW (shell_window));
+ camel_folder_info_free (folder_info);
+}
+
+static void
+action_mail_folder_properties_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ EShellView *shell_view;
+ GtkTreeSelection *selection;
+ GtkTreeView *tree_view;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *uri;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ tree_view = GTK_TREE_VIEW (folder_tree);
+ selection = gtk_tree_view_get_selection (tree_view);
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, COL_STRING_URI, &uri, -1);
+ em_folder_properties_show (shell_view, NULL, uri);
+ g_free (uri);
+}
+
+static void
+action_mail_folder_refresh_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ CamelFolder *folder;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder = em_folder_tree_get_selected_folder (folder_tree);
+ g_return_if_fail (folder != NULL);
+
+ mail_refresh_folder (folder, NULL, NULL);
+}
+
+static void
+action_mail_folder_rename_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ CamelFolder *folder;
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+ folder = em_folder_tree_get_selected_folder (folder_tree);
+ g_return_if_fail (folder != NULL);
+
+ em_folder_utils_rename_folder (folder);
+}
+
+/* Helper for action_mail_folder_select_all_cb() */
+static gboolean
+action_mail_folder_select_all_timeout_cb (MessageList *message_list)
+{
+ message_list_select_all (message_list);
+ gtk_widget_grab_focus (GTK_WIDGET (message_list));
+
+ return FALSE;
+}
+
+static void
+action_mail_folder_select_all_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ if (message_list->threaded) {
+ gtk_action_activate (ACTION (MAIL_THREADS_EXPAND_ALL));
+
+ /* XXX The timeout below is added so that the execution
+ * thread to expand all conversation threads would
+ * have completed. The timeout 505 is just to ensure
+ * that the value is a small delta more than the
+ * timeout value in mail_regen_list(). */
+ g_timeout_add (
+ 505, (GSourceFunc)
+ action_mail_folder_select_all_timeout_cb,
+ message_list);
+ } else
+ /* If there is no threading, just select all immediately. */
+ action_mail_folder_select_all_timeout_cb (message_list);
+}
+
+static void
+action_mail_folder_select_thread_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_select_thread (message_list);
+}
+
+static void
+action_mail_folder_select_subthread_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_select_subthread (message_list);
+}
+
+static void
+action_mail_hide_deleted_cb (GtkToggleAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+ gboolean active;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ active = gtk_toggle_action_get_active (action);
+ message_list_set_hidedeleted (message_list, active);
+}
+
+static void
+action_mail_hide_read_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_hide_add (
+ message_list,
+ "(match-all (system-flag \"seen\"))",
+ ML_HIDE_SAME, ML_HIDE_SAME);
+}
+
+static void
+action_mail_hide_selected_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+ GPtrArray *uids;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ uids = message_list_get_selected (message_list);
+ message_list_hide_uids (message_list, uids);
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_label_cb (GtkToggleAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GPtrArray *uids;
+ const gchar *tag;
+ gint ii;
+
+ tag = g_object_get_data (G_OBJECT (action), "tag");
+ g_return_if_fail (tag != NULL);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder = message_list->folder;
+
+ uids = message_list_get_selected (message_list);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ if (gtk_toggle_action_get_active (action))
+ camel_folder_set_message_user_flag (
+ folder, uids->pdata[ii], tag, TRUE);
+ else {
+ camel_folder_set_message_user_flag (
+ folder, uids->pdata[ii], tag, FALSE);
+ camel_folder_set_message_user_tag (
+ folder, uids->pdata[ii], "label", NULL);
+ }
+ }
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_label_new_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EMailLabelDialog *label_dialog;
+ EMailLabelListStore *store;
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelFolder *folder;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkWidget *dialog;
+ GPtrArray *uids;
+ GdkColor label_color;
+ const gchar *property_name;
+ const gchar *label_name;
+ gchar *label_tag;
+ gint n_children;
+ guint ii;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ dialog = e_mail_label_dialog_new (GTK_WINDOW (shell_window));
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Add Label"));
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ label_dialog = E_MAIL_LABEL_DIALOG (dialog);
+ label_name = e_mail_label_dialog_get_label_name (label_dialog);
+ e_mail_label_dialog_get_label_color (label_dialog, &label_color);
+
+ property_name = "mail-label-list-store";
+ store = e_shell_settings_get_object (shell_settings, property_name);
+ e_mail_label_list_store_set (store, NULL, label_name, &label_color);
+ g_object_unref (store);
+
+ /* XXX This is awkward. We've added a new label to the list store
+ * but we don't have the new label's tag nor an iterator to use
+ * to fetch it. We know the label was appended to the store,
+ * so we have to dig it out manually. EMailLabelListStore API
+ * probably needs some rethinking. */
+ model = GTK_TREE_MODEL (store);
+ n_children = gtk_tree_model_iter_n_children (model, NULL);
+ gtk_tree_model_iter_nth_child (model, &iter, NULL, n_children - 1);
+ label_tag = e_mail_label_list_store_get_tag (store, &iter);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder = message_list->folder;
+
+ uids = message_list_get_selected (message_list);
+
+ for (ii = 0; ii < uids->len; ii++)
+ camel_folder_set_message_user_flag (
+ folder, uids->pdata[ii], label_tag, TRUE);
+
+ message_list_free_uids (message_list, uids);
+
+ g_free (label_tag);
+
+exit:
+ gtk_widget_destroy (dialog);
+}
+
+static void
+action_mail_label_none_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellSettings *shell_settings;
+ EShellWindow *shell_window;
+ EMailReader *reader;
+ MessageList *message_list;
+ GtkTreeModel *tree_model;
+ CamelFolder *folder;
+ GtkTreeIter iter;
+ GPtrArray *uids;
+ gboolean valid;
+ guint ii;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ tree_model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ uids = message_list_get_selected (message_list);
+ folder = message_list->folder;
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ gchar *tag;
+
+ tag = e_mail_label_list_store_get_tag (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+
+ for (ii = 0; ii < uids->len; ii++) {
+ camel_folder_set_message_user_flag (
+ folder, uids->pdata[ii], tag, FALSE);
+ camel_folder_set_message_user_tag (
+ folder, uids->pdata[ii], "label", NULL);
+ }
+
+ g_free (tag);
+
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ }
+
+ message_list_free_uids (message_list, uids);
+}
+
+static void
+action_mail_preview_cb (GtkToggleAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ gboolean active;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ active = gtk_toggle_action_get_active (action);
+
+ e_mail_shell_content_set_preview_visible (mail_shell_content, active);
+}
+
+static void
+action_mail_show_hidden_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_hide_clear (message_list);
+}
+
+static void
+action_mail_smart_backward_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSettings *shell_settings;
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ EMFormatHTMLDisplay *html_display;
+ EMailReader *reader;
+ MessageList *message_list;
+ GtkToggleAction *toggle_action;
+ GtkHTML *html;
+ gboolean caret_mode;
+ gboolean magic_spacebar;
+
+ /* This implements the so-called "Magic Backspace". */
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ magic_spacebar = e_shell_settings_get_boolean (
+ shell_settings, "mail-magic-spacebar");
+
+ toggle_action = GTK_TOGGLE_ACTION (ACTION (MAIL_CARET_MODE));
+ caret_mode = gtk_toggle_action_get_active (toggle_action);
+
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ if (gtk_html_command (html, "scroll-backward"))
+ return;
+
+ if (caret_mode || !magic_spacebar)
+ return;
+
+ /* XXX Are two separate calls really necessary? */
+
+ if (message_list_select (
+ message_list, MESSAGE_LIST_SELECT_PREVIOUS,
+ 0, CAMEL_MESSAGE_SEEN))
+ return;
+
+ if (message_list_select (
+ message_list, MESSAGE_LIST_SELECT_PREVIOUS |
+ MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN))
+ return;
+
+ em_folder_tree_select_prev_path (folder_tree, TRUE);
+
+ gtk_widget_grab_focus (GTK_WIDGET (message_list));
+}
+
+static void
+action_mail_smart_forward_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellSettings *shell_settings;
+ EMailShellSidebar *mail_shell_sidebar;
+ EMFolderTree *folder_tree;
+ EMFormatHTMLDisplay *html_display;
+ EMailReader *reader;
+ MessageList *message_list;
+ GtkToggleAction *toggle_action;
+ GtkHTML *html;
+ gboolean caret_mode;
+ gboolean magic_spacebar;
+
+ /* This implements the so-called "Magic Spacebar". */
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ magic_spacebar = e_shell_settings_get_boolean (
+ shell_settings, "mail-magic-spacebar");
+
+ toggle_action = GTK_TOGGLE_ACTION (ACTION (MAIL_CARET_MODE));
+ caret_mode = gtk_toggle_action_get_active (toggle_action);
+
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ if (gtk_html_command (html, "scroll-forward"))
+ return;
+
+ if (caret_mode || !magic_spacebar)
+ return;
+
+ /* XXX Are two separate calls really necessary? */
+
+ if (message_list_select (
+ message_list, MESSAGE_LIST_SELECT_NEXT,
+ 0, CAMEL_MESSAGE_SEEN))
+ return;
+
+ if (message_list_select (
+ message_list, MESSAGE_LIST_SELECT_NEXT |
+ MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN))
+ return;
+
+ em_folder_tree_select_next_path (folder_tree, TRUE);
+
+ gtk_widget_grab_focus (GTK_WIDGET (message_list));
+}
+
+static void
+action_mail_stop_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ mail_cancel_all ();
+}
+
+static void
+action_mail_threads_collapse_all_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_set_threaded_collapse_all (message_list);
+}
+
+static void
+action_mail_threads_expand_all_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ MessageList *message_list;
+ EMailReader *reader;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_set_threaded_expand_all (message_list);
+}
+
+static void
+action_mail_threads_group_by_cb (GtkToggleAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ MessageList *message_list;
+ EMailReader *reader;
+ gboolean active;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ active = gtk_toggle_action_get_active (action);
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ message_list_set_threaded (message_list, active);
+}
+
+static void
+action_mail_tools_filters_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ em_utils_edit_filters (GTK_WIDGET (shell_window));
+}
+
+static void
+action_mail_tools_search_folders_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ vfolder_edit (E_SHELL_VIEW (mail_shell_view));
+}
+
+static void
+action_mail_tools_subscriptions_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkWidget *dialog;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ dialog = em_subscribe_editor_new ();
+ gtk_window_set_transient_for (
+ GTK_WINDOW (dialog), GTK_WINDOW (shell_window));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ /* XXX Dialog destroys itself. */
+}
+
+static void
+action_mail_view_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ gboolean vertical_view;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ vertical_view = (gtk_radio_action_get_current_value (action) == 1);
+
+ e_mail_shell_content_set_vertical_view (
+ mail_shell_content, vertical_view);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+ EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+
+ /* All shell views respond to the activation of this action,
+ * which is defined by EShellWindow. But only the currently
+ * active shell view proceeds with executing the search. */
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ e_mail_shell_view_execute_search (mail_shell_view);
+}
+
+static void
+action_search_filter_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailShellView *mail_shell_view)
+{
+ e_mail_shell_view_execute_search (mail_shell_view);
+}
+
+static void
+action_search_scope_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EMailShellView *mail_shell_view)
+{
+ e_mail_shell_view_execute_search (mail_shell_view);
+}
+
+static GtkActionEntry mail_entries[] = {
+
+ { "mail-account-disable",
+ NULL,
+ N_("_Disable Account"),
+ NULL,
+ N_("Disable this account"),
+ G_CALLBACK (action_mail_account_disable_cb) },
+
+ { "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-download",
+ NULL,
+ N_("_Download Messages for Offline Usage"),
+ NULL,
+ N_("Download messages of accounts and folders marked for offline"),
+ G_CALLBACK (action_mail_download_cb) },
+
+ { "mail-empty-trash",
+ NULL,
+ N_("Empty _Trash"),
+ NULL,
+ N_("Permanently remove all the deleted messages from all folders"),
+ G_CALLBACK (action_mail_empty_trash_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",
+ GTK_STOCK_DELETE,
+ NULL,
+ NULL,
+ N_("Permanently remove this folder"),
+ G_CALLBACK (action_mail_folder_delete_cb) },
+
+ { "mail-folder-expunge",
+ NULL,
+ N_("E_xpunge"),
+ "<Control>e",
+ N_("Permanently remove all deleted messages from this folder"),
+ G_CALLBACK (action_mail_folder_expunge_cb) },
+
+ { "mail-folder-mark-all-as-read",
+ "mail-read",
+ N_("Mar_k All Messages as Read"),
+ NULL,
+ 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",
+ N_("_New..."),
+ NULL,
+ N_("Create a new folder for storing mail"),
+ G_CALLBACK (action_mail_folder_new_cb) },
+
+ { "mail-folder-properties",
+ GTK_STOCK_PROPERTIES,
+ NULL,
+ NULL,
+ N_("Change the properties of this folder"),
+ G_CALLBACK (action_mail_folder_properties_cb) },
+
+ { "mail-folder-refresh",
+ GTK_STOCK_REFRESH,
+ NULL,
+ "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-all",
+ NULL,
+ N_("Select _All Messages"),
+ "<Control>a",
+ N_("Select all visible messages"),
+ G_CALLBACK (action_mail_folder_select_all_cb) },
+
+ { "mail-folder-select-thread",
+ NULL,
+ N_("Select Message _Thread"),
+ "<Control>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"),
+ "<Shift><Control>h",
+ N_("Select all replies to the currently selected message"),
+ G_CALLBACK (action_mail_folder_select_subthread_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,
+ N_("N_one"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ G_CALLBACK (action_mail_label_none_cb) },
+
+ { "mail-hide-read",
+ NULL,
+ N_("Hide _Read Messages"),
+ NULL,
+ N_("Temporarily hide all messages that have already been read"),
+ G_CALLBACK (action_mail_hide_read_cb) },
+
+ { "mail-hide-selected",
+ NULL,
+ N_("Hide S_elected Messages"),
+ NULL,
+ N_("Temporarily hide the selected messages"),
+ G_CALLBACK (action_mail_hide_selected_cb) },
+
+ { "mail-show-hidden",
+ NULL,
+ N_("Show Hidde_n Messages"),
+ NULL,
+ N_("Show messages that have been temporarily hidden"),
+ G_CALLBACK (action_mail_show_hidden_cb) },
+
+ { "mail-smart-backward",
+ NULL,
+ NULL, /* No menu item; key press only */
+ NULL,
+ NULL,
+ G_CALLBACK (action_mail_smart_backward_cb) },
+
+ { "mail-smart-forward",
+ NULL,
+ NULL, /* No menu item; key press only */
+ NULL,
+ NULL,
+ G_CALLBACK (action_mail_smart_forward_cb) },
+
+ { "mail-stop",
+ GTK_STOCK_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"),
+ "<Shift><Control>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-search-folders",
+ NULL,
+ N_("Search F_olders"),
+ NULL,
+ N_("Create or edit search folder definitions"),
+ G_CALLBACK (action_mail_tools_search_folders_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-label-menu",
+ NULL,
+ N_("_Label"),
+ NULL,
+ NULL,
+ NULL },
+
+ { "mail-preview-menu",
+ NULL,
+ N_("_Preview"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static EPopupActionEntry mail_popup_entries[] = {
+
+ { "mail-popup-account-disable",
+ NULL,
+ "mail-account-disable" },
+
+ { "mail-popup-empty-trash",
+ NULL,
+ "mail-empty-trash" },
+
+ { "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" }
+};
+
+static GtkToggleActionEntry mail_toggle_entries[] = {
+
+ { "mail-hide-deleted",
+ NULL,
+ N_("Hide _Deleted Messages"),
+ NULL,
+ N_("Hide deleted messages rather than displaying "
+ "them with a line through them"),
+ G_CALLBACK (action_mail_hide_deleted_cb),
+ TRUE },
+
+ { "mail-preview",
+ NULL,
+ N_("Show Message _Preview"),
+ "<Control>m",
+ N_("Show message preview pane"),
+ G_CALLBACK (action_mail_preview_cb),
+ TRUE },
+
+ { "mail-threads-group-by",
+ NULL,
+ N_("_Group By Threads"),
+ "<Control>t",
+ N_("Threaded message list"),
+ G_CALLBACK (action_mail_threads_group_by_cb),
+ FALSE }
+};
+
+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-internal",
+ 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-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-recent-messages",
+ NULL,
+ N_("Recent Messages"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_RECENT_MESSAGES },
+
+ { "mail-filter-unread-messages",
+ "mail-unread",
+ N_("Unread Messages"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_FILTER_UNREAD_MESSAGES }
+};
+
+static GtkRadioActionEntry mail_search_entries[] = {
+
+ { "mail-search-body-contains",
+ NULL,
+ N_("Body contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_BODY_CONTAINS },
+
+ { "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-recipients-contains",
+ NULL,
+ N_("Subject or Recipients contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS },
+
+ { "mail-search-subject-or-sender-contains",
+ NULL,
+ N_("Subject or Sender contains"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS }
+};
+
+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-message",
+ NULL,
+ N_("Current Message"),
+ NULL,
+ NULL, /* XXX Add a tooltip! */
+ MAIL_SCOPE_CURRENT_MESSAGE }
+};
+
+void
+e_mail_shell_view_actions_init (EMailShellView *mail_shell_view)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GConfBridge *bridge;
+ GObject *object;
+ GObject *src_object;
+ GObject *dst_object;
+ const gchar *key;
+
+ 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_content = e_shell_view_get_shell_content (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);
+ e_action_group_add_popup_actions (
+ action_group, mail_popup_entries,
+ G_N_ELEMENTS (mail_popup_entries));
+ 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),
+ MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS,
+ NULL, NULL);
+ gtk_action_group_add_radio_actions (
+ action_group, mail_scope_entries,
+ G_N_ELEMENTS (mail_scope_entries),
+ MAIL_SCOPE_CURRENT_FOLDER,
+ G_CALLBACK (action_search_scope_cb), mail_shell_view);
+
+ radio_action = GTK_RADIO_ACTION (ACTION (MAIL_SCOPE_ALL_ACCOUNTS));
+ e_shell_content_set_scope_action (shell_content, radio_action);
+ e_shell_content_set_scope_visible (shell_content, TRUE);
+
+ /* Bind GObject properties for GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ object = G_OBJECT (ACTION (MAIL_PREVIEW));
+ key = "/apps/evolution/mail/display/show_preview";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ object = G_OBJECT (ACTION (MAIL_THREADS_GROUP_BY));
+ key = "/apps/evolution/mail/display/thread_list";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ object = G_OBJECT (ACTION (MAIL_VIEW_VERTICAL));
+ key = "/apps/evolution/mail/display/layout";
+ gconf_bridge_bind_property (bridge, key, object, "current-value");
+
+ /* Fine tuning. */
+
+ src_object = G_OBJECT (ACTION (MAIL_THREADS_GROUP_BY));
+
+ dst_object = G_OBJECT (ACTION (MAIL_FOLDER_SELECT_THREAD));
+ e_binding_new (src_object, "active", dst_object, "sensitive");
+
+ dst_object = G_OBJECT (ACTION (MAIL_FOLDER_SELECT_SUBTHREAD));
+ e_binding_new (src_object, "active", dst_object, "sensitive");
+
+ dst_object = G_OBJECT (ACTION (MAIL_THREADS_COLLAPSE_ALL));
+ e_binding_new (src_object, "active", dst_object, "sensitive");
+
+ dst_object = G_OBJECT (ACTION (MAIL_THREADS_EXPAND_ALL));
+ e_binding_new (src_object, "active", dst_object, "sensitive");
+
+ /* XXX The boolean sense of the GConf key is the inverse of
+ * the menu item, so we have to maintain two properties. */
+ e_mutual_binding_new_with_negation (
+ G_OBJECT (shell_content), "show-deleted",
+ G_OBJECT (ACTION (MAIL_HIDE_DELETED)), "active");
+
+ g_signal_connect (
+ ACTION (GAL_SAVE_CUSTOM_VIEW), "activate",
+ G_CALLBACK (action_gal_save_custom_view_cb), mail_shell_view);
+
+ g_signal_connect (
+ ACTION (SEARCH_EXECUTE), "activate",
+ G_CALLBACK (action_search_execute_cb), mail_shell_view);
+}
+
+/* Helper for e_mail_shell_view_update_popup_labels() */
+static void
+mail_shell_view_update_label_action (GtkToggleAction *action,
+ MessageList *message_list,
+ GPtrArray *uids,
+ const gchar *label_tag)
+{
+ CamelFolder *folder;
+ gboolean exists = FALSE;
+ gboolean not_exists = FALSE;
+ gboolean sensitive;
+ guint ii;
+
+ folder = message_list->folder;
+
+ /* Figure out the proper label action state for the selected
+ * messages. If all the selected messages have the given label,
+ * make the toggle action active. If all the selected message
+ * DO NOT have the given label, make the toggle action inactive.
+ * If some do and some don't, make the action insensitive. */
+
+ for (ii = 0; ii < uids->len && (!exists || !not_exists); ii++) {
+ const gchar *old_label;
+ gchar *new_label;
+
+ /* Check for new-style labels. */
+ if (camel_folder_get_message_user_flag (
+ folder, uids->pdata[ii], label_tag)) {
+ exists = TRUE;
+ continue;
+ }
+
+ /* Check for old-style labels. */
+ old_label = camel_folder_get_message_user_tag (
+ folder, uids->pdata[ii], "label");
+ if (old_label == NULL) {
+ not_exists = TRUE;
+ continue;
+ }
+
+ /* Convert old-style labels ("<name>") to "$Label<name>". */
+ new_label = g_alloca (strlen (old_label) + 10);
+ g_stpcpy (g_stpcpy (new_label, "$Label"), old_label);
+
+ if (strcmp (new_label, label_tag) == 0)
+ exists = TRUE;
+ else
+ not_exists = TRUE;
+ }
+
+ sensitive = !(exists && not_exists);
+ gtk_toggle_action_set_active (action, exists);
+ gtk_action_set_sensitive (GTK_ACTION (action), sensitive);
+}
+
+void
+e_mail_shell_view_update_popup_labels (EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellSettings *shell_settings;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ EMailReader *reader;
+ MessageList *message_list;
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ GPtrArray *uids;
+ const gchar *path;
+ gboolean valid;
+ guint merge_id;
+ gint ii = 0;
+
+ 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);
+ ui_manager = e_shell_window_get_ui_manager (shell_window);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ tree_model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ action_group = ACTION_GROUP (MAIL_LABEL);
+ merge_id = mail_shell_view->priv->label_merge_id;
+ path = "/mail-message-popup/mail-label-menu/mail-label-actions";
+
+ /* Unmerge the previous menu items. */
+ gtk_ui_manager_remove_ui (ui_manager, merge_id);
+ e_action_group_remove_all_actions (action_group);
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ uids = message_list_get_selected (message_list);
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ GtkToggleAction *toggle_action;
+ GtkAction *action;
+ gchar *action_name;
+ gchar *stock_id;
+ gchar *label;
+ gchar *tag;
+
+ label = e_mail_label_list_store_get_name (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+ stock_id = e_mail_label_list_store_get_stock_id (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+ tag = e_mail_label_list_store_get_tag (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+ action_name = g_strdup_printf ("mail-label-%d", ii);
+
+ /* XXX Add a tooltip! */
+ toggle_action = gtk_toggle_action_new (
+ action_name, label, NULL, stock_id);
+
+ g_object_set_data_full (
+ G_OBJECT (toggle_action), "tag",
+ tag, (GDestroyNotify) g_free);
+
+ /* Configure the action before we connect to signals. */
+ mail_shell_view_update_label_action (
+ toggle_action, message_list, uids, tag);
+
+ g_signal_connect (
+ toggle_action, "toggled",
+ G_CALLBACK (action_mail_label_cb), mail_shell_view);
+
+ /* The action group takes ownership of the action. */
+ action = GTK_ACTION (toggle_action);
+ gtk_action_group_add_action (action_group, action);
+ g_object_unref (toggle_action);
+
+ gtk_ui_manager_add_ui (
+ ui_manager, merge_id, path, action_name,
+ action_name, GTK_UI_MANAGER_AUTO, FALSE);
+
+ g_free (label);
+ g_free (stock_id);
+ g_free (action_name);
+
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ ii++;
+ }
+
+ message_list_free_uids (message_list, uids);
+
+ g_object_unref (tree_model);
+}
+
+void
+e_mail_shell_view_update_search_filter (EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellContent *shell_content;
+ EShellSettings *shell_settings;
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkActionGroup *action_group;
+ GtkRadioAction *radio_action;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ GList *list;
+ GSList *group;
+ gboolean valid;
+ gint ii = 0;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ tree_model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ action_group = ACTION_GROUP (MAIL_FILTER);
+ e_action_group_remove_all_actions (action_group);
+
+ /* Add the standard filter actions. */
+ gtk_action_group_add_radio_actions (
+ action_group, mail_filter_entries,
+ G_N_ELEMENTS (mail_filter_entries),
+ MAIL_FILTER_ALL_MESSAGES,
+ G_CALLBACK (action_search_filter_cb),
+ mail_shell_view);
+
+ /* 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);
+
+ valid = gtk_tree_model_get_iter_first (tree_model, &iter);
+
+ while (valid) {
+ GtkAction *action;
+ gchar *action_name;
+ gchar *stock_id;
+ gchar *label;
+
+ label = e_mail_label_list_store_get_name (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &iter);
+ stock_id = e_mail_label_list_store_get_stock_id (
+ E_MAIL_LABEL_LIST_STORE (tree_model), &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);
+
+ gtk_radio_action_set_group (radio_action, group);
+ group = gtk_radio_action_get_group (radio_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_free (label);
+ g_free (stock_id);
+
+ valid = gtk_tree_model_iter_next (tree_model, &iter);
+ ii++;
+ }
+
+ /* Use any action in the group; doesn't matter which. */
+ e_shell_content_set_filter_action (shell_content, radio_action);
+
+ ii = MAIL_FILTER_UNREAD_MESSAGES;
+ e_shell_content_add_filter_separator_after (shell_content, ii);
+
+ ii = MAIL_FILTER_READ_MESSAGES;
+ e_shell_content_add_filter_separator_before (shell_content, ii);
+
+ g_object_unref (tree_model);
+}
diff --cc mail/e-mail-shell-view-actions.h
index bf7410d,0000000..2a05582
mode 100644,000000..100644
--- a/mail/e-mail-shell-view-actions.h
+++ b/mail/e-mail-shell-view-actions.h
@@@ -1,257 -1,0 +1,257 @@@
+/*
+ * e-mail-shell-view-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_VIEW_ACTIONS_H
+#define E_MAIL_SHELL_VIEW_ACTIONS_H
+
+#include <shell/e-shell-window-actions.h>
+
+/* 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_ADD_SENDER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-add-sender")
+#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_EMPTY_TRASH(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-empty-trash")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_MAILING_LIST(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-mailing-list")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_RECIPIENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-recipients")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_SENDER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-sender")
+#define E_SHELL_WINDOW_ACTION_MAIL_FILTER_ON_SUBJECT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-on-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_EXPUNGE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-expunge")
+#define E_SHELL_WINDOW_ACTION_MAIL_FOLDER_MARK_ALL_READ(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-folder-mark-all-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_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_HIDE_DELETED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-hide-deleted")
+#define E_SHELL_WINDOW_ACTION_MAIL_HIDE_READ(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-hide-read")
+#define E_SHELL_WINDOW_ACTION_MAIL_HIDE_SELECTED(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-hide-selected")
+#define E_SHELL_WINDOW_ACTION_MAIL_LABEL_NEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-label-new")
+#define E_SHELL_WINDOW_ACTION_MAIL_LABEL_NONE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-label-none")
+#define E_SHELL_WINDOW_ACTION_MAIL_LOAD_IMAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-load-images")
+#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_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_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_SELECT_ALL(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-select-all")
+#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_HIDDEN(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-show-hidden")
+#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_UNDELETE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-undelete")
+#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")
+
+/* 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_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_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_RECENT_MESSAGES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-filter-recent-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_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_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_RECIPIENTS_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-or-recipients-contains")
+#define E_SHELL_WINDOW_ACTION_MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "mail-search-subject-or-sender-contains")
+
+/* 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_MAIL_LABEL(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "mail-label")
+
+#endif /* E_MAIL_SHELL_VIEW_ACTIONS_H */
diff --cc mail/e-mail-shell-view-private.c
index 552ff1a,0000000..9026c8e
mode 100644,000000..100644
--- a/mail/e-mail-shell-view-private.c
+++ b/mail/e-mail-shell-view-private.c
@@@ -1,898 -1,0 +1,898 @@@
+/*
+ * e-mail-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-view-private.h"
+
+#include "widgets/menus/gal-view-factory-etable.h"
+
+static void
+mail_shell_view_folder_tree_selected_cb (EMailShellView *mail_shell_view,
+ const gchar *full_name,
+ const gchar *uri,
+ guint32 flags,
+ EMFolderTree *folder_tree)
+{
+ EMailReader *reader;
+ gboolean folder_selected;
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+
+ folder_selected =
+ !(flags & CAMEL_FOLDER_NOSELECT) &&
+ full_name != NULL;
+
+ if (folder_selected) {
+ EMFolderTreeModel *model;
+
+ model = em_folder_tree_get_model (folder_tree);
+ em_folder_tree_model_set_selected (model, uri);
+ em_folder_tree_model_save_state (model);
+
+ e_mail_reader_set_folder_uri (reader, uri);
+ } else
+ e_mail_reader_set_folder (reader, NULL, NULL);
+
+ e_shell_view_update_actions (E_SHELL_VIEW (mail_shell_view));
+}
+
+static void
+mail_shell_view_folder_tree_popup_event_cb (EShellView *shell_view,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/mail-folder-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+}
+
+static gboolean
+mail_shell_view_key_press_event_cb (EMailShellView *mail_shell_view,
+ GdkEventKey *event)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkAction *action;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if ((event->state & GDK_CONTROL_MASK) != 0)
+ return FALSE;
+
+ switch (event->keyval) {
+ case GDK_space:
+ action = ACTION (MAIL_SMART_FORWARD);
+ break;
+
+ case GDK_BackSpace:
+ action = ACTION (MAIL_SMART_BACKWARD);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ gtk_action_activate (action);
+
+ return TRUE;
+}
+
+static gint
+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_right_click_cb (EShellView *shell_view,
+ gint row,
+ ETreePath path,
+ gint col,
+ GdkEventButton *event)
+{
+ const gchar *widget_path;
+
+ widget_path = "/mail-message-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+
+ return TRUE;
+}
+
+static void
+mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ e_mail_shell_content_update_view_instance (mail_shell_content);
+ e_mail_shell_view_update_sidebar (mail_shell_view);
+}
+
+static void
+mail_shell_view_reader_status_message_cb (EMailShellView *mail_shell_view,
+ const gchar *status_message)
+{
+ EShellView *shell_view;
+ EShellTaskbar *shell_taskbar;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_taskbar = e_shell_view_get_shell_taskbar (shell_view);
+
+ e_shell_taskbar_set_message (shell_taskbar, status_message);
+}
+
+static void
+mail_shell_view_load_view_collection (EShellViewClass *shell_view_class)
+{
+ GalViewCollection *collection;
+ GalViewFactory *factory;
+ ETableSpecification *spec;
+ const gchar *base_dir;
+ gchar *filename;
+
+ collection = shell_view_class->view_collection;
+
+ base_dir = EVOLUTION_ETSPECDIR;
+ spec = e_table_specification_new ();
+ filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
+ if (!e_table_specification_load_from_file (spec, filename))
+ g_critical ("Unable to load ETable specification file "
+ "for mail");
+ g_free (filename);
+
+ factory = gal_view_factory_etable_new (spec);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+ g_object_unref (spec);
+
+ gal_view_collection_load (collection);
+}
+
+static void
+mail_shell_view_notify_view_id_cb (EMailShellView *mail_shell_view)
+{
+ EMailShellContent *mail_shell_content;
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+ view_instance = NULL; /* FIXME */
+ view_id = e_shell_view_get_view_id (E_SHELL_VIEW (mail_shell_view));
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_mail_shell_view_private_init (EMailShellView *mail_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ if (!gal_view_collection_loaded (shell_view_class->view_collection))
+ mail_shell_view_load_view_collection (shell_view_class);
+
+ g_signal_connect (
+ mail_shell_view, "notify::view-id",
+ G_CALLBACK (mail_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
+{
+ EMailShellViewPrivate *priv = mail_shell_view->priv;
+ EMailShellSidebar *mail_shell_sidebar;
+ EShell *shell;
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellContent *shell_content;
+ EShellSettings *shell_settings;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EMFormatHTMLDisplay *html_display;
+ EMFolderTreeModel *folder_tree_model;
+ EMFolderTree *folder_tree;
+ RuleContext *context;
+ FilterRule *rule = NULL;
+ GtkTreeModel *tree_model;
+ GtkUIManager *ui_manager;
+ MessageList *message_list;
+ EMailReader *reader;
+ GtkHTML *html;
+ const gchar *source;
+ guint merge_id;
+ gchar *uri;
+ gint ii = 0;
+
+ shell_view = E_SHELL_VIEW (mail_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);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ ui_manager = e_shell_window_get_ui_manager (shell_window);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ tree_model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ e_shell_window_add_action_group (shell_window, "mail");
+ e_shell_window_add_action_group (shell_window, "mail-filter");
+ e_shell_window_add_action_group (shell_window, "mail-label");
+
+ merge_id = gtk_ui_manager_new_merge_id (ui_manager);
+ priv->label_merge_id = merge_id;
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->mail_shell_backend = g_object_ref (shell_backend);
+ priv->mail_shell_content = g_object_ref (shell_content);
+ priv->mail_shell_sidebar = g_object_ref (shell_sidebar);
+
+ reader = E_MAIL_READER (shell_content);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ mail_shell_sidebar = E_MAIL_SHELL_SIDEBAR (shell_sidebar);
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ html = EM_FORMAT_HTML (html_display)->html;
+
+ g_signal_connect_swapped (
+ folder_tree, "folder-selected",
+ G_CALLBACK (mail_shell_view_folder_tree_selected_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ folder_tree, "popup-event",
+ G_CALLBACK (mail_shell_view_folder_tree_popup_event_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ message_list->tree, "key-press",
+ G_CALLBACK (mail_shell_view_message_list_key_press_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ message_list->tree, "right-click",
+ G_CALLBACK (mail_shell_view_message_list_right_click_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ reader, "changed",
+ G_CALLBACK (mail_shell_view_reader_changed_cb),
+ mail_shell_view);
+
+ /* Use the same callback as "changed". */
+ g_signal_connect_swapped (
+ reader, "folder-loaded",
+ G_CALLBACK (mail_shell_view_reader_changed_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ tree_model, "row-changed",
+ G_CALLBACK (e_mail_shell_view_update_search_filter),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ tree_model, "row-deleted",
+ G_CALLBACK (e_mail_shell_view_update_search_filter),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ tree_model, "row-inserted",
+ G_CALLBACK (e_mail_shell_view_update_search_filter),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ html, "key-press-event",
+ G_CALLBACK (mail_shell_view_key_press_event_cb),
+ mail_shell_view);
+
+ g_signal_connect_swapped (
+ html, "status-message",
+ G_CALLBACK (mail_shell_view_reader_status_message_cb),
+ mail_shell_view);
+
+ e_mail_shell_view_actions_init (mail_shell_view);
+ e_mail_shell_view_update_search_filter (mail_shell_view);
+ e_mail_reader_init (reader);
+
+ /* Populate built-in rules for search entry popup menu.
+ * Keep the assertions, please. If the conditions aren't
+ * met we're going to crash anyway, just more mysteriously. */
+ context = e_shell_content_get_search_context (shell_content);
+ source = FILTER_SOURCE_DEMAND;
+ while ((rule = rule_context_next_rule (context, rule, source))) {
+ g_assert (ii < MAIL_NUM_SEARCH_RULES);
+ priv->search_rules[ii++] = g_object_ref (rule);
+ }
+ g_assert (ii == MAIL_NUM_SEARCH_RULES);
+
+ /* Restore the previously selected folder. */
+ folder_tree_model = em_folder_tree_get_model (folder_tree);
+ uri = em_folder_tree_model_get_selected (folder_tree_model);
+ if (uri != NULL) {
+ gboolean expanded;
+
+ expanded = em_folder_tree_model_get_expanded_uri (
+ folder_tree_model, uri);
+ em_folder_tree_set_selected (folder_tree, uri, FALSE);
+ e_mail_reader_set_folder_uri (reader, uri);
+
+ if (!expanded)
+ em_folder_tree_model_set_expanded_uri (
+ folder_tree_model, uri, expanded);
+
+ g_free (uri);
+ }
+}
+
+void
+e_mail_shell_view_private_dispose (EMailShellView *mail_shell_view)
+{
+ EMailShellViewPrivate *priv = mail_shell_view->priv;
+ gint ii;
+
+ DISPOSE (priv->mail_shell_backend);
+ DISPOSE (priv->mail_shell_content);
+ DISPOSE (priv->mail_shell_sidebar);
+
+ for (ii = 0; ii < MAIL_NUM_SEARCH_RULES; ii++)
+ DISPOSE (priv->search_rules[ii]);
+}
+
+void
+e_mail_shell_view_private_finalize (EMailShellView *mail_shell_view)
+{
+ /* XXX Nothing to do? */
+}
+
+void
+e_mail_shell_view_execute_search (EMailShellView *mail_shell_view)
+{
+ EShell *shell;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ EShellSettings *shell_settings;
+ EMFormatHTMLDisplay *html_display;
+ EMailShellContent *mail_shell_content;
+ MessageList *message_list;
+ FilterRule *rule;
+ EMailReader *reader;
+ CamelFolder *folder;
+ GtkAction *action;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter tree_iter;
+ GString *string;
+ GList *iter;
+ GSList *search_strings = NULL;
+ const gchar *folder_uri;
+ const gchar *text;
+ gboolean valid;
+ gchar *query;
+ gchar *temp;
+ gchar *tag;
+ gint value;
+
+ 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_content = e_shell_view_get_shell_content (shell_view);
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+
+ reader = E_MAIL_READER (shell_content);
+ html_display = e_mail_reader_get_html_display (reader);
+ message_list = e_mail_reader_get_message_list (reader);
+
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ /* This returns a new object reference. */
+ model = e_shell_settings_get_object (
+ shell_settings, "mail-label-list-store");
+
+ text = e_shell_content_get_search_text (shell_content);
+ if (text == NULL || *text == '\0') {
+ query = g_strdup ("");
+ goto filter;
+ }
+
+ /* Replace variables in the selected rule with the
+ * current search text and extract a query string. */
+
+ action = ACTION (MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS);
+ value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+ g_return_if_fail (value >= 0 && value < MAIL_NUM_SEARCH_RULES);
+ rule = mail_shell_view->priv->search_rules[value];
+
+ for (iter = rule->parts; iter != NULL; iter = iter->next) {
+ FilterPart *part = iter->data;
+ FilterElement *element = NULL;
+
+ if (strcmp (part->name, "subject") == 0)
+ element = filter_part_find_element (part, "subject");
+ else if (strcmp (part->name, "body") == 0)
+ element = filter_part_find_element (part, "word");
+ else if (strcmp (part->name, "sender") == 0)
+ element = filter_part_find_element (part, "sender");
+ else if (strcmp (part->name, "to") == 0)
+ element = filter_part_find_element (part, "recipient");
+
+ if (strcmp (part->name, "body") == 0) {
+ struct _camel_search_words *words;
+ gint ii;
+
+ words = camel_search_words_split ((guchar *) text);
+ for (ii = 0; ii < words->len; ii++)
+ search_strings = g_slist_prepend (
+ search_strings, g_strdup (
+ words->words[ii]->word));
+ camel_search_words_free (words);
+ }
+
+ if (element != NULL) {
+ FilterInput *input = FILTER_INPUT (element);
+ filter_input_set_value (input, text);
+ }
+ }
+
+ string = g_string_sized_new (1024);
+ filter_rule_build_code (rule, string);
+ query = g_string_free (string, FALSE);
+
+filter:
+
+ /* Apply selected filter. */
+
+ value = e_shell_content_get_filter_value (shell_content);
+ switch (value) {
+ case MAIL_FILTER_ALL_MESSAGES:
+ break;
+
+ case MAIL_FILTER_UNREAD_MESSAGES:
+ temp = g_strdup_printf (
+ "(and %s (match-all (not "
+ "(system-flag \"Seen\"))))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_NO_LABEL:
+ string = g_string_sized_new (1024);
+ g_string_append_printf (
+ string, "(and %s (and ", query);
+ valid = gtk_tree_model_get_iter_first (
+ model, &tree_iter);
+ while (valid) {
+ tag = e_mail_label_list_store_get_tag (
+ E_MAIL_LABEL_LIST_STORE (model),
+ &tree_iter);
+ g_string_append_printf (
+ string, " (match-all (not (or "
+ "(= (user-tag \"label\") \"%s\") "
+ "(user-flag \"$Label%s\") "
+ "(user-flag \"%s\"))))",
+ tag, tag, tag);
+ g_free (tag);
+
+ valid = gtk_tree_model_iter_next (
+ model, &tree_iter);
+ }
+ g_string_append_len (string, "))", 2);
+ g_free (query);
+ query = g_string_free (string, FALSE);
+ break;
+
+ case MAIL_FILTER_READ_MESSAGES:
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(system-flag \"Seen\")))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_RECENT_MESSAGES:
+ if (em_utils_folder_is_sent (folder, folder_uri))
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(> (get-sent-date) "
+ "(- (get-current-date) 86400))))",
+ query);
+ else
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(> (get-received-date) "
+ "(- (get_current_date) 86400))))",
+ query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_LAST_5_DAYS_MESSAGES:
+ if (em_utils_folder_is_sent (folder, folder_uri))
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(> (get-sent-date) "
+ "(- (get-current-date) 432000))))",
+ query);
+ else
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(> (get-received-date) "
+ "(- (get_current_date) 432000))))",
+ query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS:
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(system-flag \"Attachments\")))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_IMPORTANT_MESSAGES:
+ temp = g_strdup_printf (
+ "(and %s (match-all "
+ "(system-flag \"Flagged\")))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ case MAIL_FILTER_MESSAGES_NOT_JUNK:
+ temp = g_strdup_printf (
+ "(and %s (match-all (not "
+ "(system-flag \"junk\"))))", query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ /* The action value also serves as a path for
+ * 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 (model, &tree_iter, path);
+ gtk_tree_path_free (path);
+
+ tag = e_mail_label_list_store_get_tag (
+ E_MAIL_LABEL_LIST_STORE (model), &tree_iter);
+ temp = g_strdup_printf (
+ "(and %s (match-all (or "
+ "(= (user-tag \"label\") \"%s\") "
+ "(user-flag \"$Label%s\") "
+ "(user-flag \"%s\"))))",
+ query, tag, tag, tag);
+ g_free (tag);
+
+ g_free (query);
+ query = temp;
+ break;
+ }
+
+ message_list_set_search (message_list, query);
+
+ e_mail_shell_content_set_search_strings (
+ mail_shell_content, search_strings);
+
+ g_slist_foreach (search_strings, (GFunc) g_free, NULL);
+ g_slist_free (search_strings);
+
+ g_object_unref (model);
+ g_free (query);
+}
+
+/* Helper for e_mail_shell_view_create_filter_from_selected() */
+static void
+mail_shell_view_create_filter_cb (CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ gpointer user_data)
+{
+ struct {
+ const gchar *source;
+ gint type;
+ } *filter_data = user_data;
+
+ if (message != NULL)
+ filter_gui_add_from_message (
+ message, filter_data->source, filter_data->type);
+
+ g_free (filter_data);
+}
+
+void
+e_mail_shell_view_create_filter_from_selected (EMailShellView *mail_shell_view,
+ gint filter_type)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelFolder *folder;
+ const gchar *filter_source;
+ const gchar *folder_uri;
+ GPtrArray *uids;
+
+ struct {
+ const gchar *source;
+ gint type;
+ } *filter_data;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ if (em_utils_folder_is_sent (folder, folder_uri))
+ filter_source = FILTER_SOURCE_OUTGOING;
+ else if (em_utils_folder_is_outbox (folder, folder_uri))
+ filter_source = FILTER_SOURCE_OUTGOING;
+ else
+ filter_source = FILTER_SOURCE_INCOMING;
+
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len == 1) {
+ filter_data = g_malloc (sizeof (*filter_data));
+ filter_data->source = filter_source;
+ filter_data->type = filter_type;
+
+ mail_get_message (
+ folder, uids->pdata[0],
+ mail_shell_view_create_filter_cb,
+ filter_data, mail_msg_unordered_push);
+ }
+
+ em_utils_uids_free (uids);
+}
+
+/* Helper for e_mail_shell_view_create_vfolder_from_selected() */
+static void
+mail_shell_view_create_vfolder_cb (CamelFolder *folder,
+ const gchar *uid,
+ CamelMimeMessage *message,
+ gpointer user_data)
+{
+ struct {
+ gchar *uri;
+ gint type;
+ } *vfolder_data = user_data;
+
+ if (message != NULL)
+ vfolder_gui_add_from_message (
+ message, vfolder_data->type, vfolder_data->uri);
+
+ g_free (vfolder_data->uri);
+ g_free (vfolder_data);
+}
+
+void
+e_mail_shell_view_create_vfolder_from_selected (EMailShellView *mail_shell_view,
+ gint vfolder_type)
+{
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelFolder *folder;
+ const gchar *folder_uri;
+ GPtrArray *uids;
+
+ struct {
+ gchar *uri;
+ gint type;
+ } *vfolder_data;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ reader = E_MAIL_READER (mail_shell_view->priv->mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ uids = message_list_get_selected (message_list);
+
+ if (uids->len == 1) {
+ vfolder_data = g_malloc (sizeof (*vfolder_data));
+ vfolder_data->uri = g_strdup (folder_uri);
+ vfolder_data->type = vfolder_type;
+
+ mail_get_message (
+ folder, uids->pdata[0],
+ mail_shell_view_create_vfolder_cb,
+ vfolder_data, mail_msg_unordered_push);
+ }
+
+ em_utils_uids_free (uids);
+}
+
+void
+e_mail_shell_view_update_sidebar (EMailShellView *mail_shell_view)
+{
+ EMailShellBackend *mail_shell_backend;
+ EMailShellContent *mail_shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellView *shell_view;
+ EMailReader *reader;
+ MessageList *message_list;
+ CamelStore *local_store;
+ CamelFolder *folder;
+ GPtrArray *selected;
+ GString *buffer;
+ const gchar *display_name;
+ const gchar *folder_uri;
+ gchar *folder_name;
+ gchar *title;
+ guint32 num_deleted;
+ guint32 num_junked;
+ guint32 num_junked_not_deleted;
+ guint32 num_unread;
+ guint32 num_visible;
+
+ g_return_if_fail (E_IS_MAIL_SHELL_VIEW (mail_shell_view));
+
+ mail_shell_backend = mail_shell_view->priv->mail_shell_backend;
+ mail_shell_content = mail_shell_view->priv->mail_shell_content;
+
+ shell_view = E_SHELL_VIEW (mail_shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+
+ reader = E_MAIL_READER (mail_shell_content);
+ message_list = e_mail_reader_get_message_list (reader);
+ folder_uri = message_list->folder_uri;
+ folder = message_list->folder;
+
+ local_store = e_mail_shell_backend_get_local_store (mail_shell_backend);
+
+ /* If no folder is selected, reset the sidebar banners
+ * to their default values and stop. */
+ if (folder == NULL) {
+ GtkAction *action;
+ gchar *label;
+
+ action = e_shell_view_get_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);
+
+ return;
+ }
+
+ camel_object_get (
+ folder, NULL,
+ CAMEL_FOLDER_NAME, &folder_name,
+ CAMEL_FOLDER_DELETED, &num_deleted,
+ CAMEL_FOLDER_JUNKED, &num_junked,
+ CAMEL_FOLDER_JUNKED_NOT_DELETED, &num_junked_not_deleted,
+ CAMEL_FOLDER_UNREAD, &num_unread,
+ CAMEL_FOLDER_VISIBLE, &num_visible,
+ NULL);
+
+ buffer = g_string_sized_new (256);
+ selected = message_list_get_selected (message_list);
+
+ if (selected->len > 1)
+ g_string_append_printf (
+ buffer, ngettext ("%d selected, ", "%d selected, ",
+ selected->len), selected->len);
+
+ if (CAMEL_IS_VTRASH_FOLDER (folder)) {
+ CamelVTrashFolder *trash_folder;
+
+ trash_folder = (CamelVTrashFolder *) folder;
+
+ /* "Trash" folder */
+ if (trash_folder->type == CAMEL_VTRASH_FOLDER_TRASH)
+ g_string_append_printf (
+ buffer, ngettext ("%d deleted",
+ "%d deleted", num_deleted), num_deleted);
+
+ /* "Junk" folder (hide deleted messages) */
+ else if (e_mail_reader_get_hide_deleted (reader))
+ g_string_append_printf (
+ buffer, ngettext ("%d junk",
+ "%d junk", num_junked_not_deleted),
+ num_junked_not_deleted);
+
+ /* "Junk" folder (show deleted messages) */
+ else
+ g_string_append_printf (
+ buffer, ngettext ("%d junk", "%d junk",
+ num_junked), num_junked);
+
+ /* "Drafts" folder */
+ } else if (em_utils_folder_is_drafts (folder, folder_uri)) {
+ g_string_append_printf (
+ buffer, ngettext ("%d draft", "%d drafts",
+ num_visible), num_visible);
+
+ /* "Outbox" folder */
+ } else if (em_utils_folder_is_outbox (folder, folder_uri)) {
+ g_string_append_printf (
+ buffer, ngettext ("%d unsent", "%d unsent",
+ num_visible), num_visible);
+
+ /* "Sent" folder */
+ } else if (em_utils_folder_is_sent (folder, folder_uri)) {
+ g_string_append_printf (
+ buffer, ngettext ("%d sent", "%d sent",
+ num_visible), num_visible);
+
+ /* Normal folder */
+ } else {
+ if (!e_mail_reader_get_hide_deleted (reader))
+ num_visible +=
+ num_deleted - num_junked +
+ num_junked_not_deleted;
+
+ if (num_unread > 0 && selected->len <= 1)
+ g_string_append_printf (
+ buffer, ngettext ("%d unread, ",
+ "%d unread, ", num_unread), num_unread);
+ g_string_append_printf (
+ buffer, ngettext ("%d total", "%d total",
+ num_visible), num_visible);
+ }
+
+ message_list_free_uids (message_list, selected);
+
+ /* Choose a suitable folder name for displaying. */
+ if (folder->parent_store == local_store && (
+ strcmp (folder_name, "Drafts") == 0 ||
+ strcmp (folder_name, "Inbox") == 0 ||
+ strcmp (folder_name, "Outbox") == 0 ||
+ strcmp (folder_name, "Sent") == 0 ||
+ strcmp (folder_name, "Templates") == 0))
+ display_name = _(folder_name);
+ else if (strcmp (folder_name, "INBOX") == 0)
+ display_name = _("Inbox");
+ else
+ display_name = folder_name;
+
+ title = g_strdup_printf ("%s (%s)", display_name, buffer->str);
+ e_shell_sidebar_set_secondary_text (shell_sidebar, buffer->str);
+ e_shell_view_set_title (shell_view, title);
+ g_free (title);
+
+ camel_object_free (folder, CAMEL_FOLDER_NAME, folder_name);
+ g_string_free (buffer, TRUE);
+}
diff --cc mail/e-mail-shell-view-private.h
index 1d61f8d,0000000..4b27c4c
mode 100644,000000..100644
--- a/mail/e-mail-shell-view-private.h
+++ b/mail/e-mail-shell-view-private.h
@@@ -1,170 -1,0 +1,170 @@@
+/*
+ * e-mail-shell-view-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_VIEW_PRIVATE_H
+#define E_MAIL_SHELL_VIEW_PRIVATE_H
+
+#include "e-mail-shell-view.h"
+
+#include <glib/gi18n.h>
+#include <gtkhtml/gtkhtml.h>
+#include <camel/camel-disco-store.h>
+#include <camel/camel-offline-store.h>
+#include <camel/camel-vtrash-folder.h>
+#include <camel/camel-search-private.h> /* for camel_search_word */
+
+#include "e-util/e-util.h"
+#include "e-util/e-binding.h"
+#include "e-util/gconf-bridge.h"
+#include "e-util/e-account-utils.h"
+#include "filter/filter-part.h"
+#include "widgets/misc/e-popup-action.h"
+#include "widgets/menus/gal-view-instance.h"
+
+#include "e-mail-label-dialog.h"
+#include "e-mail-label-list-store.h"
+#include "e-mail-reader.h"
+#include "em-composer-utils.h"
+#include "em-folder-properties.h"
+#include "em-folder-selector.h"
+#include "em-folder-utils.h"
+#include "em-subscribe-editor.h"
+#include "em-utils.h"
+#include "mail-autofilter.h"
+#include "mail-config.h"
+#include "mail-ops.h"
+#include "mail-send-recv.h"
+#include "mail-vfolder.h"
+
+#include "e-mail-shell-backend.h"
+#include "e-mail-shell-content.h"
+#include "e-mail-shell-sidebar.h"
+#include "e-mail-shell-view-actions.h"
+
+#define E_MAIL_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* For use in dispose() methods. */
+#define DISPOSE(obj) \
+ G_STMT_START { \
+ if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
+ } G_STMT_END
+
+/* ETable Specifications */
+#define ETSPEC_FILENAME "message-list.etspec"
+
+G_BEGIN_DECLS
+
+/* Filter items are displayed in ascending order.
+ * Labels are numbered from zero, so subsequent items must have
+ * sufficiently large values. Unfortunately this introduces an
+ * arbitrary upper bound on labels. */
+enum {
+ MAIL_FILTER_ALL_MESSAGES = -3,
+ MAIL_FILTER_UNREAD_MESSAGES = -2,
+ MAIL_FILTER_NO_LABEL = -1,
+ /* Labels go here */
+ MAIL_FILTER_READ_MESSAGES = 5000,
+ MAIL_FILTER_RECENT_MESSAGES = 5001,
+ MAIL_FILTER_LAST_5_DAYS_MESSAGES = 5002,
+ MAIL_FILTER_MESSAGES_WITH_ATTACHMENTS = 5003,
+ MAIL_FILTER_IMPORTANT_MESSAGES = 5004,
+ MAIL_FILTER_MESSAGES_NOT_JUNK = 5005
+};
+
+/* Search items are displayed in ascending order. */
+enum {
+ MAIL_SEARCH_SUBJECT_OR_SENDER_CONTAINS,
+ MAIL_SEARCH_SUBJECT_OR_RECIPIENTS_CONTAINS,
+ MAIL_SEARCH_RECIPIENTS_CONTAIN,
+ MAIL_SEARCH_MESSAGE_CONTAINS,
+ MAIL_SEARCH_SUBJECT_CONTAINS,
+ MAIL_SEARCH_SENDER_CONTAINS,
+ MAIL_SEARCH_BODY_CONTAINS,
+ MAIL_NUM_SEARCH_RULES
+};
+
+/* Scope items are displayed in ascending order. */
+enum {
+ MAIL_SCOPE_CURRENT_FOLDER,
+ MAIL_SCOPE_CURRENT_ACCOUNT,
+ MAIL_SCOPE_ALL_ACCOUNTS,
+ MAIL_SCOPE_CURRENT_MESSAGE
+};
+
+struct _EMailShellViewPrivate {
+
+ /*** Other Stuff ***/
+
+ /* These are just for convenience. */
+ EMailShellBackend *mail_shell_backend;
+ EMailShellContent *mail_shell_content;
+ EMailShellSidebar *mail_shell_sidebar;
+
+ /* For UI merging and unmerging. */
+ guint merge_id;
+ guint label_merge_id;
+
+ /* Filter rules correspond to the search entry menu. */
+ FilterRule *search_rules[MAIL_NUM_SEARCH_RULES];
+
+ guint show_deleted : 1;
+};
+
+void e_mail_shell_view_private_init
+ (EMailShellView *mail_shell_view,
+ EShellViewClass *shell_view_class);
+void e_mail_shell_view_private_constructed
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_private_dispose
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_private_finalize
+ (EMailShellView *mail_shell_view);
+
+/* Private Utilities */
+
+void e_mail_shell_view_actions_init
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_execute_search
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_create_filter_from_selected
+ (EMailShellView *mail_shell_view,
+ gint filter_type);
+void e_mail_shell_view_create_vfolder_from_selected
+ (EMailShellView *mail_shell_view,
+ gint vfolder_type);
+void e_mail_shell_view_update_popup_labels
+ (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);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_VIEW_PRIVATE_H */
diff --cc mail/e-mail-shell-view.c
index f58d1f6,0000000..8d8b4aa
mode 100644,000000..100644
--- a/mail/e-mail-shell-view.c
+++ b/mail/e-mail-shell-view.c
@@@ -1,260 -1,0 +1,260 @@@
+/*
+ * e-mail-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-view-private.h"
+
+static gpointer parent_class;
+static GType mail_shell_view_type;
+
+static void
+mail_shell_view_dispose (GObject *object)
+{
+ e_mail_shell_view_private_dispose (E_MAIL_SHELL_VIEW (object));
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_shell_view_finalize (GObject *object)
+{
+ e_mail_shell_view_private_finalize (E_MAIL_SHELL_VIEW (object));
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_shell_view_constructed (GObject *object)
+{
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ e_mail_shell_view_private_constructed (E_MAIL_SHELL_VIEW (object));
+}
+
+static void
+mail_shell_view_toggled (EShellView *shell_view)
+{
+ EMailShellViewPrivate *priv;
+ EShellWindow *shell_window;
+ GtkUIManager *ui_manager;
+ const gchar *basename;
+ gboolean view_is_active;
+
+ /* Chain up to parent's toggled() method. */
+ E_SHELL_VIEW_CLASS (parent_class)->toggled (shell_view);
+
+ priv = E_MAIL_SHELL_VIEW_GET_PRIVATE (shell_view);
+
+ 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 = E_MAIL_READER_UI_DEFINITION;
+
+ if (view_is_active && priv->merge_id == 0) {
+ priv->merge_id = e_load_ui_definition (ui_manager, basename);
+ e_mail_reader_create_charset_menu (
+ E_MAIL_READER (priv->mail_shell_content),
+ ui_manager, priv->merge_id);
+ } else if (!view_is_active && priv->merge_id != 0) {
+ gtk_ui_manager_remove_ui (ui_manager, priv->merge_id);
+ priv->merge_id = 0;
+ }
+
+ gtk_ui_manager_ensure_update (ui_manager);
+}
+
+static void
+mail_shell_view_update_actions (EShellView *shell_view)
+{
+ EMailShellView *mail_shell_view;
+ EMailShellSidebar *mail_shell_sidebar;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellWindow *shell_window;
+ EMFolderTree *folder_tree;
+ EAccount *account = NULL;
+ GtkAction *action;
+ const gchar *label;
+ gchar *uri;
+ gboolean sensitive;
+ guint32 state;
+
+ /* Be descriptive. */
+ gboolean account_is_groupwise;
+ gboolean folder_allows_children;
+ gboolean folder_can_be_deleted;
+ gboolean folder_is_junk;
+ gboolean folder_is_outbox;
+ gboolean folder_is_store;
+ gboolean folder_is_trash;
+
+ mail_shell_view = E_MAIL_SHELL_VIEW (shell_view);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ e_mail_reader_update_actions (E_MAIL_READER (shell_content));
+
+ mail_shell_sidebar = mail_shell_view->priv->mail_shell_sidebar;
+ folder_tree = e_mail_shell_sidebar_get_folder_tree (mail_shell_sidebar);
+
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ state = e_shell_sidebar_check_state (shell_sidebar);
+
+ folder_allows_children =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_ALLOWS_CHILDREN);
+ folder_can_be_deleted =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_CAN_DELETE);
+ folder_is_junk =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_JUNK);
+ folder_is_outbox =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_OUTBOX);
+ folder_is_store =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_STORE);
+ folder_is_trash =
+ (state & E_MAIL_SHELL_SIDEBAR_FOLDER_IS_TRASH);
+
+ uri = em_folder_tree_get_selected_uri (folder_tree);
+ if (uri != NULL) {
+ account = mail_config_get_account_by_source_url (uri);
+
+ /* FIXME This belongs in a GroupWise plugin. */
+ account_is_groupwise =
+ (g_strrstr (uri, "groupwise://") != NULL) &&
+ account != NULL && account->parent_uid != NULL;
+
+ g_free (uri);
+ }
+
+ action = ACTION (MAIL_ACCOUNT_DISABLE);
+ sensitive = (account != NULL) && folder_is_store;
+ if (account_is_groupwise)
+ label = _("Proxy _Logout");
+ else
+ label = _("_Disable Account");
+ gtk_action_set_sensitive (action, sensitive);
+ g_object_set (action, "label", label, NULL);
+
+ action = ACTION (MAIL_EMPTY_TRASH);
+ sensitive = folder_is_trash;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FLUSH_OUTBOX);
+ sensitive = folder_is_outbox;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_COPY);
+ sensitive = !folder_is_store;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_DELETE);
+ sensitive = !folder_is_store && folder_can_be_deleted;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_MOVE);
+ sensitive = !folder_is_store && folder_can_be_deleted;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_NEW);
+ sensitive = folder_allows_children;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_PROPERTIES);
+ sensitive = !folder_is_store;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_REFRESH);
+ sensitive = !folder_is_store;
+ gtk_action_set_sensitive (action, sensitive);
+
+ action = ACTION (MAIL_FOLDER_RENAME);
+ sensitive = !folder_is_store && folder_can_be_deleted;
+ gtk_action_set_sensitive (action, sensitive);
+
+ e_mail_shell_view_update_popup_labels (mail_shell_view);
+}
+
+static void
+mail_shell_view_class_init (EMailShellViewClass *class,
+ GTypeModule *type_module)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMailShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = mail_shell_view_dispose;
+ object_class->finalize = mail_shell_view_finalize;
+ object_class->constructed = mail_shell_view_constructed;
+
+ 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_manager_id = "org.gnome.evolution.mail";
+ 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_sidebar = e_mail_shell_sidebar_new;
+ shell_view_class->toggled = mail_shell_view_toggled;
+ shell_view_class->update_actions = mail_shell_view_update_actions;
+}
+
+static void
+mail_shell_view_init (EMailShellView *mail_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ mail_shell_view->priv =
+ E_MAIL_SHELL_VIEW_GET_PRIVATE (mail_shell_view);
+
+ e_mail_shell_view_private_init (mail_shell_view, shell_view_class);
+}
+
+GType
+e_mail_shell_view_get_type (void)
+{
+ return mail_shell_view_type;
+}
+
+void
+e_mail_shell_view_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (EMailShellViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) mail_shell_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMailShellView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) mail_shell_view_init,
+ NULL /* value_table */
+ };
+
+ mail_shell_view_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_VIEW,
+ "EMailShellView", &type_info, 0);
+}
diff --cc mail/e-mail-shell-view.h
index 2bc7695,0000000..d20bde7
mode 100644,000000..100644
--- a/mail/e-mail-shell-view.h
+++ b/mail/e-mail-shell-view.h
@@@ -1,72 -1,0 +1,72 @@@
+/*
+ * e-mail-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_MAIL_SHELL_VIEW_H
+#define E_MAIL_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_SHELL_VIEW \
+ (e_mail_shell_view_get_type ())
+#define E_MAIL_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellView))
+#define E_MAIL_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewClass))
+#define E_IS_MAIL_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MAIL_SHELL_VIEW))
+#define E_IS_MAIL_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MAIL_SHELL_VIEW))
+#define E_MAIL_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MAIL_SHELL_VIEW, EMailShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailShellView EMailShellView;
+typedef struct _EMailShellViewClass EMailShellViewClass;
+typedef struct _EMailShellViewPrivate EMailShellViewPrivate;
+
+struct _EMailShellView {
+ EShellView parent;
+ EMailShellViewPrivate *priv;
+};
+
+struct _EMailShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_mail_shell_view_get_type (void);
+void e_mail_shell_view_register_type
+ (GTypeModule *type_module);
+gboolean e_mail_shell_view_get_show_deleted
+ (EMailShellView *mail_shell_view);
+void e_mail_shell_view_set_show_deleted
+ (EMailShellView *mail_shell_view,
+ gboolean show_deleted);
+
+G_END_DECLS
+
+#endif /* E_MAIL_SHELL_VIEW_H */
diff --cc mail/e-searching-tokenizer.c
index 129aa05,724cc3b..726ae41
--- a/mail/e-searching-tokenizer.c
+++ b/mail/e-searching-tokenizer.c
@@@ -874,10 -935,10 +875,10 @@@ search_info_clone (struct _search_info
}
static struct _searcher *
-search_info_to_searcher(struct _search_info *si)
+search_info_to_searcher (struct _search_info *si)
{
char *tags, *tage;
- char *col;
+ const gchar *col;
if (si->strv->len == 0)
return NULL;
diff --cc mail/em-account-editor.c
index a9ba161,2b13e7e..e5f0f98
--- a/mail/em-account-editor.c
+++ b/mail/em-account-editor.c
@@@ -1422,7 -1402,8 +1422,8 @@@ emae_refresh_providers(EMAccountEditor
int active = 0, i;
struct _service_info *info = &emae_service_info[service->type];
const char *uri = e_account_get_string(account, info->account_uri_key);
- char *current = NULL, *tmp;
- const char *tmp;
+ char *current = NULL;
++ const gchar *tmp;
CamelURL *url;
dropdown = service->providers;
@@@ -2850,8 -2831,8 +2851,7 @@@ emae_check_complete(EConfig *ec, const
} else {
g_warning("buz2\n");
}
-
-
+
-
} else if (!strcmp(pageid, "20.receive_options")) {
if (emae->priv->source.provider
&& emae->priv->extra_provider != emae->priv->source.provider) {
@@@ -2918,10 -2902,11 +2921,11 @@@
if (ok && (pageid == NULL || !strcmp(pageid, "40.management"))) {
ok = (tmp = e_account_get_string(emae->account, E_ACCOUNT_NAME))
&& tmp[0]
- && ((ea = mail_config_get_account_by_name(tmp)) == NULL
+ && ((ea = e_get_account_by_name (tmp)) == NULL
|| ea == emae->original);
- if (!ok)
+ if (!ok) {
d(printf("management page incomplete\n"));
+ }
}
return ok;
diff --cc mail/em-account-prefs.c
index 75ff66d,d2303aa..82342de
--- a/mail/em-account-prefs.c
+++ b/mail/em-account-prefs.c
@@@ -12,9 -10,12 +12,9 @@@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Jeffrey Stedfast <fejj ximian com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
diff --cc mail/em-account-prefs.h
index 4c02d71,0dabc8a..82df8fa
--- a/mail/em-account-prefs.h
+++ b/mail/em-account-prefs.h
@@@ -12,9 -11,12 +12,9 @@@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Jeffrey Stedfast <fejj ximian com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
diff --cc mail/em-composer-utils.c
index f6ea663,4ed3e70..fdff698
--- a/mail/em-composer-utils.c
+++ b/mail/em-composer-utils.c
@@@ -904,15 -896,13 +904,15 @@@ edit_message (CamelMimeMessage *message
camel_object_unref (body);
}
}
-
+
composer = e_msg_composer_new_with_message (message);
-
+
- if (em_utils_folder_is_templates(drafts, NULL) == TRUE)
- em_composer_utils_setup_callbacks (composer, NULL, NULL, 0, 0, NULL, NULL);
- else
- em_composer_utils_setup_callbacks (composer, NULL, NULL, 0, 0, drafts, uid);
+ if (em_utils_folder_is_drafts (drafts, NULL)) {
+ struct emcs_t *emcs;
+
+ emcs = g_object_get_data (G_OBJECT (composer), "emcs");
+ emcs_set_drafts_info (emcs, drafts, uid);
+ }
composer_set_no_change (composer, TRUE, FALSE);
diff --cc mail/em-composer-utils.h
index 37fd185,60944cb..8ee05a5
--- a/mail/em-composer-utils.h
+++ b/mail/em-composer-utils.h
@@@ -41,8 -41,16 +41,8 @@@ struct _EMFormat
struct _EAccount;
struct _EDestination;
-void em_composer_utils_setup_callbacks (struct _EMsgComposer *composer, struct _CamelFolder *folder, const char *uid,
- guint32 flags, guint32 set, struct _CamelFolder *drafts, const char *drafts_uid);
-
-#define em_composer_utils_setup_default_callbacks(composer) em_composer_utils_setup_callbacks (composer, NULL, NULL, 0, 0, NULL, NULL)
-
-void em_utils_composer_send_cb(struct _EMsgComposer *composer, gpointer user_data);
-void em_utils_composer_save_draft_cb(struct _EMsgComposer *composer, gpointer user_data);
-
void em_utils_compose_new_message (const char *fromuri);
- struct _EMsgComposer * em_utils_compose_lite_new_message (const char *fromuri);
+ struct _EMsgComposer * em_utils_compose_lite_new_message (const char *fromuri);
/* FIXME: mailto? url? should make up its mind what its called. imho use 'uri' */
void em_utils_compose_new_message_with_mailto (const char *url, const char *fromuri);
diff --cc mail/em-folder-tree-model.c
index abdd3c8,d90bcbb..c0e3f2b
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@@ -98,64 -96,98 +98,65 @@@ enum
LAST_SIGNAL
};
+ extern CamelStore *vfolder_store;
+
-static guint signals[LAST_SIGNAL] = { 0, };
-static GtkTreeStoreClass *parent_class = NULL;
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
-GType
-em_folder_tree_model_get_type (void)
+static void
+store_info_free (EMFolderTreeModelStoreInfo *si)
{
- static GType type = 0;
+ camel_object_remove_event (si->store, si->created_id);
+ camel_object_remove_event (si->store, si->deleted_id);
+ camel_object_remove_event (si->store, si->renamed_id);
+ camel_object_remove_event (si->store, si->subscribed_id);
+ camel_object_remove_event (si->store, si->unsubscribed_id);
- if (!type) {
- static const GTypeInfo info = {
- sizeof (EMFolderTreeModelClass),
- NULL, /* base_class_init */
- NULL, /* base_class_finalize */
- (GClassInitFunc) em_folder_tree_model_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (EMFolderTreeModel),
- 0, /* n_preallocs */
- (GInstanceInitFunc) em_folder_tree_model_init,
- };
- static const GInterfaceInfo tree_model_info = {
- (GInterfaceInitFunc) tree_model_iface_init,
- NULL,
- NULL
- };
- static const GInterfaceInfo sortable_info = {
- (GInterfaceInitFunc) tree_sortable_iface_init,
- NULL,
- NULL
- };
+ g_free (si->display_name);
+ camel_object_unref (si->store);
+ gtk_tree_row_reference_free (si->row);
+ g_hash_table_destroy (si->full_hash);
+ g_free (si);
+}
+
+static void
+folder_tree_model_load_state (EMFolderTreeModel *model,
+ const gchar *filename)
+{
+ xmlNodePtr root, node;
- type = g_type_register_static (GTK_TYPE_TREE_STORE, "EMFolderTreeModel", &info, 0);
+ if (model->state)
+ xmlFreeDoc (model->state);
- g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL,
- &tree_model_info);
- g_type_add_interface_static (type, GTK_TYPE_TREE_SORTABLE,
- &sortable_info);
+ if ((model->state = e_xml_parse_file (filename)) != NULL) {
+ node = xmlDocGetRootElement (model->state);
+ if (!node || strcmp ((char *)node->name, "tree-state") != 0) {
+ /* it is not expected XML file, thus free it and use the default */
+ xmlFreeDoc (model->state);
+ } else
+ return;
}
- return type;
-}
+ /* setup some defaults - expand "Local Folders" and "Search Folders" */
+ model->state = xmlNewDoc ((const unsigned char *)"1.0");
+ root = xmlNewDocNode (model->state, NULL, (const unsigned char *)"tree-state", NULL);
+ xmlDocSetRootElement (model->state, root);
+ node = xmlNewChild (root, NULL, (const unsigned char *)"node", NULL);
+ xmlSetProp (node, (const unsigned char *)"name", (const unsigned char *)"local");
+ xmlSetProp (node, (const unsigned char *)"expand", (const unsigned char *)"true");
-static void
-em_folder_tree_model_class_init (EMFolderTreeModelClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- parent_class = g_type_class_ref (GTK_TYPE_TREE_STORE);
-
- object_class->finalize = em_folder_tree_model_finalize;
-
- /* signals */
- signals[LOADING_ROW] =
- g_signal_new ("loading-row",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EMFolderTreeModelClass, loading_row),
- NULL, NULL,
- e_marshal_VOID__POINTER_POINTER,
- G_TYPE_NONE, 2,
- G_TYPE_POINTER,
- G_TYPE_POINTER);
-
- signals[LOADED_ROW] =
- g_signal_new ("loaded-row",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EMFolderTreeModelClass, loaded_row),
- NULL, NULL,
- e_marshal_VOID__POINTER_POINTER,
- G_TYPE_NONE, 2,
- G_TYPE_POINTER,
- G_TYPE_POINTER);
-
- signals[FOLDER_ADDED] =
- g_signal_new ("folder-added",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- G_STRUCT_OFFSET (EMFolderTreeModelClass, folder_added),
- NULL, NULL,
- e_marshal_VOID__STRING_STRING,
- G_TYPE_NONE, 2,
- G_TYPE_STRING,
- G_TYPE_STRING);
+ node = xmlNewChild (root, NULL, (const unsigned char *)"node", NULL);
+ xmlSetProp (node, (const unsigned char *)"name", (const unsigned char *)"vfolder");
+ xmlSetProp (node, (const unsigned char *)"expand", (const unsigned char *)"true");
}
static int
-sort_cb (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
+folder_tree_model_sort (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
{
- extern CamelStore *vfolder_store;
char *aname, *bname;
CamelStore *store;
gboolean is_store;
diff --cc mail/em-folder-tree.c
index 07aedc2,77e62df..f4980dc
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@@ -157,7 -151,13 +157,8 @@@ static GdkAtom drop_atoms[NUM_DROP_TYPE
static guint signals[LAST_SIGNAL] = { 0 };
extern CamelSession *session;
+ extern CamelStore *vfolder_store;
-static void em_folder_tree_class_init (EMFolderTreeClass *klass);
-static void em_folder_tree_init (EMFolderTree *emft);
-static void em_folder_tree_destroy (GtkObject *obj);
-static void em_folder_tree_finalize (GObject *obj);
-
static gboolean emft_save_state (EMFolderTree *emft);
static void emft_queue_save_state (EMFolderTree *emft);
@@@ -544,10 -530,7 +545,9 @@@ emft_expand_node (EMFolderTreeModel *mo
{
struct _EMFolderTreePrivate *priv = emft->priv;
struct _EMFolderTreeModelStoreInfo *si;
- extern CamelStore *vfolder_store;
+ EMailShellBackend *mail_shell_backend;
GtkTreeRowReference *row;
+ GtkTreeView *tree_view;
GtkTreePath *path;
EAccount *account;
CamelStore *store;
diff --cc mail/em-folder-utils.c
index 510bcf7,ad60516..2b319ff
--- a/mail/em-folder-utils.c
+++ b/mail/em-folder-utils.c
@@@ -269,8 -268,7 +269,8 @@@ emfu_copy_folder_selected (const char *
{
struct _copy_folder_data *cfd = data;
CamelStore *fromstore = NULL, *tostore = NULL;
+ CamelStore *local_store;
- char *tobase = NULL;
+ const gchar *tobase = NULL;
CamelException ex;
CamelURL *url;
diff --cc mail/em-folder-view.c
index 8da3b5d,d0f8289..b72e187
--- a/mail/em-folder-view.c
+++ b/mail/em-folder-view.c
@@@ -123,22 -164,22 +123,22 @@@ static const EMFolderViewEnable emfv_en
{ "AddSenderToAddressbook", EM_POPUP_SELECT_ADD_SENDER },
- { "MessageApplyFilters", EM_POPUP_SELECT_MANY },
- { "MessageFilterJunk", EM_POPUP_SELECT_MANY },
- { "MessageCopy", EM_POPUP_SELECT_MANY },
- { "MessageDelete", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_DELETE },
- { "MessageDeleteKey", EM_POPUP_SELECT_MANY},
- { "MessageForward", EM_POPUP_SELECT_MANY },
- { "MessageForwardAttached", EM_POPUP_SELECT_MANY },
- { "MessageForwardInline", EM_POPUP_SELECT_ONE },
- { "MessageForwardQuoted", EM_POPUP_SELECT_ONE },
- { "MessageRedirect", EM_POPUP_SELECT_ONE },
- { "MessageMarkAsRead", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_READ },
- { "MessageMarkAsUnRead", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNREAD },
- { "MessageMarkAsImportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_IMPORTANT },
- { "MessageMarkAsUnimportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNIMPORTANT },
- { "MessageMarkAsJunk", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_JUNK },
- { "MessageMarkAsNotJunk", EM_POPUP_SELECT_MANY},
+// { "MessageApplyFilters", EM_POPUP_SELECT_MANY },
+// { "MessageFilterJunk", EM_POPUP_SELECT_MANY },
+// { "MessageCopy", EM_POPUP_SELECT_MANY },
+// { "MessageDelete", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_DELETE },
- // { "MessageDeleteKey", EM_POPUP_SELECT_MANY},
++// { "MessageDeleteKey", EM_POPUP_SELECT_MANY},
+// { "MessageForward", EM_POPUP_SELECT_MANY },
+// { "MessageForwardAttached", EM_POPUP_SELECT_MANY },
+// { "MessageForwardInline", EM_POPUP_SELECT_ONE },
+// { "MessageForwardQuoted", EM_POPUP_SELECT_ONE },
+// { "MessageRedirect", EM_POPUP_SELECT_ONE },
+// { "MessageMarkAsRead", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_READ },
+// { "MessageMarkAsUnRead", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNREAD },
+// { "MessageMarkAsImportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_IMPORTANT },
+// { "MessageMarkAsUnimportant", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_MARK_UNIMPORTANT },
+// { "MessageMarkAsJunk", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_JUNK },
+// { "MessageMarkAsNotJunk", EM_POPUP_SELECT_MANY},
{ "MessageFollowUpFlag", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_FOLLOWUP },
{ "MessageFollowUpComplete", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_COMPLETED },
{ "MessageFollowUpClear", EM_POPUP_SELECT_MANY|EM_POPUP_SELECT_FLAG_CLEAR },
@@@ -197,28 -241,40 +197,29 @@@ enum
LAST_SIGNAL
};
+ extern CamelSession *session;
+
static guint signals[LAST_SIGNAL];
-static void emfv_selection_get(GtkWidget *widget, GtkSelectionData *data, guint info, guint time_stamp, EMFolderView *emfv);
-static void emfv_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, EMFolderView *emfv);
-
-#ifdef ENABLE_PROFILING
-static void
-emfv_format_complete(EMFormat *emf, EMFolderView *emfv)
-{
- e_profile_event_emit("goto.done", emf->uid?emf->uid:"", 0);
-}
-#endif
-
static void
emfv_init(GObject *o)
{
EMFolderView *emfv = (EMFolderView *)o;
struct _EMFolderViewPrivate *p;
- extern CamelSession *session;
- gtk_box_set_homogeneous (GTK_BOX (emfv), FALSE);
-
- p = emfv->priv = g_malloc0(sizeof(struct _EMFolderViewPrivate));
-
- emfv->statusbar_active = TRUE;
- emfv->list_active = FALSE;
-
- emfv->ui_files = g_slist_append(NULL,
- g_build_filename (EVOLUTION_UIDIR,
- "evolution-mail-message.xml",
- NULL));
-
- emfv->ui_app_name = "evolution-mail";
+// gtk_box_set_homogeneous (GTK_BOX (emfv), FALSE);
+//
+// p = emfv->priv = g_malloc0(sizeof(struct _EMFolderViewPrivate));
+//
+// emfv->statusbar_active = TRUE;
+// emfv->list_active = FALSE;
+//
+// emfv->ui_files = g_slist_append(NULL,
+// g_build_filename (EVOLUTION_UIDIR,
+// "evolution-mail-message.xml",
+// NULL));
+//
+// emfv->ui_app_name = "evolution-mail";
emfv->enable_map = g_slist_prepend(NULL, (void *)emfv_enable_map);
diff --cc mail/em-format-html.c
index cbf90a9,aa82851..6bc4a79
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@@ -956,93 -281,34 +956,91 @@@ em_format_html_get_type (void
return type;
}
-EMFormatHTML *em_format_html_new(void)
+void
+em_format_html_load_images (EMFormatHTML *efh)
{
- EMFormatHTML *efh;
+ g_return_if_fail (EM_IS_FORMAT_HTML (efh));
- efh = g_object_new(em_format_html_get_type(), NULL);
+ if (efh->priv->image_loading_policy == MAIL_CONFIG_HTTP_ALWAYS)
+ return;
- return efh;
+ /* This will remain set while we're still
+ * rendering the same message, then it wont be. */
+ efh->priv->load_images_now = TRUE;
+ em_format_redraw (EM_FORMAT (efh));
}
-/* force loading of http images */
-void em_format_html_load_http(EMFormatHTML *emfh)
+void
+em_format_html_get_color (EMFormatHTML *efh,
+ EMFormatHTMLColorType type,
+ GdkColor *color)
{
- if (emfh->load_http == MAIL_CONFIG_HTTP_ALWAYS)
- return;
+ GdkColor *format_color;
+
+ g_return_if_fail (EM_IS_FORMAT_HTML (efh));
- g_return_if_fail (type >= 0);
+ g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES);
+ g_return_if_fail (color != NULL);
- /* This will remain set while we're still rendering the same message, then it wont be */
- emfh->load_http_now = TRUE;
- d(printf("redrawing with images forced on\n"));
- em_format_redraw((EMFormat *)emfh);
+ format_color = &efh->priv->colors[type];
+
+ color->red = format_color->red;
+ color->green = format_color->green;
+ color->blue = format_color->blue;
}
void
-em_format_html_set_load_http(EMFormatHTML *emfh, int style)
+em_format_html_set_color (EMFormatHTML *efh,
+ EMFormatHTMLColorType type,
+ const GdkColor *color)
{
- if (emfh->load_http != style) {
- emfh->load_http = style;
- em_format_redraw((EMFormat *)emfh);
+ GdkColor *format_color;
+ const gchar *property_name;
+
+ g_return_if_fail (EM_IS_FORMAT_HTML (efh));
- g_return_if_fail (type >= 0);
+ g_return_if_fail (type < EM_FORMAT_HTML_NUM_COLOR_TYPES);
+ g_return_if_fail (color != NULL);
+
+ format_color = &efh->priv->colors[type];
+
+ if (gdk_color_equal (color, format_color))
+ return;
+
+ format_color->red = color->red;
+ format_color->green = color->green;
+ format_color->blue = color->blue;
+
+ switch (type) {
+ case EM_FORMAT_HTML_COLOR_BODY:
+ property_name = "body-color";
+ break;
+ case EM_FORMAT_HTML_COLOR_CITATION:
+ property_name = "citation-color";
+ break;
+ case EM_FORMAT_HTML_COLOR_CONTENT:
+ property_name = "content-color";
+ break;
+ case EM_FORMAT_HTML_COLOR_FRAME:
+ property_name = "frame-color";
+ break;
+ case EM_FORMAT_HTML_COLOR_HEADER:
+ property_name = "header-color";
+ break;
+ case EM_FORMAT_HTML_COLOR_TEXT:
+ property_name = "text-color";
+ break;
+ default:
+ g_return_if_reached ();
}
+
+ g_object_notify (G_OBJECT (efh), property_name);
+}
+
+MailConfigHTTPMode
+em_format_html_get_image_loading_policy (EMFormatHTML *efh)
+{
+ g_return_val_if_fail (EM_IS_FORMAT_HTML (efh), 0);
+
+ return efh->priv->image_loading_policy;
}
void
@@@ -2430,15 -1859,13 +2428,15 @@@ efh_format_headers(EMFormatHTML *efh, C
charset = camel_iconv_charset_name(charset);
if (!efh->simple_headers)
- camel_stream_printf(stream,
- "<font color=\"#%06x\">\n"
- "<table cellpadding=\"0\" width=\"100%%\">",
- efh->header_colour & 0xffffff);
+ camel_stream_printf (
+ stream, "<font color=\"#%06x\">\n"
+ "<table cellpadding=\"0\" width=\"100%%\">",
+ e_color_to_value (
+ &efh->priv->colors[
+ EM_FORMAT_HTML_COLOR_HEADER]));
-
+
hdr_charset = emf->charset ? emf->charset : emf->default_charset;
-
+
header = ((CamelMimePart *)part)->headers;
while (header) {
if (!g_ascii_strcasecmp (header->name, "Sender")) {
diff --cc mail/em-mailer-prefs.h
index c7dc6ac,10503a8..fddc7cd
--- a/mail/em-mailer-prefs.h
+++ b/mail/em-mailer-prefs.h
@@@ -97,29 -111,31 +97,29 @@@ struct _EMMailerPrefs
guint labels_change_notify_id; /* mail_config's notify id */
/* Headers tab */
- struct _GtkButton *add_header;
- struct _GtkButton *remove_header;
- struct _GtkEntry *entry_header;
- struct _GtkTreeView *header_list;
- struct _GtkListStore *header_list_store;
- struct _GtkToggleButton *photo_show;
- struct _GtkToggleButton *photo_local;
+ GtkButton *add_header;
+ GtkButton *remove_header;
+ GtkEntry *entry_header;
+ GtkTreeView *header_list;
+ GtkListStore *header_list_store;
/* Junk prefs */
- struct _GtkToggleButton *check_incoming;
- struct _GtkToggleButton *empty_junk;
- struct _GtkComboBox *empty_junk_days;
-
- struct _GtkToggleButton *sa_local_tests_only;
- struct _GtkToggleButton *sa_use_daemon;
- struct _GtkComboBox *default_junk_plugin;
- struct _GtkLabel *plugin_status;
- struct _GtkImage *plugin_image;
-
- struct _GtkToggleButton *junk_header_check;
- struct _GtkTreeView *junk_header_tree;
- struct _GtkButton *junk_header_add;
- struct _GtkButton *junk_header_remove;
- struct _GtkToggleButton *junk_book_lookup;
- struct _GtkToggleButton *junk_lookup_local_only;
+ GtkToggleButton *empty_junk;
+ GtkComboBox *empty_junk_days;
-
++
+ GtkToggleButton *sa_local_tests_only;
+ GtkToggleButton *sa_use_daemon;
+ GtkComboBox *default_junk_plugin;
+ GtkLabel *plugin_status;
+ GtkImage *plugin_image;
+
+ GtkToggleButton *junk_header_check;
+ GtkTreeView *junk_header_tree;
- GtkListStore *junk_header_list_store;
++ GtkListStore *junk_header_list_store;
+ GtkButton *junk_header_add;
+ GtkButton *junk_header_remove;
+ GtkToggleButton *junk_book_lookup;
+ GtkToggleButton *junk_lookup_local_only;
};
struct _EMMailerPrefsClass {
diff --cc mail/em-network-prefs.h
index 50d986c,3d933a7..bd4e9e7
--- a/mail/em-network-prefs.h
+++ b/mail/em-network-prefs.h
@@@ -58,38 -51,48 +58,38 @@@ typedef enum
NETWORK_PROXY_AUTOCONFIG
} NetworkConfigProxyType;
-
struct _EMNetworkPrefs {
GtkVBox parent_object;
-
+
- struct _GConfClient *gconf;
+ GConfClient *gconf;
-
+
- struct _GladeXML *gui;
+ GladeXML *gui;
-
+
/* Default Behavior */
- struct _GtkToggleButton *sys_proxy;
- struct _GtkToggleButton *no_proxy;
- struct _GtkToggleButton *manual_proxy;
-#if 0
- struct _GtkToggleButton *auto_proxy;
-#endif
- struct _GtkToggleButton *use_auth;
-
- struct _GtkEntry *http_host;
- struct _GtkEntry *https_host;
- struct _GtkEntry *ignore_hosts;
-#if 0
- struct _GtkEntry *auto_proxy_url;
-#endif
- struct _GtkEntry *auth_user;
- struct _GtkEntry *auth_pwd;
-
- struct _GtkLabel *lbl_http_host;
- struct _GtkLabel *lbl_http_port;
- struct _GtkLabel *lbl_https_host;
- struct _GtkLabel *lbl_https_port;
- struct _GtkLabel *lbl_ignore_hosts;
- struct _GtkLabel *lbl_auth_user;
- struct _GtkLabel *lbl_auth_pwd;
-
- struct _GtkSpinButton *http_port;
- struct _GtkSpinButton *https_port;
-#if 0
- struct _GtkLabel *lbl_socks_host;
- struct _GtkEntry *socks_host;
- struct _GtkLabel *lbl_socks_port;
- struct _GtkSpinButton *socks_port;
-#endif
+ GtkToggleButton *sys_proxy;
+ GtkToggleButton *no_proxy;
+ GtkToggleButton *manual_proxy;
+ GtkToggleButton *use_auth;
+
+ GtkEntry *http_host;
+ GtkEntry *https_host;
+ GtkEntry *socks_host;
+ GtkEntry *ignore_hosts;
+ GtkEntry *auth_user;
+ GtkEntry *auth_pwd;
+
+ GtkLabel *lbl_http_host;
+ GtkLabel *lbl_http_port;
+ GtkLabel *lbl_https_host;
+ GtkLabel *lbl_https_port;
+ GtkLabel *lbl_socks_host;
+ GtkLabel *lbl_socks_port;
+ GtkLabel *lbl_ignore_hosts;
+ GtkLabel *lbl_auth_user;
+ GtkLabel *lbl_auth_pwd;
+
+ GtkSpinButton *http_port;
+ GtkSpinButton *https_port;
};
struct _EMNetworkPrefsClass {
diff --cc mail/em-utils.c
index 2a7ce74,ba180e5..9b27869
--- a/mail/em-utils.c
+++ b/mail/em-utils.c
@@@ -1401,16 -1384,13 +1401,16 @@@ em_utils_folder_is_templates (CamelFold
int is = FALSE;
char *templates_uri;
- if (folder == mail_component_get_folder (NULL, MAIL_COMPONENT_FOLDER_TEMPLATES))
+ local_templates_folder = e_mail_shell_backend_get_folder (
+ global_mail_shell_backend, E_MAIL_FOLDER_TEMPLATES);
+
+ if (folder == local_templates_folder)
return TRUE;
-
+
- if (uri == NULL)
+ if (folder == NULL || uri == NULL)
return FALSE;
-
+
- accounts = mail_config_get_accounts();
+ accounts = e_get_account_list ();
iter = e_list_get_iterator ((EList *)accounts);
while (e_iterator_is_valid (iter)) {
account = (EAccount *)e_iterator_get (iter);
diff --cc mail/evolution-module-mail.c
index a629681,0000000..97bc953
mode 100644,000000..100644
--- a/mail/evolution-module-mail.c
+++ b/mail/evolution-module-mail.c
@@@ -1,59 -1,0 +1,59 @@@
+/*
+ * evolution-module-mail.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-mail-shell-backend.h"
+#include "e-mail-shell-content.h"
+#include "e-mail-shell-sidebar.h"
+#include "e-mail-shell-view.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+const gchar * g_module_check_init (GModule *module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ /* Register dynamically loaded types. */
+
+ e_mail_shell_backend_register_type (type_module);
+ e_mail_shell_content_register_type (type_module);
+ e_mail_shell_sidebar_register_type (type_module);
+ e_mail_shell_view_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
+
+G_MODULE_EXPORT const gchar *
+g_module_check_init (GModule *module)
+{
+ /* FIXME Until mail is split into a module library and a
+ * reusable shared library, prevent the module from
+ * being unloaded. Unloading the module resets all
+ * static variables, which screws up foo_get_type()
+ * functions among other things. */
+ g_module_make_resident (module);
+
+ return NULL;
+}
diff --cc mail/mail-component.c
index 6167cc5,698cc94..7cf42f6
--- a/mail/mail-component.c
+++ b/mail/mail-component.c
@@@ -382,12 -862,9 +382,11 @@@ impl_quit(PortableServer_Servant servan
if (mc->priv->quit_state == -1)
mc->priv->quit_state = MC_QUIT_START;
- mail_config_prune_proxies ();
+ account_list = e_get_account_list ();
+ e_account_list_prune_proxies (account_list);
+
switch (mc->priv->quit_state) {
case MC_QUIT_START: {
- extern int camel_application_is_exiting;
int now = time(NULL)/60/60/24, days;
gboolean empty_junk;
@@@ -507,21 -1304,297 +506,21 @@@ mail_component_init (MailComponent *com
e_activity_handler_set_logger (priv->activity_handler, priv->logger);
e_activity_handler_set_error_flush_time (priv->activity_handler, mail_config_get_error_timeout ()*1000);
- mail_session_init (e_get_user_data_dir ());
-
- priv->async_event = mail_async_event_new();
- priv->store_hash = g_hash_table_new_full (
- NULL, NULL,
- (GDestroyNotify) NULL,
- (GDestroyNotify) store_hash_free);
-
- mail_autoreceive_init (session);
-
- priv->mail_sync_in_progress = 0;
- if (g_getenv("CAMEL_FLUSH_CHANGES"))
- priv->mail_sync_id = g_timeout_add_seconds (mail_config_get_sync_timeout (), call_mail_sync, component);
- else
- priv->mail_sync_id = 0;
-}
-
-/* Public API. */
-MailComponent *
-mail_component_peek (void)
-{
- static MailComponent *component = NULL;
-
- if (component == NULL)
- component = g_object_new(mail_component_get_type(), NULL);
-
- return component;
-}
-
-const char *
-mail_component_peek_base_directory (MailComponent *component)
-{
- MAIL_COMPONENT_DEFAULT(component);
-
- return component->priv->base_directory;
-}
-
-RuleContext *
-mail_component_peek_search_context (MailComponent *component)
-{
- MAIL_COMPONENT_DEFAULT(component);
-
- setup_search_context(component);
-
- return component->priv->search_context;
-}
-
-EActivityHandler *
-mail_component_peek_activity_handler (MailComponent *component)
-{
- MAIL_COMPONENT_DEFAULT(component);
-
- return component->priv->activity_handler;
-}
-
-struct _CamelSession *mail_component_peek_session(MailComponent *component)
-{
- MAIL_COMPONENT_DEFAULT(component);
-
- return session;
-}
-
-void
-mail_component_add_store (MailComponent *component, CamelStore *store, const char *name)
-{
- mc_add_store(component, store, name, NULL);
-}
-
-/**
- * mail_component_load_store_by_uri:
- * @component: mail component
- * @uri: uri of store
- * @name: name of store (used for display purposes)
- *
- * Return value: Pointer to the newly added CamelStore. The caller is supposed
- * to ref the object if it wants to store it.
- **/
-CamelStore *
-mail_component_load_store_by_uri (MailComponent *component, const char *uri, const char *name)
-{
- CamelException ex;
- CamelStore *store;
- CamelProvider *prov;
-
- MAIL_COMPONENT_DEFAULT(component);
-
- camel_exception_init (&ex);
-
- /* Load the service (don't connect!). Check its provider and
- * see if this belongs in the shell's folder list. If so, add
- * it.
- */
-
- prov = camel_provider_get(uri, &ex);
- if (prov == NULL) {
- /* EPFIXME: real error dialog */
- g_warning ("couldn't get service %s: %s\n", uri,
- camel_exception_get_description (&ex));
- camel_exception_clear (&ex);
- return NULL;
- }
-
- if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE))
- return NULL;
-
- store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex);
- if (store == NULL) {
- /* EPFIXME: real error dialog */
- g_warning ("couldn't get service %s: %s\n", uri,
- camel_exception_get_description (&ex));
- camel_exception_clear (&ex);
- return NULL;
- }
-
- mail_component_add_store(component, store, name);
- camel_object_unref (store);
-
- return store;
-}
-
-static void
-store_disconnect (CamelStore *store, void *event_data, void *user_data)
-{
- camel_service_disconnect (CAMEL_SERVICE (store), TRUE, NULL);
- camel_object_unref (store);
-}
-
-void
-mail_component_remove_store (MailComponent *component, CamelStore *store)
-{
- MailComponentPrivate *priv;
-
- MAIL_COMPONENT_DEFAULT(component);
-
- priv = component->priv;
-
- /* Because the store_hash holds a reference to each store
- * used as a key in it, none of them will ever be gc'ed, meaning
- * any call to camel_session_get_{service,store} with the same
- * URL will always return the same object. So this works.
- */
-
- if (g_hash_table_lookup (priv->store_hash, store) == NULL)
- return;
-
- camel_object_ref (store);
- g_hash_table_remove (priv->store_hash, store);
-
- /* so i guess potentially we could have a race, add a store while one
- being removed. ?? */
- mail_note_store_remove (store);
-
- em_folder_tree_model_remove_store (priv->model, store);
-
- mail_async_event_emit (priv->async_event, MAIL_ASYNC_THREAD, (MailAsyncFunc) store_disconnect, store, NULL, NULL);
-}
-
-void
-mail_component_remove_store_by_uri (MailComponent *component, const char *uri)
-{
- CamelProvider *prov;
- CamelStore *store;
-
- MAIL_COMPONENT_DEFAULT(component);
-
- if (!(prov = camel_provider_get(uri, NULL)))
- return;
-
- if (!(prov->flags & CAMEL_PROVIDER_IS_STORAGE))
- return;
-
- store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, NULL);
- if (store != NULL) {
- mail_component_remove_store (component, store);
- camel_object_unref (store);
- }
-}
-
-int
-mail_component_get_store_count (MailComponent *component)
-{
- MAIL_COMPONENT_DEFAULT(component);
-
- return g_hash_table_size (component->priv->store_hash);
-}
-
-/* need to map from internal struct to external api */
-struct _store_foreach_data {
- GHFunc func;
- void *data;
-};
-
-static void
-mc_stores_foreach(CamelStore *store, struct _store_info *si, struct _store_foreach_data *data)
-{
- data->func((void *)store, (void *)si->name, data->data);
-}
-
-void
-mail_component_stores_foreach (MailComponent *component, GHFunc func, void *user_data)
-{
- struct _store_foreach_data data = { func, user_data };
-
- MAIL_COMPONENT_DEFAULT(component);
-
- g_hash_table_foreach (component->priv->store_hash, (GHFunc)mc_stores_foreach, &data);
-}
-
-void
-mail_component_remove_folder (MailComponent *component, CamelStore *store, const char *path)
-{
- MAIL_COMPONENT_DEFAULT(component);
-
- /* FIXME: implement me. but first, am I really even needed? */
-}
-
-EMFolderTreeModel *
-mail_component_peek_tree_model (MailComponent *component)
-{
- MAIL_COMPONENT_DEFAULT(component);
-
- return component->priv->model;
-}
-
-CamelStore *
-mail_component_peek_local_store (MailComponent *mc)
-{
- MAIL_COMPONENT_DEFAULT (mc);
- mc_setup_local_store (mc);
-
- return mc->priv->local_store;
-}
+// mail_session_init (e_get_user_data_dir ());
-/**
- * mail_component_get_folder:
- * @mc:
- * @id:
- *
- * Get a standard/default folder by id. This call is thread-safe.
- *
- * Return value:
- **/
-struct _CamelFolder *
-mail_component_get_folder(MailComponent *mc, enum _mail_component_folder_t id)
-{
- g_return_val_if_fail (id <= MAIL_COMPONENT_FOLDER_LOCAL_INBOX, NULL);
+// priv->async_event = mail_async_event_new();
+// priv->store_hash = g_hash_table_new_full (
+// NULL, NULL,
+// (GDestroyNotify) NULL,
+// (GDestroyNotify) store_hash_free);
- MAIL_COMPONENT_DEFAULT(mc);
- mc_setup_local_store(mc);
+// mail_autoreceive_init (session);
- return mc_default_folders[id].folder;
-}
-
-/**
- * mail_component_get_folder_uri:
- * @mc:
- * @id:
- *
- * Get a standard/default folder's uri. This call is thread-safe.
- *
- * Return value:
- **/
-const char *
-mail_component_get_folder_uri(MailComponent *mc, enum _mail_component_folder_t id)
-{
- g_return_val_if_fail (id <= MAIL_COMPONENT_FOLDER_LOCAL_INBOX, NULL);
-
- MAIL_COMPONENT_DEFAULT(mc);
- mc_setup_local_store(mc);
-
- return mc_default_folders[id].uri;
-}
-
-/**
- * mail_indicate_new_mail
- * Indicates new mail in a shell window.
- * @param have_new_mail TRUE when have new mail, false otherwise.
- **/
-void
-mail_indicate_new_mail (gboolean have_new_mail)
-{
- const char *icon = NULL;
- MailComponent *mc = mail_component_peek ();
-
- g_return_if_fail (mc != NULL);
-
- if (have_new_mail)
- icon = "mail-unread";
-
- if (mc->priv->component_view)
- e_component_view_set_button_icon (mc->priv->component_view, icon);
+// priv->mail_sync_in_progress = 0;
+// if (g_getenv("CAMEL_FLUSH_CHANGES"))
+// priv->mail_sync_id = g_timeout_add_seconds (mail_config_get_sync_timeout (), call_mail_sync, component);
- // else
++// else
+// priv->mail_sync_id = 0;
}
void
diff --cc mail/mail-config.c
index 45fc8f9,bcf8dd7..59bab65
--- a/mail/mail-config.c
+++ b/mail/mail-config.c
@@@ -93,7 -110,18 +95,6 @@@ extern int camel_header_param_encode_fi
static MailConfig *config = NULL;
static guint config_write_timeout = 0;
-
-void
-mail_config_save_accounts (void)
-{
- e_account_list_save (config->accounts);
-}
-
-void
-mail_config_save_signatures (void)
-{
- e_signature_list_save (config->signatures);
-}
-
static void
config_clear_mime_types (void)
{
@@@ -800,15 -991,15 +799,16 @@@ mail_config_uri_renamed (GCompareFunc u
EIterator *iter;
int i, work = 0;
char *oldname, *newname;
- char *cachenames[] = { "config/hidestate-",
- "config/et-expanded-",
- "config/et-header-",
- "*views/current_view-",
- "*views/custom_view-",
- NULL };
+ const gchar *cachenames[] = {
+ "config/hidestate-",
+ "config/et-expanded-",
+ "config/et-header-",
+ "*views/current_view-",
+ "*views/custom_view-",
+ NULL };
- iter = e_list_get_iterator ((EList *) config->accounts);
+ account_list = e_get_account_list ();
+ iter = e_list_get_iterator ((EList *) account_list);
while (e_iterator_is_valid (iter)) {
account = (EAccount *) e_iterator_get (iter);
diff --cc mail/mail-folder-cache.c
index b6a92bc,a84dfcb..23b85ac
--- a/mail/mail-folder-cache.c
+++ b/mail/mail-folder-cache.c
@@@ -197,8 -196,7 +197,9 @@@ real_flush_updates (EMailShellBackend *
t->name = em_folder_tree_model_get_folder_name (model, up->store, up->full_name);
if (t->new > 0)
- mail_indicate_new_mail (TRUE);
+ e_shell_event (
- shell, "mail-icon", "mail-unread");
++ shell, "mail-icon",
++ (gpointer) "mail-unread");
/** @Event: folder.changed
* @Title: Folder changed
diff --cc mail/mail-send-recv.c
index 7b63263,be834bb..a463bb8
--- a/mail/mail-send-recv.c
+++ b/mail/mail-send-recv.c
@@@ -1234,11 -1204,10 +1234,11 @@@ mail_send (void
d(printf("Adding new info %p\n", info));
- g_hash_table_insert (data->active, SEND_URI_KEY, info);
+ g_hash_table_insert (data->active, (gpointer) SEND_URI_KEY, info);
/* todo, store the folder in info? */
- outbox_folder = mail_component_get_folder(NULL, MAIL_COMPONENT_FOLDER_OUTBOX);
+ outbox_folder = e_mail_shell_backend_get_folder (
+ global_mail_shell_backend, E_MAIL_FOLDER_OUTBOX);
mail_send_queue (outbox_folder, info->uri,
FILTER_SOURCE_OUTGOING,
info->cancel,
diff --cc mail/message-list.c
index e970a09,09f080c..8d84e4a
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@@ -122,13 -113,8 +122,13 @@@ struct _MessageListPrivate
gboolean any_row_changed; /* save state before regen list when this is set to true */
};
+enum {
+ PROP_0,
+ PROP_SHELL_BACKEND
+};
+
static struct {
- char *target;
+ const gchar *target;
GdkAtom atom;
guint32 actions;
} ml_drag_info[] = {
diff --cc plugins/imap-features/Makefile.am
index b0f34f1,69b94ff..cf7dbd7
--- a/plugins/imap-features/Makefile.am
+++ b/plugins/imap-features/Makefile.am
@@@ -1,7 -1,10 +1,6 @@@
INCLUDES = \
-if OS_WIN32
-NO_UNDEFINED_REQUIRED_LIBS = $(top_builddir)/mail/libevolution-mail.la
-endif
-
-I$(top_srcdir) \
-I$(top_srcdir)/mail \
- -I$(top_srcdir)/libedataserver \
$(EVOLUTION_MAIL_CFLAGS) \
$(CAMEL_IMAP_CFLAGS) \
-DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \
diff --cc shell/e-shell-backend.c
index e1b29ae,0000000..06e1469
mode 100644,000000..100644
--- a/shell/e-shell-backend.c
+++ b/shell/e-shell-backend.c
@@@ -1,458 -1,0 +1,458 @@@
+/*
+ * e-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-backend.h"
+
+#include <errno.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+
+#include "e-shell.h"
+#include "e-shell-view.h"
+
+#define E_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SHELL_BACKEND, EShellBackendPrivate))
+
+struct _EShellBackendPrivate {
+
+ gpointer shell; /* weak pointer */
+
+ /* We keep a reference to corresponding EShellView subclass
+ * since it keeps a reference back to us. This ensures the
+ * subclass is not finalized before we are, otherwise it
+ * would leak its EShellBackend reference. */
+ EShellViewClass *shell_view_class;
+
+ gchar *config_dir;
+ gchar *data_dir;
+
+ guint started : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_SHELL
+};
+
+enum {
+ ACTIVITY_ADDED,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+shell_backend_set_shell (EShellBackend *shell_backend,
+ EShell *shell)
+{
+ g_return_if_fail (shell_backend->priv->shell == NULL);
+
+ shell_backend->priv->shell = shell;
+
+ g_object_add_weak_pointer (
+ G_OBJECT (shell_backend),
+ &shell_backend->priv->shell);
+}
+
+static void
+shell_backend_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SHELL:
+ shell_backend_set_shell (
+ E_SHELL_BACKEND (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_backend_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SHELL:
+ g_value_set_object (
+ value, e_shell_backend_get_shell (
+ E_SHELL_BACKEND (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_backend_dispose (GObject *object)
+{
+ EShellBackendPrivate *priv;
+
+ priv = E_SHELL_BACKEND_GET_PRIVATE (object);
+
+ if (priv->shell_view_class != NULL) {
+ g_type_class_unref (priv->shell_view_class);
+ priv->shell_view_class = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+shell_backend_finalize (GObject *object)
+{
+ EShellBackendPrivate *priv;
+
+ priv = E_SHELL_BACKEND_GET_PRIVATE (object);
+
+ g_free (priv->data_dir);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+shell_backend_class_init (EShellBackendClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = shell_backend_set_property;
+ object_class->get_property = shell_backend_get_property;
+ object_class->dispose = shell_backend_dispose;
+ object_class->finalize = shell_backend_finalize;
+
+ /**
+ * EShellBackend:shell
+ *
+ * The #EShell singleton.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_SHELL,
+ g_param_spec_object (
+ "shell",
+ _("Shell"),
+ _("The EShell singleton"),
+ E_TYPE_SHELL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * EShellBackend::activity-added
+ * @shell_backend: the #EShellBackend that emitted the signal
+ * @activity: an #EActivity
+ *
+ * Broadcasts a newly added activity.
+ **/
+ signals[ACTIVITY_ADDED] = g_signal_new (
+ "activity-added",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_ACTIVITY);
+}
+
+static void
+shell_backend_init (EShellBackend *shell_backend,
+ EShellBackendClass *class)
+{
+ EShellViewClass *shell_view_class;
+ gchar *dirname;
+
+ shell_backend->priv = E_SHELL_BACKEND_GET_PRIVATE (shell_backend);
+
+ /* Install a reference to ourselves in the corresponding
+ * EShellViewClass structure, */
+ shell_view_class = g_type_class_ref (class->shell_view_type);
+ shell_view_class->shell_backend = g_object_ref (shell_backend);
+ shell_backend->priv->shell_view_class = shell_view_class;
+
+ /* Determine the user data directory for this backend. */
+ shell_backend->priv->data_dir = g_build_filename (
+ e_get_user_data_dir (), class->name, NULL);
+
+ /* Determine the user configuration directory for this backend. */
+ shell_backend->priv->config_dir = g_build_filename (
+ shell_backend->priv->data_dir, "config", NULL);
+
+ /* Create the user configuration directory for this backend,
+ * which should also create the user data directory. */
+ dirname = shell_backend->priv->config_dir;
+ if (g_mkdir_with_parents (dirname, 0777) != 0)
+ g_critical (
+ "Cannot create directory %s: %s",
+ dirname, g_strerror (errno));
+}
+
+GType
+e_shell_backend_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (EShellBackendClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) shell_backend_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EShellBackend),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) shell_backend_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EShellBackend", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * e_shell_backend_compare:
+ * @shell_backend_a: an #EShellBackend
+ * @shell_backend_b: an #EShellBackend
+ *
+ * Using the <structfield>sort_order</structfield> field from both backends'
+ * #EShellBackendClass, compares @shell_backend_a with @shell_mobule_b and
+ * returns -1, 0 or +1 if @shell_backend_a is found to be less than, equal
+ * to or greater than @shell_backend_b, respectively.
+ *
+ * Returns: -1, 0 or +1, for a less than, equal to or greater than result
+ **/
+gint
+e_shell_backend_compare (EShellBackend *shell_backend_a,
+ EShellBackend *shell_backend_b)
+{
+ gint a = E_SHELL_BACKEND_GET_CLASS (shell_backend_a)->sort_order;
+ gint b = E_SHELL_BACKEND_GET_CLASS (shell_backend_b)->sort_order;
+
+ return (a < b) ? -1 : (a > b);
+}
+
+/**
+ * e_shell_backend_get_config_dir:
+ * @shell_backend: an #EShellBackend
+ *
+ * Returns the absolute path to the configuration directory for
+ * @shell_backend. The string is owned by @shell_backend and should
+ * not be modified or freed.
+ *
+ * Returns: the backend's configuration directory
+ **/
+const gchar *
+e_shell_backend_get_config_dir (EShellBackend *shell_backend)
+{
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
+ g_return_val_if_fail (shell_backend->priv->config_dir != NULL, NULL);
+
+ return shell_backend->priv->config_dir;
+}
+
+/**
+ * e_shell_backend_get_data_dir:
+ * @shell_backend: an #EShellBackend
+ *
+ * Returns the absolute path to the data directory for @shell_backend.
+ * The string is owned by @shell_backend and should not be modified or
+ * freed.
+ *
+ * Returns: the backend's data directory
+ **/
+const gchar *
+e_shell_backend_get_data_dir (EShellBackend *shell_backend)
+{
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
+ g_return_val_if_fail (shell_backend->priv->data_dir != NULL, NULL);
+
+ return shell_backend->priv->data_dir;
+}
+
+/**
+ * e_shell_backend_get_shell:
+ * @shell_backend: an #EShellBackend
+ *
+ * Returns the #EShell singleton.
+ *
+ * Returns: the #EShell
+ **/
+EShell *
+e_shell_backend_get_shell (EShellBackend *shell_backend)
+{
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
+
+ return E_SHELL (shell_backend->priv->shell);
+}
+
+/**
+ * e_shell_backend_add_activity:
+ * @shell_backend: an #EShellBackend
+ * @activity: an #EActivity
+ *
+ * Emits an #EShellBackend::activity-added signal.
+ **/
+void
+e_shell_backend_add_activity (EShellBackend *shell_backend,
+ EActivity *activity)
+{
+ g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend));
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ g_signal_emit (shell_backend, signals[ACTIVITY_ADDED], 0, activity);
+}
+
+/**
+ * e_shell_backend_start:
+ * @shell_backend: an #EShellBackend
+ *
+ * Tells the @shell_backend to begin loading data or running background
+ * tasks which may consume significant resources. This gets called in
+ * reponse to the user switching to the corresponding #EShellView for
+ * the first time. The function is idempotent for each @shell_backend.
+ **/
+void
+e_shell_backend_start (EShellBackend *shell_backend)
+{
+ EShellBackendClass *class;
+
+ g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend));
+
+ if (shell_backend->priv->started)
+ return;
+
+ class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
+
+ if (class->start != NULL)
+ class->start (shell_backend);
+
+ shell_backend->priv->started = TRUE;
+}
+
+/**
+ * e_shell_backend_is_busy:
+ * @shell_backend: an #EShellBackend
+ *
+ * Returns %TRUE if @shell_backend is busy and cannot be shutdown at
+ * present. Each backend must define what "busy" means to them and
+ * determine an appropriate response.
+ *
+ * XXX This function is likely to change or disappear. I'm toying with
+ * the idea of just having it check whether there are any unfinished
+ * #EActivity<!-- -->'s left, so we have a consistent and easily
+ * testable definition of what "busy" means.
+ *
+ * Returns: %TRUE if the backend is busy
+ **/
+gboolean
+e_shell_backend_is_busy (EShellBackend *shell_backend)
+{
+ EShellBackendClass *class;
+
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), FALSE);
+
+ class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
+
+ if (class->is_busy == NULL)
+ return FALSE;
+
+ return class->is_busy (shell_backend);
+}
+
+/**
+ * e_shell_backend_shutdown:
+ * @shell_backend: an #EShellBackend
+ *
+ * Alerts @shell_backend to begin shutdown procedures. If the backend is
+ * busy and cannot immediately shut down, the function returns %FALSE.
+ * A %TRUE response implies @shell_backend has successfully shut down.
+ *
+ * XXX This function is likely to change or disappear. I'm toying with
+ * the idea of just having it check whether there are any unfinished
+ * #EActivity<!-- -->'s left, so we have a consistent and easily
+ * testable definition of what "busy" means.
+ *
+ * Returns: %TRUE if the backend has shut down, %FALSE if the backend is
+ * busy and cannot immediately shut down
+ */
+gboolean
+e_shell_backend_shutdown (EShellBackend *shell_backend)
+{
+ EShellBackendClass *class;
+
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), TRUE);
+
+ class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
+
+ if (class->shutdown == NULL)
+ return TRUE;
+
+ return class->shutdown (shell_backend);
+}
+
+/**
+ * e_shell_migrate:
+ * @shell_backend: an #EShellBackend
+ * @major: major part of version to migrate from
+ * @minor: minor part of version to migrate from
+ * @micro: micro part of version to migrate from
+ * @error: return location for a #GError, or %NULL
+ *
+ * Attempts to migrate data and settings from version %major.%minor.%micro.
+ * Returns %TRUE if the migration was successful or if no action was
+ * necessary. Returns %FALSE and sets %error if the migration failed.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise
+ **/
+gboolean
+e_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ EShellBackendClass *class;
+
+ g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), TRUE);
+
+ class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
+
+ if (class->migrate == NULL)
+ return TRUE;
+
+ return class->migrate (shell_backend, major, minor, micro, error);
+}
diff --cc shell/e-shell-backend.h
index 570199c,0000000..57663d8
mode 100644,000000..100644
--- a/shell/e-shell-backend.h
+++ b/shell/e-shell-backend.h
@@@ -1,151 -1,0 +1,151 @@@
+/*
+ * e-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/**
+ * SECTION: e-shell-backend
+ * @short_description: dynamically loaded capabilities
+ * @include: shell/e-shell-backend.h
+ **/
+
+#ifndef E_SHELL_BACKEND_H
+#define E_SHELL_BACKEND_H
+
+#include <shell/e-shell-common.h>
+#include <widgets/misc/e-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SHELL_BACKEND \
+ (e_shell_backend_get_type ())
+#define E_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SHELL_BACKEND, EShellBackend))
+#define E_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SHELL_BACKEND, EShellBackendClass))
+#define E_IS_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SHELL_BACKEND))
+#define E_IS_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SHELL_BACKEND))
+#define E_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SHELL_BACKEND, EShellBackendClass))
+
+G_BEGIN_DECLS
+
+/* Avoid including <e-shell.h>, because it includes us! */
+struct _EShell;
+
+typedef struct _EShellBackend EShellBackend;
+typedef struct _EShellBackendClass EShellBackendClass;
+typedef struct _EShellBackendPrivate EShellBackendPrivate;
+
+/**
+ * EShellBackend:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _EShellBackend {
+ GObject parent;
+ EShellBackendPrivate *priv;
+};
+
+/**
+ * EShellBackendClass:
+ * @parent_class: The parent class structure.
+ * @name: The name of the backend. Also becomes the name of
+ * the corresponding #EShellView subclass that the
+ * backend will register.
+ * @aliases: Colon-separated list of aliases that can be used
+ * when referring to a backend by name.
+ * @schemes: Colon-separated list of URI schemes. The #EShell
+ * will forward command-line URIs to the appropriate
+ * backend based on this list.
+ * @sort_order: Used to determine the order of backends listed in
+ * the main menu and in the switcher. See
+ * e_shell_backend_compare().
+ * @shell_view_type: #GType for the corresponding #EShellView subclass.
+ * @start: Method for notifying the backend to begin loading
+ * data and running background tasks. This is called
+ * just before the first instantiation of the
+ * corresponding #EShellView subclass. It allows the
+ * backend to delay initialization steps that consume
+ * significant resources until they are actually needed.
+ * @is_busy: Method for querying whether the backend has operations
+ * in progress that cannot be cancelled or finished
+ * immediately. Returning %TRUE prevents the application
+ * from shutting down.
+ * @shutdown: Method for notifying the backend to begin shutting
+ * down. Returning %FALSE indicates there are still
+ * unfinished operations and the #EShell should check
+ * back shortly.
+ * @migrate: Method for notifying the backend to migrate data and
+ * settings from the given version. Returns %TRUE if the
+ * migration was successful or if no action was necessary.
+ * Returns %FALSE and sets a #GError if the migration
+ * failed.
+ *
+ * #EShellBackendClass contains a number of important settings for subclasses.
+ **/
+struct _EShellBackendClass {
+ GObjectClass parent_class;
+
+ GType shell_view_type;
+
+ const gchar *name;
+ const gchar *aliases;
+ const gchar *schemes;
+ gint sort_order;
+
+ /* Methods */
+ void (*start) (EShellBackend *shell_backend);
+ gboolean (*is_busy) (EShellBackend *shell_backend);
+ gboolean (*shutdown) (EShellBackend *shell_backend);
+ gboolean (*migrate) (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+};
+
+GType e_shell_backend_get_type (void);
+gint e_shell_backend_compare (EShellBackend *shell_backend_a,
+ EShellBackend *shell_backend_b);
+const gchar * e_shell_backend_get_config_dir (EShellBackend *shell_backend);
+const gchar * e_shell_backend_get_data_dir (EShellBackend *shell_backend);
+const gchar * e_shell_backend_get_filename (EShellBackend *shell_backend);
+struct _EShell *e_shell_backend_get_shell (EShellBackend *shell_backend);
+void e_shell_backend_add_activity (EShellBackend *shell_backend,
+ EActivity *activity);
+void e_shell_backend_start (EShellBackend *shell_backend);
+gboolean e_shell_backend_is_busy (EShellBackend *shell_backend);
+gboolean e_shell_backend_shutdown (EShellBackend *shell_backend);
+gboolean e_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_SHELL_BACKEND_H */
diff --cc shell/e-shell-common.h
index 50c8415,0000000..7ff3509
mode 100644,000000..100644
--- a/shell/e-shell-common.h
+++ b/shell/e-shell-common.h
@@@ -1,33 -1,0 +1,33 @@@
+/*
+ * e-shell-common.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_SHELL_COMMON_H
+#define E_SHELL_COMMON_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#endif /* E_SHELL_COMMON_H */
diff --cc shell/e-shell-content.c
index ff344ae,0000000..b557908
mode 100644,000000..100644
--- a/shell/e-shell-content.c
+++ b/shell/e-shell-content.c
@@@ -1,1384 -1,0 +1,1384 @@@
+/*
+ * e-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-content.h"
+
+#include <glib/gi18n.h>
+
+#include <filter/rule-editor.h>
+#include <widgets/misc/e-action-combo-box.h>
+#include <widgets/misc/e-icon-entry.h>
+
+#include <e-shell-backend.h>
+#include <e-shell-view.h>
+#include <e-shell-window-actions.h>
+
+#define E_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SHELL_CONTENT, EShellContentPrivate))
+
+struct _EShellContentPrivate {
+
+ gpointer shell_view; /* weak pointer */
+
+ RuleContext *search_context;
+ FilterRule *search_rule;
+ gchar *system_filename;
+ gchar *user_filename;
+
+ /* Container for the following widgets */
+ GtkWidget *search_bar;
+
+ /* Search bar widgets */
+ GtkWidget *filter_label;
+ GtkWidget *filter_combo_box;
+ GtkWidget *search_label;
+ GtkWidget *search_entry;
+ GtkWidget *scope_label;
+ GtkWidget *scope_combo_box;
+
+ GtkStateType search_state;
+};
+
+enum {
+ PROP_0,
+ PROP_FILTER_ACTION,
+ PROP_FILTER_VALUE,
+ PROP_FILTER_VISIBLE,
+ PROP_SEARCH_CONTEXT,
+ PROP_SEARCH_RULE,
+ PROP_SEARCH_TEXT,
+ PROP_SEARCH_VISIBLE,
+ PROP_SCOPE_ACTION,
+ PROP_SCOPE_VALUE,
+ PROP_SCOPE_VISIBLE,
+ PROP_SHELL_VIEW
+};
+
+static gpointer parent_class;
+
+static void
+shell_content_dialog_rule_changed (GtkWidget *dialog,
+ FilterRule *rule)
+{
+ gboolean sensitive;
+
+ sensitive = (rule != NULL) && (rule->parts != NULL);
+
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_APPLY, sensitive);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+ EShellContent *shell_content)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EIconEntry *icon_entry;
+ GtkStateType visual_state;
+ const gchar *search_text;
+
+ /* EShellView subclasses are responsible for actually
+ * executing the search. This is all cosmetic stuff. */
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ search_text = e_shell_content_get_search_text (shell_content);
+
+ if (search_text != NULL && *search_text != '\0')
+ visual_state = GTK_STATE_SELECTED;
+ else
+ visual_state = GTK_STATE_NORMAL;
+
+ e_icon_entry_set_visual_state (icon_entry, visual_state);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
+ gtk_action_set_sensitive (action, TRUE);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window);
+ gtk_action_set_sensitive (action, TRUE);
+
+ /* Direct the focus away from the search entry, so that a
+ * focus-in event is required before the text can be changed.
+ * This will reset the entry to the appropriate visual state. */
+ gtk_widget_grab_focus (gtk_bin_get_child (GTK_BIN (shell_content)));
+}
+
+static void
+shell_content_entry_activated_cb (EShellContent *shell_content,
+ GtkWidget *entry)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkAction *action;
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ /* Verify the shell view is active before proceeding. */
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+ gtk_action_activate (action);
+}
+
+static gboolean
+shell_content_entry_focus_in_cb (EShellContent *shell_content,
+ GdkEventFocus *focus_event,
+ GtkWidget *entry)
+{
+ EIconEntry *icon_entry;
+ GtkStateType visual_state;
+
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ visual_state = e_icon_entry_get_visual_state (icon_entry);
+
+ if (visual_state == GTK_STATE_INSENSITIVE)
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+
+ e_icon_entry_set_visual_state (icon_entry, GTK_STATE_NORMAL);
+
+ return FALSE;
+}
+
+static gboolean
+shell_content_entry_focus_out_cb (EShellContent *shell_content,
+ GdkEventFocus *focus_event,
+ GtkWidget *entry)
+{
+ /* FIXME */
+ return FALSE;
+}
+
+static gboolean
+shell_content_entry_key_press_cb (EShellContent *shell_content,
+ GdkEventKey *key_event,
+ GtkWidget *entry)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ guint mask;
+
+ mask = gtk_accelerator_get_default_mod_mask ();
+ if ((key_event->state & mask) != GDK_MOD1_MASK)
+ return FALSE;
+
+ if (key_event->keyval != GDK_Down)
+ return FALSE;
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
+ gtk_action_activate (action);
+
+ return TRUE;
+}
+
+static void
+shell_content_init_search_context (EShellContent *shell_content)
+{
+ EShellContentClass *shell_content_class;
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ EShellBackend *shell_backend;
+ RuleContext *context;
+ FilterRule *rule;
+ FilterPart *part;
+ gchar *system_filename;
+ gchar *user_filename;
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ g_return_if_fail (shell_view_class->search_rules != NULL);
+
+ shell_content_class = E_SHELL_CONTENT_GET_CLASS (shell_content);
+ g_return_if_fail (shell_content_class->new_search_context != NULL);
+
+ /* The basename for built-in searches is specified in the
+ * shell view class. All built-in search rules live in the
+ * same directory. */
+ system_filename = g_build_filename (
+ EVOLUTION_RULEDIR, shell_view_class->search_rules, NULL);
+
+ /* The filename for custom saved searches is always of
+ * the form "$(shell_backend_data_dir)/searches.xml". */
+ user_filename = g_build_filename (
+ e_shell_backend_get_data_dir (shell_backend),
+ "searches.xml", NULL);
+
+ context = shell_content_class->new_search_context ();
+ rule_context_add_part_set (
+ context, "partset", FILTER_TYPE_PART,
+ rule_context_add_part, rule_context_next_part);
+ rule_context_add_rule_set (
+ context, "ruleset", FILTER_TYPE_RULE,
+ rule_context_add_rule, rule_context_next_rule);
+ rule_context_load (context, system_filename, user_filename);
+
+ /* XXX Not sure why this is necessary. */
+ g_object_set_data_full (
+ G_OBJECT (context), "system",
+ g_strdup (system_filename), g_free);
+ g_object_set_data_full (
+ G_OBJECT (context), "user",
+ g_strdup (user_filename), g_free);
+
+ rule = filter_rule_new ();
+ part = rule_context_next_part (context, NULL);
+ if (part == NULL)
+ g_warning (
+ "Could not load %s search: no parts",
+ e_shell_view_get_name (shell_view));
+ else
+ filter_rule_add_part (rule, filter_part_clone (part));
+
+ shell_content->priv->search_context = context;
+ shell_content->priv->system_filename = system_filename;
+ shell_content->priv->user_filename = user_filename;
+}
+
+static void
+shell_content_set_shell_view (EShellContent *shell_content,
+ EShellView *shell_view)
+{
+ g_return_if_fail (shell_content->priv->shell_view == NULL);
+
+ shell_content->priv->shell_view = shell_view;
+
+ g_object_add_weak_pointer (
+ G_OBJECT (shell_view),
+ &shell_content->priv->shell_view);
+}
+
+static void
+shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FILTER_ACTION:
+ e_shell_content_set_filter_action (
+ E_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_FILTER_VALUE:
+ e_shell_content_set_filter_value (
+ E_SHELL_CONTENT (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_FILTER_VISIBLE:
+ e_shell_content_set_filter_visible (
+ E_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SEARCH_RULE:
+ e_shell_content_set_search_rule (
+ E_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SEARCH_TEXT:
+ e_shell_content_set_search_text (
+ E_SHELL_CONTENT (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_SEARCH_VISIBLE:
+ e_shell_content_set_search_visible (
+ E_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SCOPE_ACTION:
+ e_shell_content_set_scope_action (
+ E_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SCOPE_VALUE:
+ e_shell_content_set_scope_value (
+ E_SHELL_CONTENT (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_SCOPE_VISIBLE:
+ e_shell_content_set_scope_visible (
+ E_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SHELL_VIEW:
+ shell_content_set_shell_view (
+ E_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FILTER_ACTION:
+ g_value_set_object (
+ value, e_shell_content_get_filter_action (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_FILTER_VALUE:
+ g_value_set_int (
+ value, e_shell_content_get_filter_value (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_FILTER_VISIBLE:
+ g_value_set_boolean (
+ value, e_shell_content_get_filter_visible (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SEARCH_CONTEXT:
+ g_value_set_object (
+ value, e_shell_content_get_search_context (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SEARCH_RULE:
+ g_value_set_object (
+ value, e_shell_content_get_search_rule (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SEARCH_TEXT:
+ g_value_set_string (
+ value, e_shell_content_get_search_text (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SEARCH_VISIBLE:
+ g_value_set_boolean (
+ value, e_shell_content_get_search_visible (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SCOPE_ACTION:
+ g_value_set_object (
+ value, e_shell_content_get_scope_action (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SCOPE_VALUE:
+ g_value_set_int (
+ value, e_shell_content_get_scope_value (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SCOPE_VISIBLE:
+ g_value_set_boolean (
+ value, e_shell_content_get_scope_visible (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SHELL_VIEW:
+ g_value_set_object (
+ value, e_shell_content_get_shell_view (
+ E_SHELL_CONTENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_content_dispose (GObject *object)
+{
+ EShellContentPrivate *priv;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->shell_view != NULL) {
+ g_object_remove_weak_pointer (
+ G_OBJECT (priv->shell_view), &priv->shell_view);
+ priv->shell_view = NULL;
+ }
+
+ if (priv->filter_label != NULL) {
+ g_object_unref (priv->filter_label);
+ priv->filter_label = NULL;
+ }
+
+ if (priv->filter_combo_box != NULL) {
+ g_object_unref (priv->filter_combo_box);
+ priv->filter_combo_box = NULL;
+ }
+
+ if (priv->search_context != NULL) {
+ g_object_unref (priv->search_context);
+ priv->search_context = NULL;
+ }
+
+ if (priv->search_label != NULL) {
+ g_object_unref (priv->search_label);
+ priv->search_label = NULL;
+ }
+
+ if (priv->search_entry != NULL) {
+ g_object_unref (priv->search_entry);
+ priv->search_entry = NULL;
+ }
+
+ if (priv->scope_label != NULL) {
+ g_object_unref (priv->scope_label);
+ priv->scope_label = NULL;
+ }
+
+ if (priv->scope_combo_box != NULL) {
+ g_object_unref (priv->scope_combo_box);
+ priv->scope_combo_box = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+shell_content_finalize (GObject *object)
+{
+ EShellContentPrivate *priv;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (object);
+
+ g_free (priv->system_filename);
+ g_free (priv->user_filename);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+shell_content_constructed (GObject *object)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ EIconEntry *icon_entry;
+ GtkSizeGroup *size_group;
+ GtkAction *action;
+ GtkWidget *widget;
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ size_group = e_shell_view_get_size_group (shell_view);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
+ e_icon_entry_add_action_end (icon_entry, action);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+ g_signal_connect (
+ action, "activate",
+ G_CALLBACK (action_search_execute_cb), shell_content);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
+ e_icon_entry_add_action_start (icon_entry, action);
+
+ widget = shell_content->priv->search_bar;
+ gtk_size_group_add_widget (size_group, widget);
+
+ shell_content_init_search_context (shell_content);
+}
+
+static void
+shell_content_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ EShellContentPrivate *priv;
+ GtkRequisition child_requisition;
+ GtkWidget *child;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (widget);
+
+ requisition->width = 0;
+ requisition->height = 0;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ gtk_widget_size_request (child, requisition);
+
+ child = priv->search_bar;
+ gtk_widget_size_request (child, &child_requisition);
+ requisition->width = MAX (requisition->width, child_requisition.width);
+ requisition->height += child_requisition.height;
+}
+
+static void
+shell_content_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ EShellContentPrivate *priv;
+ GtkAllocation child_allocation;
+ GtkRequisition child_requisition;
+ GtkWidget *child;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (widget);
+
+ widget->allocation = *allocation;
+
+ child = priv->search_bar;
+ gtk_widget_size_request (child, &child_requisition);
+
+ child_allocation.x = allocation->x;
+ child_allocation.y = allocation->y;
+ child_allocation.width = allocation->width;
+ child_allocation.height = child_requisition.height;
+
+ gtk_widget_size_allocate (child, &child_allocation);
+
+ child_allocation.y += child_requisition.height;
+ child_allocation.height =
+ allocation->height - child_requisition.height;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (child != NULL)
+ gtk_widget_size_allocate (child, &child_allocation);
+}
+
+static void
+shell_content_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ EShellContentPrivate *priv;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (container);
+
+ /* Look in the internal widgets first. */
+
+ if (widget == priv->search_bar) {
+ gtk_widget_unparent (priv->search_bar);
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+ return;
+ }
+
+ /* Chain up to parent's remove() method. */
+ GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
+}
+
+static void
+shell_content_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EShellContentPrivate *priv;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (container);
+
+ if (include_internals)
+ callback (priv->search_bar, callback_data);
+
+ /* Chain up to parent's forall() method. */
+ GTK_CONTAINER_CLASS (parent_class)->forall (
+ container, include_internals, callback, callback_data);
+}
+
+static void
+shell_content_class_init (EShellContentClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkContainerClass *container_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = shell_content_set_property;
+ object_class->get_property = shell_content_get_property;
+ object_class->dispose = shell_content_dispose;
+ object_class->finalize = shell_content_finalize;
+ object_class->constructed = shell_content_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->size_request = shell_content_size_request;
+ widget_class->size_allocate = shell_content_size_allocate;
+
+ container_class = GTK_CONTAINER_CLASS (class);
+ container_class->remove = shell_content_remove;
+ container_class->forall = shell_content_forall;
+
+ class->new_search_context = rule_context_new;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILTER_ACTION,
+ g_param_spec_object (
+ "filter-action",
+ NULL,
+ NULL,
+ GTK_TYPE_RADIO_ACTION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILTER_VALUE,
+ g_param_spec_int (
+ "filter-value",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILTER_VISIBLE,
+ g_param_spec_boolean (
+ "filter-visible",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEARCH_CONTEXT,
+ g_param_spec_object (
+ "search-context",
+ NULL,
+ NULL,
+ RULE_TYPE_CONTEXT,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEARCH_RULE,
+ g_param_spec_object (
+ "search-rule",
+ NULL,
+ NULL,
+ FILTER_TYPE_RULE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEARCH_TEXT,
+ g_param_spec_string (
+ "search-text",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEARCH_VISIBLE,
+ g_param_spec_boolean (
+ "search-visible",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SCOPE_ACTION,
+ g_param_spec_object (
+ "scope-action",
+ NULL,
+ NULL,
+ GTK_TYPE_RADIO_ACTION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SCOPE_VALUE,
+ g_param_spec_int (
+ "scope-value",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SCOPE_VISIBLE,
+ g_param_spec_boolean (
+ "scope-visible",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHELL_VIEW,
+ g_param_spec_object (
+ "shell-view",
+ NULL,
+ NULL,
+ E_TYPE_SHELL_VIEW,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+shell_content_init (EShellContent *shell_content)
+{
+ GtkBox *box;
+ GtkLabel *label;
+ GtkWidget *mnemonic;
+ GtkWidget *widget;
+ EIconEntry *icon_entry;
+
+ shell_content->priv = E_SHELL_CONTENT_GET_PRIVATE (shell_content);
+
+ GTK_WIDGET_SET_FLAGS (shell_content, GTK_NO_WINDOW);
+
+ /*** Build the Search Bar ***/
+
+ widget = gtk_hbox_new (FALSE, 3);
+ gtk_widget_set_parent (widget, GTK_WIDGET (shell_content));
+ shell_content->priv->search_bar = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ box = GTK_BOX (widget);
+
+ /* Filter Combo Widgets */
+
+ /* Translators: The "Show:" label precedes a combo box that
+ * allows the user to filter the current view. Examples of
+ * items that appear in the combo box are "Unread Messages",
+ * "Important Messages", or "Active Appointments". */
+ widget = gtk_label_new_with_mnemonic (_("Sho_w:"));
+ gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->filter_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ label = GTK_LABEL (widget);
+
+ widget = e_action_combo_box_new ();
+ gtk_label_set_mnemonic_widget (label, widget);
+ gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->filter_combo_box = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Scope Combo Widgets */
+
+ widget = e_action_combo_box_new ();
+ gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->scope_combo_box = g_object_ref (widget);
- gtk_widget_show (widget);
++ gtk_widget_show (widget);
+
+ mnemonic = widget;
+
+ /* Translators: This is part of the quick search interface.
+ * example: Search: [_______________] in [ Current Folder ] */
+ widget = gtk_label_new_with_mnemonic (_("i_n"));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (widget), mnemonic);
+ gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->scope_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Search Entry Widgets */
+
+ widget = e_icon_entry_new ();
+ gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->search_entry = g_object_ref (widget);
+ shell_content->priv->search_state = GTK_STATE_NORMAL;
+ gtk_widget_show (widget);
+
+ icon_entry = E_ICON_ENTRY (widget);
+
+ /* Translators: This is part of the quick search interface.
+ * example: Search: [_______________] in [ Current Folder ] */
+ widget = gtk_label_new_with_mnemonic (_("Sear_ch:"));
+ gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->search_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ label = GTK_LABEL (widget);
+
+ widget = e_icon_entry_get_entry (icon_entry);
+ gtk_label_set_mnemonic_widget (label, widget);
+ g_signal_connect_swapped (
+ widget, "activate",
+ G_CALLBACK (shell_content_entry_activated_cb), shell_content);
+ g_signal_connect_swapped (
+ widget, "focus-in-event",
+ G_CALLBACK (shell_content_entry_focus_in_cb), shell_content);
+ g_signal_connect_swapped (
+ widget, "focus-out-event",
+ G_CALLBACK (shell_content_entry_focus_out_cb), shell_content);
+ g_signal_connect_swapped (
+ widget, "key-press-event",
+ G_CALLBACK (shell_content_entry_key_press_cb), shell_content);
+}
+
+GType
+e_shell_content_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EShellContentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) shell_content_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EShellContent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) shell_content_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_BIN, "EShellContent", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * e_shell_content_new:
+ * @shell_view: an #EShellView
+ *
+ * Creates a new #EShellContent instance belonging to @shell_view.
+ *
+ * Returns: a new #EShellContent instance
+ **/
+GtkWidget *
+e_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_SHELL_CONTENT, "shell-view", shell_view, NULL);
+}
+
+/**
+ * e_shell_content_check_state:
+ * @shell_content: an #EShellContent
+ *
+ * #EShellContent subclasses should implement the
+ * <structfield>check_state</structfield> method in #EShellContentClass
+ * to return a set of flags describing the current content selection.
+ * Subclasses are responsible for defining their own flags. This is
+ * primarily used to assist shell views with updating actions (see
+ * e_shell_view_update_actions()).
+ *
+ * Returns: a set of flags describing the current @shell_content selection
+ **/
+guint32
+e_shell_content_check_state (EShellContent *shell_content)
+{
+ EShellContentClass *shell_content_class;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
+
+ shell_content_class = E_SHELL_CONTENT_GET_CLASS (shell_content);
+ g_return_val_if_fail (shell_content_class->check_state != NULL, 0);
+
+ return shell_content_class->check_state (shell_content);
+}
+
+/**
+ * e_shell_content_get_shell_view:
+ * @shell_content: an #EShellContent
+ *
+ * Returns the #EShellView that was passed to e_shell_content_new().
+ *
+ * Returns: the #EShellView to which @shell_content belongs
+ **/
+EShellView *
+e_shell_content_get_shell_view (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ return E_SHELL_VIEW (shell_content->priv->shell_view);
+}
+
+GtkRadioAction *
+e_shell_content_get_filter_action (EShellContent *shell_content)
+{
+ EActionComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ return e_action_combo_box_get_action (combo_box);
+}
+
+void
+e_shell_content_set_filter_action (EShellContent *shell_content,
+ GtkRadioAction *filter_action)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ e_action_combo_box_set_action (combo_box, filter_action);
+ g_object_notify (G_OBJECT (shell_content), "filter-action");
+}
+
+gint
+e_shell_content_get_filter_value (EShellContent *shell_content)
+{
+ EActionComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ return e_action_combo_box_get_current_value (combo_box);
+}
+
+void
+e_shell_content_set_filter_value (EShellContent *shell_content,
+ gint filter_value)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ e_action_combo_box_set_current_value (combo_box, filter_value);
+ g_object_notify (G_OBJECT (shell_content), "filter-value");
+}
+
+gboolean
+e_shell_content_get_filter_visible (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
+
+ return GTK_WIDGET_VISIBLE (shell_content->priv->filter_combo_box);
+}
+
+void
+e_shell_content_set_filter_visible (EShellContent *shell_content,
+ gboolean filter_visible)
+{
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ if (filter_visible) {
+ gtk_widget_show (shell_content->priv->filter_label);
+ gtk_widget_show (shell_content->priv->filter_combo_box);
+ } else {
+ gtk_widget_hide (shell_content->priv->filter_label);
+ gtk_widget_hide (shell_content->priv->filter_combo_box);
+ }
+}
+
+void
+e_shell_content_add_filter_separator_before (EShellContent *shell_content,
+ gint action_value)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ e_action_combo_box_add_separator_before (combo_box, action_value);
+}
+
+void
+e_shell_content_add_filter_separator_after (EShellContent *shell_content,
+ gint action_value)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ e_action_combo_box_add_separator_after (combo_box, action_value);
+}
+
+RuleContext *
+e_shell_content_get_search_context (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ return shell_content->priv->search_context;
+}
+
+FilterRule *
+e_shell_content_get_search_rule (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ return shell_content->priv->search_rule;
+}
+
+void
+e_shell_content_set_search_rule (EShellContent *shell_content,
+ FilterRule *search_rule)
+{
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ if (search_rule != NULL) {
+ g_return_if_fail (IS_FILTER_RULE (search_rule));
+ g_object_ref (search_rule);
+ }
+
+ if (shell_content->priv->search_rule != NULL)
+ g_object_unref (shell_content->priv->search_rule);
+
+ shell_content->priv->search_rule = search_rule;
+ g_object_notify (G_OBJECT (shell_content), "search-rule");
+}
+
+const gchar *
+e_shell_content_get_search_text (EShellContent *shell_content)
+{
+ EIconEntry *icon_entry;
+ GtkWidget *text_entry;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ if (shell_content->priv->search_state == GTK_STATE_INSENSITIVE)
+ return "";
+
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ text_entry = e_icon_entry_get_entry (icon_entry);
+
+ return gtk_entry_get_text (GTK_ENTRY (text_entry));
+}
+
+void
+e_shell_content_set_search_text (EShellContent *shell_content,
+ const gchar *search_text)
+{
+ EIconEntry *icon_entry;
+ GtkWidget *text_entry;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ text_entry = e_icon_entry_get_entry (icon_entry);
+
+ search_text = (search_text != NULL) ? search_text : "";
+ gtk_entry_set_text (GTK_ENTRY (text_entry), search_text);
+ g_object_notify (G_OBJECT (shell_content), "search-text");
+}
+
+gboolean
+e_shell_content_get_search_visible (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
+
+ return GTK_WIDGET_VISIBLE (shell_content->priv->search_entry);
+}
+
+void
+e_shell_content_set_search_visible (EShellContent *shell_content,
+ gboolean search_visible)
+{
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ if (search_visible) {
+ gtk_widget_show (shell_content->priv->search_label);
+ gtk_widget_show (shell_content->priv->search_entry);
+ } else {
+ gtk_widget_hide (shell_content->priv->search_label);
+ gtk_widget_hide (shell_content->priv->search_entry);
+ }
+}
+
+GtkRadioAction *
+e_shell_content_get_scope_action (EShellContent *shell_content)
+{
+ EActionComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
+
+ return e_action_combo_box_get_action (combo_box);
+}
+
+void
+e_shell_content_set_scope_action (EShellContent *shell_content,
+ GtkRadioAction *scope_action)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
+
+ e_action_combo_box_set_action (combo_box, scope_action);
+ g_object_notify (G_OBJECT (shell_content), "scope-action");
+}
+
+gint
+e_shell_content_get_scope_value (EShellContent *shell_content)
+{
+ EActionComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
+
+ return e_action_combo_box_get_current_value (combo_box);
+}
+
+void
+e_shell_content_set_scope_value (EShellContent *shell_content,
+ gint scope_value)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
+
+ e_action_combo_box_set_current_value (combo_box, scope_value);
+ g_object_notify (G_OBJECT (shell_content), "scope-value");
+}
+
+gboolean
+e_shell_content_get_scope_visible (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
+
+ return GTK_WIDGET_VISIBLE (shell_content->priv->scope_combo_box);
+}
+
+void
+e_shell_content_set_scope_visible (EShellContent *shell_content,
+ gboolean scope_visible)
+{
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ if (scope_visible) {
+ gtk_widget_show (shell_content->priv->scope_label);
+ gtk_widget_show (shell_content->priv->scope_combo_box);
+ } else {
+ gtk_widget_hide (shell_content->priv->scope_label);
+ gtk_widget_hide (shell_content->priv->scope_combo_box);
+ }
+
+ g_object_notify (G_OBJECT (shell_content), "scope-visible");
+}
+
+void
+e_shell_content_run_advanced_search_dialog (EShellContent *shell_content)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ GtkWidget *dialog;
+ GtkWidget *widget;
+ FilterRule *rule;
+ RuleContext *context;
+ const gchar *user_filename;
+ gint response;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ user_filename = shell_content->priv->user_filename;
+
+ rule = e_shell_content_get_search_rule (shell_content);
+
+ if (rule == NULL)
+ rule = filter_rule_new ();
+ else
+ rule = filter_rule_clone (rule);
+
+ context = e_shell_content_get_search_context (shell_content);
+ widget = filter_rule_get_widget (rule, context);
+ filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
+
+ dialog = gtk_dialog_new_with_buttons (
+ _("Advanced Search"), GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_APPLY,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 7);
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 300);
+
+ gtk_box_pack_start (
+ GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 0);
+
+ g_signal_connect_swapped (
+ rule, "changed", G_CALLBACK (
+ shell_content_dialog_rule_changed), dialog);
+
+ shell_content_dialog_rule_changed (dialog, rule);
+
+run:
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
+ goto exit;
+
+ if (!filter_rule_validate (rule))
+ goto run;
+
+ e_shell_content_set_search_rule (shell_content, rule);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+ gtk_action_activate (action);
+
+ if (response == GTK_RESPONSE_APPLY) {
+ if (!rule_context_find_rule (context, rule->name, rule->source))
+ rule_context_add_rule (context, rule);
+ rule_context_save (context, user_filename);
+ goto run;
+ }
+
+exit:
+ g_object_unref (rule);
+ gtk_widget_destroy (dialog);
+}
+
+void
+e_shell_content_run_edit_searches_dialog (EShellContent *shell_content)
+{
+ RuleContext *context;
+ RuleEditor *editor;
+ const gchar *user_filename;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ context = e_shell_content_get_search_context (shell_content);
+ user_filename = shell_content->priv->user_filename;
+
+ editor = rule_editor_new (
+ context, FILTER_SOURCE_INCOMING, _("Searches"));
+ gtk_window_set_title (GTK_WINDOW (editor), _("Searches"));
+
+ if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK)
+ rule_context_save (context, user_filename);
+
+ gtk_widget_destroy (GTK_WIDGET (editor));
+}
+
+void
+e_shell_content_run_save_search_dialog (EShellContent *shell_content)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkWidget *dialog;
+ GtkWidget *widget;
+ FilterRule *rule;
+ RuleContext *context;
+ const gchar *search_text;
+ const gchar *user_filename;
+ gchar *search_name;
+ gint response;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ user_filename = shell_content->priv->user_filename;
+
+ rule = e_shell_content_get_search_rule (shell_content);
+ g_return_if_fail (IS_FILTER_RULE (rule));
+ rule = filter_rule_clone (rule);
+
+ search_text = e_shell_content_get_search_text (shell_content);
+ if (search_text == NULL || *search_text == '\0')
+ search_text = "''";
+
+ search_name = g_strdup_printf ("%s %s", rule->name, search_text);
+ filter_rule_set_name (rule, search_name);
+ g_free (search_name);
+
+ context = e_shell_content_get_search_context (shell_content);
+ widget = filter_rule_get_widget (rule, context);
+ filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
+
+ dialog = gtk_dialog_new_with_buttons (
+ _("Save Search"), GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 7);
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 300);
+
+ gtk_box_pack_start (
+ GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 0);
+
+ g_signal_connect_swapped (
+ rule, "changed", G_CALLBACK (
+ shell_content_dialog_rule_changed), dialog);
+
+ shell_content_dialog_rule_changed (dialog, rule);
+
+run:
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response != GTK_RESPONSE_OK)
+ goto exit;
+
+ if (!filter_rule_validate (rule))
+ goto run;
+
+ rule_context_add_rule (context, rule);
+ rule_context_save (context, user_filename);
+
+exit:
+ g_object_unref (rule);
+ gtk_widget_destroy (dialog);
+}
diff --cc shell/e-shell-content.h
index 0463977,0000000..2259dbd
mode 100644,000000..100644
--- a/shell/e-shell-content.h
+++ b/shell/e-shell-content.h
@@@ -1,143 -1,0 +1,143 @@@
+/*
+ * e-shell-content.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/**
+ * SECTION: e-shell-content
+ * @short_description: the right side of the main window
+ * @include: shell/e-shell-content.h
+ **/
+
+#ifndef E_SHELL_CONTENT_H
+#define E_SHELL_CONTENT_H
+
+#include <shell/e-shell-common.h>
+#include <filter/filter-rule.h>
+#include <filter/rule-context.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SHELL_CONTENT \
+ (e_shell_content_get_type ())
+#define E_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SHELL_CONTENT, EShellContent))
+#define E_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SHELL_CONTENT, EShellContentClass))
+#define E_IS_SHELL_CONTENT(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SHELL_CONTENT))
+#define E_IS_SHELL_CONTENT_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((obj), E_TYPE_SHELL_CONTENT))
+#define E_SHELL_CONTENT_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SHELL_CONTENT, EShellContentClass))
+
+G_BEGIN_DECLS
+
+/* Avoid including <e-shell-view.h>, because it includes us! */
+struct _EShellView;
+
+typedef struct _EShellContent EShellContent;
+typedef struct _EShellContentClass EShellContentClass;
+typedef struct _EShellContentPrivate EShellContentPrivate;
+
+/**
+ * EShellContent:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _EShellContent {
+ GtkBin parent;
+ EShellContentPrivate *priv;
+};
+
+struct _EShellContentClass {
+ GtkBinClass parent_class;
+
+ /* Factory Methods */
+ RuleContext * (*new_search_context) (void);
+
+ guint32 (*check_state) (EShellContent *shell_content);
+};
+
+GType e_shell_content_get_type (void);
+GtkWidget * e_shell_content_new (struct _EShellView *shell_view);
+guint32 e_shell_content_check_state (EShellContent *shell_content);
+struct _EShellView *
+ e_shell_content_get_shell_view (EShellContent *shell_content);
+GtkRadioAction *e_shell_content_get_filter_action
+ (EShellContent *shell_content);
+void e_shell_content_set_filter_action
+ (EShellContent *shell_content,
+ GtkRadioAction *filter_action);
+gint e_shell_content_get_filter_value(EShellContent *shell_content);
+void e_shell_content_set_filter_value(EShellContent *shell_content,
+ gint filter_value);
+gboolean e_shell_content_get_filter_visible
+ (EShellContent *shell_content);
+void e_shell_content_set_filter_visible
+ (EShellContent *shell_content,
+ gboolean filter_visible);
+void e_shell_content_add_filter_separator_before
+ (EShellContent *shell_content,
+ gint action_value);
+void e_shell_content_add_filter_separator_after
+ (EShellContent *shell_content,
+ gint action_value);
+RuleContext * e_shell_content_get_search_context
+ (EShellContent *shell_content);
+FilterRule * e_shell_content_get_search_rule (EShellContent *shell_content);
+void e_shell_content_set_search_rule (EShellContent *shell_content,
+ FilterRule *search_rule);
+const gchar * e_shell_content_get_search_text (EShellContent *shell_content);
+void e_shell_content_set_search_text (EShellContent *shell_content,
+ const gchar *search_text);
+gboolean e_shell_content_get_search_visible
+ (EShellContent *shell_content);
+void e_shell_content_set_search_visible
+ (EShellContent *shell_content,
+ gboolean search_visible);
+GtkRadioAction *e_shell_content_get_scope_action(EShellContent *shell_content);
+void e_shell_content_set_scope_action(EShellContent *shell_content,
+ GtkRadioAction *scope_action);
+gint e_shell_content_get_scope_value (EShellContent *shell_content);
+void e_shell_content_set_scope_value (EShellContent *shell_content,
+ gint scope_value);
+gboolean e_shell_content_get_scope_visible
+ (EShellContent *shell_content);
+void e_shell_content_set_scope_visible
+ (EShellContent *shell_content,
+ gboolean scope_visible);
+const gchar * e_shell_content_get_view_id (EShellContent *shell_content);
+void e_shell_content_set_view_id (EShellContent *shell_content,
+ const gchar *view_id);
+void e_shell_content_run_advanced_search_dialog
+ (EShellContent *shell_content);
+void e_shell_content_run_edit_searches_dialog
+ (EShellContent *shell_content);
+void e_shell_content_run_save_search_dialog
+ (EShellContent *shell_content);
+
+G_END_DECLS
+
+#endif /* E_SHELL_CONTENT_H */
diff --cc shell/e-shell-migrate.c
index b141ba4,0000000..53df410
mode 100644,000000..100644
--- a/shell/e-shell-migrate.c
+++ b/shell/e-shell-migrate.c
@@@ -1,335 -1,0 +1,335 @@@
+/*
+ * e-shell-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-migrate.h"
+
+#include <string.h>
+#include <unistd.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <libedataserver/e-xml-utils.h>
+
+#include "e-util/e-bconf-map.h"
+#include "e-util/e-error.h"
+#include "e-util/e-fsutils.h"
+#include "e-util/e-util.h"
+
+#define GCONF_VERSION_KEY "/apps/evolution/version"
+#define GCONF_LAST_VERSION_KEY "/apps/evolution/last_version"
+
+static const gchar *
+shell_migrate_get_old_data_dir (void)
+{
+ static gchar *old_data_dir = NULL;
+
+ if (G_UNLIKELY (old_data_dir == NULL))
+ old_data_dir = g_build_filename (
+ g_get_home_dir (), "evolution", NULL);
+
+ return old_data_dir;
+}
+
+static gboolean
+shell_migrate_attempt (EShell *shell,
+ gint major,
+ gint minor,
+ gint micro)
+{
+ GList *backends;
+ gboolean success = TRUE;
+
+ backends = e_shell_get_shell_backends (shell);
+
+ while (success && backends != NULL) {
+ EShellBackend *shell_backend = backends->data;
+ GError *error = NULL;
+
+ success = e_shell_backend_migrate (
+ shell_backend, major, minor, micro, &error);
+
+ if (error != NULL) {
+ gint response;
+
+ response = e_error_run (
+ NULL, "shell:upgrade-failed",
+ error->message, NULL);
+
+ if (response == GTK_RESPONSE_CANCEL)
+ success = FALSE;
+
+ g_error_free (error);
+ }
+
+ backends = g_list_next (backends);
+ }
+
+ return success;
+}
+
+static void
+shell_migrate_get_version (EShell *shell,
+ gint *major,
+ gint *minor,
+ gint *micro)
+{
+ GConfClient *client;
+ const gchar *key;
+ const gchar *old_data_dir;
+ gchar *string;
+
+ old_data_dir = shell_migrate_get_old_data_dir ();
+
+ key = GCONF_VERSION_KEY;
+ client = e_shell_get_gconf_client (shell);
+ string = gconf_client_get_string (client, key, NULL);
+
+ if (string != NULL) {
+ /* Since 1.4.0 we've kept the version key in GConf. */
+ sscanf (string, "%d.%d.%d", major, minor, micro);
+ g_free (string);
+
+ } else if (!g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) {
+ /* If the old data directory does not exist,
+ * it must be a new installation. */
+ *major = 0;
+ *minor = 0;
+ *micro = 0;
+
+ } else {
+ xmlDocPtr doc;
+ xmlNodePtr source;
+ gchar *filename;
+
+ filename = g_build_filename (
+ old_data_dir, "config.xmldb", NULL);
+ doc = e_xml_parse_file (filename);
+ g_free (filename);
+
+ if (doc == NULL)
+ return;
+
+ source = e_bconf_get_path (doc, "/Shell");
+ if (source != NULL) {
+ key = "upgrade_from_1_0_to_1_2_performed";
+ string = e_bconf_get_value (source, key);
+ }
+
+ if (string != NULL && *string == '1') {
+ *major = 1;
+ *minor = 2;
+ *micro = 0;
+ } else {
+ *major = 1;
+ *minor = 0;
+ *micro = 0;
+ }
+
+ g_free (string);
+
+ if (doc != NULL)
+ xmlFreeDoc (doc);
+ }
+}
+
+static gint
+shell_migrate_remove_dir (const gchar *root,
+ const gchar *path)
+{
+ GDir *dir;
+ const gchar *basename;
+ gchar *filename;
+ gint result = -1;
+
+ /* Recursively removes a directory and its contents. */
+
+ dir = g_dir_open (path, 0, NULL);
+ if (dir == NULL)
+ return -1;
+
+ while ((basename = g_dir_read_name (dir)) != NULL) {
+ filename = g_build_filename (path, basename, NULL);
+
+ /* Make sure we haven't strayed from the evolution dir. */
+ g_return_val_if_fail (strlen (path) >= strlen (root), -1);
+ g_return_val_if_fail (g_str_has_prefix (path, root), -1);
+
+ if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
+ if (shell_migrate_remove_dir (root, filename) < 0)
+ goto fail;
+ } else {
+ if (g_unlink (filename) < 0)
+ goto fail;
+ }
+
+ g_free (filename);
+ filename = NULL;
+ }
+
+ result = g_rmdir (path);
+
+fail:
+ g_free (filename);
+ g_dir_close (dir);
+
+ return result;
+}
+
+gboolean
+e_shell_migrate_attempt (EShell *shell)
+{
+ GConfClient *client;
+ const gchar *key;
+ const gchar *old_data_dir;
+ gint major, minor, micro;
+ gint last_major, last_minor, last_micro;
+ gint curr_major, curr_minor, curr_micro;
+ gboolean migrated = FALSE;
+ gchar *string;
+
+ g_return_val_if_fail (E_IS_SHELL (shell), FALSE);
+
+ client = e_shell_get_gconf_client (shell);
+ old_data_dir = shell_migrate_get_old_data_dir ();
+
+ if (sscanf (BASE_VERSION, "%d.%d", &curr_major, &curr_minor) != 2) {
+ g_warning ("Could not parse BASE_VERSION (%s)", BASE_VERSION);
+ return TRUE;
+ }
+
+ curr_micro = atoi (UPGRADE_REVISION);
+
+ shell_migrate_get_version (shell, &major, &minor, µ);
+
+ if (!(curr_major > major ||
+ (curr_major == major && curr_minor > minor) ||
+ (curr_minor == minor && curr_micro > micro)))
+ goto check_old;
+
+ /* If upgrading from < 1.5, we need to copy most data from
+ * ~/evolution to ~/.evolution. Make sure we have the disk
+ * space for it before proceeding. */
+ if (major == 1 && minor < 5) {
+ glong avail;
+ glong usage;
+
+ usage = e_fsutils_usage (old_data_dir);
+ avail = e_fsutils_avail (g_get_home_dir ());
+ if (usage >= 0 && avail >= 0 && avail < usage) {
+ gchar *need;
+ gchar *have;
+
+ need = g_strdup_printf (_("%ld KB"), usage);
+ have = g_strdup_printf (_("%ld KB"), avail);
+
+ e_error_run (
+ NULL, "shell:upgrade-nospace",
+ need, have, NULL);
+
+ g_free (need);
+ g_free (have);
+
+ _exit (EXIT_SUCCESS);
+ }
+ }
+
+ if (!shell_migrate_attempt (shell, major, minor, micro))
+ _exit (EXIT_SUCCESS);
+
+ /* Record a successful migration. */
+ string = g_strdup_printf ("%d.%d.%d", major, minor, micro);
+ gconf_client_set_string (client, GCONF_VERSION_KEY, string, NULL);
+ g_free (string);
+
+ migrated = TRUE;
+
+check_old:
+
+ key = GCONF_LAST_VERSION_KEY;
+
+ /* Try to retrieve the last migrated version from GConf. */
+ string = gconf_client_get_string (client, key, NULL);
+ if (migrated || string == NULL || sscanf (string, "%d.%d.%d",
+ &last_major, &last_minor, &last_micro) != 3) {
+ last_major = major;
+ last_minor = minor;
+ last_micro = micro;
+ }
+ g_free (string);
+
+ /* If the last migrated version was old, check for stuff to remove. */
+ if (last_major == 1 && last_minor < 5 &&
+ g_file_test (old_data_dir, G_FILE_TEST_IS_DIR)) {
+
+ gint response;
+
+ string = g_strdup_printf (
+ "%d.%d.%d", last_major, last_minor, last_micro);
+ response = e_error_run (
+ NULL, "shel:upgrade-remove-1-4", string, NULL);
+ g_free (string);
+
+ switch (response) {
+ case GTK_RESPONSE_OK: /* delete */
+ response = e_error_run (
+ NULL,
+ "shell:upgrade-remove-1-4-confirm",
+ NULL);
+ if (response == GTK_RESPONSE_OK)
+ shell_migrate_remove_dir (
+ old_data_dir, old_data_dir);
+ else
+ break;
+ /* fall through */
+
+ case GTK_RESPONSE_ACCEPT: /* keep */
+ last_major = curr_major;
+ last_minor = curr_minor;
+ last_micro = curr_micro;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ last_major = curr_major;
+ last_minor = curr_minor;
+ last_micro = curr_micro;
+ }
+
+ string = g_strdup_printf (
+ "%d.%d.%d", last_major, last_minor, last_micro);
+ gconf_client_set_string (client, key, string, NULL);
+ g_free (string);
+
+ return TRUE;
+}
+
+GQuark
+e_shell_migrate_error_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (quark == 0))
+ quark = g_quark_from_static_string (
+ "e-shell-migrate-error-quark");
+
+ return quark;
+}
diff --cc shell/e-shell-migrate.h
index 45907ce,0000000..8ebe697
mode 100644,000000..100644
--- a/shell/e-shell-migrate.h
+++ b/shell/e-shell-migrate.h
@@@ -1,52 -1,0 +1,52 @@@
+/*
+ * e-shell-migrate.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* This is an EShell extension that handles migrating from older versions. */
+
+#ifndef E_SHELL_MIGRATE_H
+#define E_SHELL_MIGRATE_H
+
+#include <shell/e-shell-common.h>
+#include <shell/e-shell.h>
+
+/**
+ * E_SHELL_MIGRATE_ERROR:
+ *
+ * Error domain for migration operations. Errors in this domain will be
+ * from the #EShellMigrateError enumeration. See #GError for information
+ * on error domains.
+ **/
+#define E_SHELL_MIGRATE_ERROR \
+ (e_shell_migrate_error_quark ())
+
+G_BEGIN_DECLS
+
+/* XXX Need more specific error codes? */
+typedef enum {
+ E_SHELL_MIGRATE_ERROR_FAILED
+} EShellMigrateError;
+
+gboolean e_shell_migrate_attempt (EShell *shell);
+GQuark e_shell_migrate_error_quark (void);
+
+G_END_DECLS
+
+#endif /* E_SHELL_MIGRATE_H */
diff --cc shell/e-shell-settings.c
index 9f03f38,0000000..0883382
mode 100644,000000..100644
--- a/shell/e-shell-settings.c
+++ b/shell/e-shell-settings.c
@@@ -1,559 -1,0 +1,559 @@@
+/*
+ * e-shell-settings.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-settings.h"
+
+#include "e-util/gconf-bridge.h"
+
+#define E_SHELL_SETTINGS_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SHELL_SETTINGS, EShellSettingsPrivate))
+
+struct _EShellSettingsPrivate {
+ GArray *value_array;
+ guint debug : 1;
+};
+
+static GList *instances;
+static guint property_count;
+static gpointer parent_class;
+
+static void
+shell_settings_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EShellSettingsPrivate *priv;
+ GValue *dest_value;
+
+ priv = E_SHELL_SETTINGS_GET_PRIVATE (object);
+
+ dest_value = &g_array_index (
+ priv->value_array, GValue, property_id - 1);
+
+ g_value_copy (value, dest_value);
+ g_object_notify (object, pspec->name);
+
+ if (priv->debug) {
+ gchar *contents;
+
+ contents = g_strdup_value_contents (value);
+ g_debug (
+ "Setting '%s' set to '%s' (%s)",
+ pspec->name, contents, G_VALUE_TYPE_NAME (value));
+ g_free (contents);
+ }
+}
+
+static void
+shell_settings_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EShellSettingsPrivate *priv;
+ GValue *src_value;
+
+ priv = E_SHELL_SETTINGS_GET_PRIVATE (object);
+
+ src_value = &g_array_index (
+ priv->value_array, GValue, property_id - 1);
+
+ g_value_copy (src_value, value);
+}
+
+static void
+shell_settings_finalize (GObject *object)
+{
+ EShellSettingsPrivate *priv;
+ guint ii;
+
+ priv = E_SHELL_SETTINGS_GET_PRIVATE (object);
+
+ for (ii = 0; ii < priv->value_array->len; ii++)
+ g_value_unset (&g_array_index (priv->value_array, GValue, ii));
+
+ g_array_free (priv->value_array, TRUE);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+shell_settings_class_init (EShellSettingsClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EShellSettingsPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = shell_settings_set_property;
+ object_class->get_property = shell_settings_get_property;
+ object_class->finalize = shell_settings_finalize;
+}
+
+static void
+shell_settings_init (EShellSettings *shell_settings,
+ GObjectClass *object_class)
+{
+ GArray *value_array;
+ GParamSpec **pspecs;
+ guint ii;
+
+ instances = g_list_prepend (instances, shell_settings);
+
+ value_array = g_array_new (FALSE, TRUE, sizeof (GValue));
+ g_array_set_size (value_array, property_count);
+
+ shell_settings->priv = E_SHELL_SETTINGS_GET_PRIVATE (shell_settings);
+ shell_settings->priv->value_array = value_array;
+
+ g_object_freeze_notify (G_OBJECT (shell_settings));
+
+ pspecs = g_object_class_list_properties (object_class, NULL);
+ for (ii = 0; ii < property_count; ii++) {
+ GParamSpec *pspec = pspecs[ii];
+ GValue *value;
+
+ value = &g_array_index (value_array, GValue, ii);
+ g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+ g_param_value_set_default (pspec, value);
+ g_object_notify (G_OBJECT (shell_settings), pspec->name);
+ }
+ g_free (pspecs);
+
+ g_object_thaw_notify (G_OBJECT (shell_settings));
+}
+
+GType
+e_shell_settings_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (EShellSettingsClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) shell_settings_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EShellSettings),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) shell_settings_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EShellSettings", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * e_shell_settings_install_property:
+ * @pspec: a #GParamSpec
+ *
+ * Installs a new class property for #EShellSettings. This is usually
+ * done during initialization of a #EShellBackend or plugin, followed by
+ * a call to e_shell_settings_bind_to_gconf() to bind the property to a
+ * GConf key.
+ **/
+void
+e_shell_settings_install_property (GParamSpec *pspec)
+{
+ static GObjectClass *class = NULL;
+ GList *iter, *next;
+
+ g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+
+ if (G_UNLIKELY (class == NULL))
+ class = g_type_class_ref (E_TYPE_SHELL_SETTINGS);
+
+ if (g_object_class_find_property (class, pspec->name) != NULL) {
+ g_warning (
+ "Settings property \"%s\" already exists",
+ pspec->name);
+ return;
+ }
+
+ for (iter = instances; iter != NULL; iter = iter->next)
+ g_object_freeze_notify (iter->data);
+
+ g_object_class_install_property (class, ++property_count, pspec);
+
+ for (iter = instances; iter != NULL; iter = iter->next) {
+ EShellSettings *shell_settings = iter->data;
+ GArray *value_array;
+ GValue *value;
+
+ value_array = shell_settings->priv->value_array;
+ g_array_set_size (value_array, property_count);
+
+ value = &g_array_index (
+ value_array, GValue, property_count - 1);
+ g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+ g_param_value_set_default (pspec, value);
+ g_object_notify (G_OBJECT (shell_settings), pspec->name);
+ }
+
+ for (iter = instances; iter != NULL; iter = next) {
+ next = iter->next;
+ g_object_thaw_notify (iter->data);
+ }
+}
+
+/**
+ * e_shell_settings_bind_to_gconf:
+ * @shell_settings: an #EShellSettings
+ * @property_name: the name of the property to bind
+ * @gconf_key: the GConf key to bind the property to
+ *
+ * Binds @property_name to @gconf_key, causing them to have the same value
+ * at all times.
+ *
+ * The types of @property_name and @gconf_key should be compatible. Floats
+ * and doubles, and ints, uints, longs, unlongs, int64s, uint64s, chars,
+ * uchars and enums can be matched up. Booleans and strings can only be
+ * matched to their respective types.
+ *
+ * On calling this function, @property_name is initialized to the current
+ * value of @gconf_key.
+ **/
+void
+e_shell_settings_bind_to_gconf (EShellSettings *shell_settings,
+ const gchar *property_name,
+ const gchar *gconf_key)
+{
+ g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
+ g_return_if_fail (property_name != NULL);
+ g_return_if_fail (gconf_key != NULL);
+
+ gconf_bridge_bind_property (
+ gconf_bridge_get (), gconf_key,
+ G_OBJECT (shell_settings), property_name);
+}
+
+/**
+ * e_shell_settings_enable_debug:
+ * @shell_settings: an #EShellSettings
+ *
+ * Print a debug message to standard output when a property value changes.
+ **/
+void
+e_shell_settings_enable_debug (EShellSettings *shell_settings)
+{
+ g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
+
+ shell_settings->priv->debug = TRUE;
+}
+
+/**
+ * e_shell_settings_get_boolean:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ *
+ * Return the contents of an #EShellSettings property of type
+ * #G_TYPE_BOOLEAN.
+ *
+ * Returns: boolean contents of @property_name
+ **/
+gboolean
+e_shell_settings_get_boolean (EShellSettings *shell_settings,
+ const gchar *property_name)
+{
+ GObject *object;
+ GValue value = { 0, };
+ gboolean v_boolean;
+
+ g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), FALSE);
+ g_return_val_if_fail (property_name != NULL, FALSE);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_BOOLEAN);
+ g_object_get_property (object, property_name, &value);
+ v_boolean = g_value_get_boolean (&value);
+ g_value_unset (&value);
+
+ return v_boolean;
+}
+
+/**
+ * e_shell_settings_set_boolean:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ * @v_boolean: boolean value to be set
+ *
+ * Sets the contents of an #EShellSettings property of type #G_TYPE_BOOLEAN
+ * to @v_boolean. If @property_name is bound to a GConf key, the GConf key
+ * will also be set to @v_boolean.
+ **/
+void
+e_shell_settings_set_boolean (EShellSettings *shell_settings,
+ const gchar *property_name,
+ gboolean v_boolean)
+{
+ GObject *object;
+ GValue value = { 0, };
+
+ g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
+ g_return_if_fail (property_name != NULL);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&value, v_boolean);
+ g_object_set_property (object, property_name, &value);
+ g_value_unset (&value);
+}
+
+/**
+ * e_shell_settings_get_int:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ *
+ * Returns the contents of an #EShellSettings property of type
+ * #G_TYPE_INT.
+ *
+ * Returns: integer contents of @property_name
+ **/
+gint
+e_shell_settings_get_int (EShellSettings *shell_settings,
+ const gchar *property_name)
+{
+ GObject *object;
+ GValue value = { 0, };
+ gint v_int;
+
+ g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), 0);
+ g_return_val_if_fail (property_name != NULL, 0);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_INT);
+ g_object_get_property (object, property_name, &value);
+ v_int = g_value_get_int (&value);
+ g_value_unset (&value);
+
+ return v_int;
+}
+
+/**
+ * e_shell_settings_set_int:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ * @v_int: integer value to be set
+ *
+ * Sets the contents of an #EShellSettings property of type #G_TYPE_INT
+ * to @v_int. If @property_name is bound to a GConf key, the GConf key
+ * will also be set to @v_int.
+ **/
+void
+e_shell_settings_set_int (EShellSettings *shell_settings,
+ const gchar *property_name,
+ gint v_int)
+{
+ GObject *object;
+ GValue value = { 0, };
+
+ g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
+ g_return_if_fail (property_name != NULL);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_INT);
+ g_value_set_int (&value, v_int);
+ g_object_set_property (object, property_name, &value);
+ g_value_unset (&value);
+}
+
+/**
+ * e_shell_settings_get_string:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ *
+ * Returns the contents of an #EShellSettings property of type
+ * #G_TYPE_STRING. The returned string should be freed using g_free().
+ *
+ * Returns: string contents of @property_name
+ **/
+gchar *
+e_shell_settings_get_string (EShellSettings *shell_settings,
+ const gchar *property_name)
+{
+ GObject *object;
+ GValue value = { 0, };
+ gchar *v_string;
+
+ g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_STRING);
+ g_object_get_property (object, property_name, &value);
+ v_string = g_value_dup_string (&value);
+ g_value_unset (&value);
+
+ return v_string;
+}
+
+/**
+ * e_shell_settings_set_string:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ * @v_string: string to be set
+ *
+ * Sets the contents of an #EShellSettings property of type #G_TYPE_STRING
+ * to @v_string. If @property_name is bound to a GConf key, the GConf key
+ * will also be set to @v_string.
+ **/
+void
+e_shell_settings_set_string (EShellSettings *shell_settings,
+ const gchar *property_name,
+ const gchar *v_string)
+{
+ GObject *object;
+ GValue value = { 0, };
+
+ g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
+ g_return_if_fail (property_name != NULL);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_set_string (&value, v_string);
+ g_object_set_property (object, property_name, &value);
+ g_value_unset (&value);
+}
+
+/**
+ * e_shell_settings_get_object:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ *
+ * Returns the contents of an #EShellSettings property of type
+ * #G_TYPE_OBJECT. The caller owns the reference to the returned
+ * object, and should call g_object_unref() when finished with it.
+ *
+ * Returns: a new reference to the object under @property_name
+ **/
+gpointer
+e_shell_settings_get_object (EShellSettings *shell_settings,
+ const gchar *property_name)
+{
+ GObject *object;
+ GValue value = { 0, };
+ gpointer v_object;
+
+ g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_OBJECT);
+ g_object_get_property (object, property_name, &value);
+ v_object = g_value_dup_object (&value);
+ g_value_unset (&value);
+
+ return v_object;
+}
+
+/**
+ * e_shell_settings_set_object:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ * @v_object: object to be set
+ *
+ * Sets the contents of an #EShellSettings property of type #G_TYPE_OBJECT
+ * to @v_object.
+ **/
+void
+e_shell_settings_set_object (EShellSettings *shell_settings,
+ const gchar *property_name,
+ gpointer v_object)
+{
+ GObject *object;
+ GValue value = { 0, };
+
+ g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
+ g_return_if_fail (property_name != NULL);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_OBJECT);
+ g_value_set_object (&value, v_object);
+ g_object_set_property (object, property_name, &value);
+ g_value_unset (&value);
+}
+
+/**
+ * e_shell_settings_get_pointer:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ *
+ * Returns the contents of an #EShellSettings property of type
+ * #G_TYPE_POINTER.
+ *
+ * Returns: pointer contents of @property_name
+ **/
+gpointer
+e_shell_settings_get_pointer (EShellSettings *shell_settings,
+ const gchar *property_name)
+{
+ GObject *object;
+ GValue value = { 0, };
+ gpointer v_pointer;
+
+ g_return_val_if_fail (E_IS_SHELL_SETTINGS (shell_settings), NULL);
+ g_return_val_if_fail (property_name != NULL, NULL);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_POINTER);
+ g_object_get_property (object, property_name, &value);
+ v_pointer = g_value_get_pointer (&value);
+ g_value_unset (&value);
+
+ return v_pointer;
+}
+
+/**
+ * e_shell_settings_set_pointer:
+ * @shell_settings: an #EShellSettings
+ * @property_name: an installed property name
+ * @v_pointer: pointer to be set
+ *
+ * Sets the contents of an #EShellSettings property of type #G_TYPE_POINTER
+ * to @v_pointer.
+ **/
+void
+e_shell_settings_set_pointer (EShellSettings *shell_settings,
+ const gchar *property_name,
+ gpointer v_pointer)
+{
+ GObject *object;
+ GValue value = { 0, };
+
+ g_return_if_fail (E_IS_SHELL_SETTINGS (shell_settings));
+ g_return_if_fail (property_name != NULL);
+
+ object = G_OBJECT (shell_settings);
+ g_value_init (&value, G_TYPE_POINTER);
+ g_value_set_pointer (&value, v_pointer);
+ g_object_set_property (object, property_name, &value);
+ g_value_unset (&value);
+}
diff --cc shell/e-shell-settings.h
index a9f6a20,0000000..c400fac
mode 100644,000000..100644
--- a/shell/e-shell-settings.h
+++ b/shell/e-shell-settings.h
@@@ -1,114 -1,0 +1,114 @@@
+/*
+ * e-shell-settings.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/**
+ * SECTION: e-shell-settings
+ * @short_description: settings management
+ * @include: shell/e-shell-settings.h
+ **/
+
+#ifndef E_SHELL_SETTINGS_H
+#define E_SHELL_SETTINGS_H
+
+#include <shell/e-shell-common.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SHELL_SETTINGS \
+ (e_shell_settings_get_type ())
+#define E_SHELL_SETTINGS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SHELL_SETTINGS, EShellSettings))
+#define E_SHELL_SETTINGS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SHELL_SETTINGS, EShellSettingsClass))
+#define E_IS_SHELL_SETTINGS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SHELL_SETTINGS))
+#define E_IS_SHELL_SETTINGS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SHELL_SETTINGS))
+#define E_SHELL_SETTINGS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SHELL_SETTINGS, EShellSettingsClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EShellSettings EShellSettings;
+typedef struct _EShellSettingsClass EShellSettingsClass;
+typedef struct _EShellSettingsPrivate EShellSettingsPrivate;
+
+/**
+ * EShellSettings:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _EShellSettings {
+ GObject parent;
+ EShellSettingsPrivate *priv;
+};
+
+struct _EShellSettingsClass {
+ GObjectClass parent_class;
+};
+
+GType e_shell_settings_get_type (void);
+void e_shell_settings_install_property
+ (GParamSpec *pspec);
+void e_shell_settings_bind_to_gconf (EShellSettings *shell_settings,
+ const gchar *property_name,
+ const gchar *gconf_key);
+void e_shell_settings_enable_debug (EShellSettings *shell_settings);
+
+/* Getters and setters for common EShellSettings property types.
+ * These are more convenient than g_object_get() / g_object_set().
+ * Add more types as needed. If GObject ever adds similar functions,
+ * kill these. */
+
+gboolean e_shell_settings_get_boolean (EShellSettings *shell_settings,
+ const gchar *property_name);
+void e_shell_settings_set_boolean (EShellSettings *shell_settings,
+ const gchar *property_name,
+ gboolean v_boolean);
+gint e_shell_settings_get_int (EShellSettings *shell_settings,
+ const gchar *property_name);
+void e_shell_settings_set_int (EShellSettings *shell_settings,
+ const gchar *property_name,
+ gint v_int);
+gchar * e_shell_settings_get_string (EShellSettings *shell_settings,
+ const gchar *property_name);
+void e_shell_settings_set_string (EShellSettings *shell_settings,
+ const gchar *property_name,
+ const gchar *v_string);
+gpointer e_shell_settings_get_object (EShellSettings *shell_settings,
+ const gchar *property_name);
+void e_shell_settings_set_object (EShellSettings *shell_settings,
+ const gchar *property_name,
+ gpointer v_object);
+gpointer e_shell_settings_get_pointer (EShellSettings *shell_setting,
+ const gchar *property_name);
+void e_shell_settings_set_pointer (EShellSettings *shell_setting,
+ const gchar *property_name,
+ gpointer v_pointer);
+
+G_END_DECLS
+
+#endif /* E_SHELL_SETTINGS_H */
diff --cc shell/e-shell-sidebar.c
index 671bcad,0000000..ad4cb92
mode 100644,000000..100644
--- a/shell/e-shell-sidebar.c
+++ b/shell/e-shell-sidebar.c
@@@ -1,681 -1,0 +1,681 @@@
+/*
+ * e-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-sidebar.h"
+
+#include <e-shell-view.h>
+
+#define E_SHELL_SIDEBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SHELL_SIDEBAR, EShellSidebarPrivate))
+
+struct _EShellSidebarPrivate {
+
+ gpointer shell_view; /* weak pointer */
+
+ GtkWidget *event_box;
+ GtkWidget *image;
+ GtkWidget *primary_label;
+ GtkWidget *secondary_label;
+ gchar *primary_text;
+ gchar *secondary_text;
+};
+
+enum {
+ PROP_0,
+ PROP_ICON_NAME,
+ PROP_PRIMARY_TEXT,
+ PROP_SECONDARY_TEXT,
+ PROP_SHELL_VIEW
+};
+
+static gpointer parent_class;
+
+static void
+shell_sidebar_set_shell_view (EShellSidebar *shell_sidebar,
+ EShellView *shell_view)
+{
+ g_return_if_fail (shell_sidebar->priv->shell_view == NULL);
+
+ shell_sidebar->priv->shell_view = shell_view;
+
+ g_object_add_weak_pointer (
+ G_OBJECT (shell_view),
+ &shell_sidebar->priv->shell_view);
+}
+
+static void
+shell_sidebar_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ICON_NAME:
+ e_shell_sidebar_set_icon_name (
+ E_SHELL_SIDEBAR (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_PRIMARY_TEXT:
+ e_shell_sidebar_set_primary_text (
+ E_SHELL_SIDEBAR (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_SECONDARY_TEXT:
+ e_shell_sidebar_set_secondary_text (
+ E_SHELL_SIDEBAR (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_SHELL_VIEW:
+ shell_sidebar_set_shell_view (
+ E_SHELL_SIDEBAR (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_sidebar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ICON_NAME:
+ g_value_set_string (
+ value, e_shell_sidebar_get_icon_name (
+ E_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_PRIMARY_TEXT:
+ g_value_set_string (
+ value, e_shell_sidebar_get_primary_text (
+ E_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_SECONDARY_TEXT:
+ g_value_set_string (
+ value, e_shell_sidebar_get_secondary_text (
+ E_SHELL_SIDEBAR (object)));
+ return;
+
+ case PROP_SHELL_VIEW:
+ g_value_set_object (
+ value, e_shell_sidebar_get_shell_view (
+ E_SHELL_SIDEBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_sidebar_dispose (GObject *object)
+{
+ EShellSidebarPrivate *priv;
+
+ priv = E_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ if (priv->shell_view != NULL) {
+ g_object_remove_weak_pointer (
+ G_OBJECT (priv->shell_view), &priv->shell_view);
+ priv->shell_view = NULL;
+ }
+
+ if (priv->image != NULL) {
+ g_object_unref (priv->image);
+ priv->image = NULL;
+ }
+
+ if (priv->event_box != NULL) {
+ g_object_unref (priv->event_box);
+ priv->event_box = NULL;
+ }
+
+ if (priv->primary_label != NULL) {
+ g_object_unref (priv->primary_label);
+ priv->primary_label = NULL;
+ }
+
+ if (priv->secondary_label != NULL) {
+ g_object_unref (priv->secondary_label);
+ priv->secondary_label = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+shell_sidebar_finalize (GObject *object)
+{
+ EShellSidebarPrivate *priv;
+
+ priv = E_SHELL_SIDEBAR_GET_PRIVATE (object);
+
+ g_free (priv->primary_text);
+ g_free (priv->secondary_text);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+shell_sidebar_constructed (GObject *object)
+{
+ EShellView *shell_view;
+ EShellSidebar *shell_sidebar;
+ GtkSizeGroup *size_group;
+ GtkAction *action;
+ GtkWidget *container;
+ 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);
+
+ widget = shell_sidebar->priv->event_box;
+ gtk_size_group_add_widget (size_group, widget);
+
+ container = widget;
+
+ widget = gtk_hbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_image_new ();
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ shell_sidebar->priv->image = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new (NULL);
+ gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ shell_sidebar->priv->primary_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ shell_sidebar->priv->secondary_label = g_object_ref (widget);
+ gtk_widget_show (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);
+}
+
+static void
+shell_sidebar_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ EShellSidebarPrivate *priv;
+ GtkRequisition child_requisition;
+ GtkWidget *child;
+
+ priv = E_SHELL_SIDEBAR_GET_PRIVATE (widget);
+
+ requisition->width = 0;
+ requisition->height = 0;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ gtk_widget_size_request (child, requisition);
+
+ child = priv->event_box;
+ gtk_widget_size_request (child, &child_requisition);
+ requisition->width = MAX (requisition->width, child_requisition.width);
+ requisition->height += child_requisition.height;
+}
+
+static void
+shell_sidebar_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ EShellSidebarPrivate *priv;
+ GtkAllocation child_allocation;
+ GtkRequisition child_requisition;
+ GtkWidget *child;
+
+ priv = E_SHELL_SIDEBAR_GET_PRIVATE (widget);
+
+ widget->allocation = *allocation;
+
+ child = priv->event_box;
+ gtk_widget_size_request (child, &child_requisition);
+
+ child_allocation.x = allocation->x;
+ child_allocation.y = allocation->y;
+ child_allocation.width = allocation->width;
+ child_allocation.height = child_requisition.height;
+
+ gtk_widget_size_allocate (child, &child_allocation);
+
+ child_allocation.y += child_requisition.height;
+ child_allocation.height =
+ allocation->height - child_requisition.height;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (child != NULL)
+ gtk_widget_size_allocate (child, &child_allocation);
+}
+
+static void
+shell_sidebar_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ EShellSidebarPrivate *priv;
+
+ priv = E_SHELL_SIDEBAR_GET_PRIVATE (container);
+
+ /* Look in the internal widgets first. */
+
+ if (widget == priv->event_box) {
+ gtk_widget_unparent (priv->event_box);
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+ return;
+ }
+
+ /* Chain up to parent's remove() method. */
+ GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
+}
+
+static void
+shell_sidebar_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EShellSidebarPrivate *priv;
+
+ priv = E_SHELL_SIDEBAR_GET_PRIVATE (container);
+
+ if (include_internals)
+ callback (priv->event_box, callback_data);
+
+ /* Chain up to parent's forall() method. */
+ GTK_CONTAINER_CLASS (parent_class)->forall (
+ container, include_internals, callback, callback_data);
+}
+
+static void
+shell_sidebar_class_init (EShellSidebarClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkContainerClass *container_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EShellSidebarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = shell_sidebar_set_property;
+ object_class->get_property = shell_sidebar_get_property;
+ object_class->dispose = shell_sidebar_dispose;
+ object_class->finalize = shell_sidebar_finalize;
+ object_class->constructed = shell_sidebar_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->size_request = shell_sidebar_size_request;
+ widget_class->size_allocate = shell_sidebar_size_allocate;
+
+ container_class = GTK_CONTAINER_CLASS (class);
+ container_class->remove = shell_sidebar_remove;
+ container_class->forall = shell_sidebar_forall;
+
+ /**
+ * EShellSidebar:icon-name
+ *
+ * The named icon is displayed at the top of the sidebar.
+ */
+ g_object_class_install_property (
+ object_class,
+ PROP_ICON_NAME,
+ g_param_spec_string (
+ "icon-name",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * EShellSidebar:primary-text
+ *
+ * The primary text is displayed in bold at the top of the sidebar.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_PRIMARY_TEXT,
+ g_param_spec_string (
+ "primary-text",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * EShellSidebar:secondary-text
+ *
+ * The secondary text is displayed in a smaller font at the top of
+ * the sidebar.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_SECONDARY_TEXT,
+ g_param_spec_string (
+ "secondary-text",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ /**
+ * EShellSidebar:shell-view
+ *
+ * The #EShellView to which the sidebar widget belongs.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_SHELL_VIEW,
+ g_param_spec_object (
+ "shell-view",
+ NULL,
+ NULL,
+ E_TYPE_SHELL_VIEW,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+shell_sidebar_init (EShellSidebar *shell_sidebar)
+{
+ GtkStyle *style;
+ GtkWidget *widget;
+ const GdkColor *color;
+
+ shell_sidebar->priv = E_SHELL_SIDEBAR_GET_PRIVATE (shell_sidebar);
+
+ GTK_WIDGET_SET_FLAGS (shell_sidebar, GTK_NO_WINDOW);
+
+ widget = gtk_event_box_new ();
+ style = gtk_widget_get_style (widget);
+ color = &style->bg[GTK_STATE_ACTIVE];
+ gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, color);
+ gtk_widget_set_parent (widget, GTK_WIDGET (shell_sidebar));
+ shell_sidebar->priv->event_box = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Finish initialization once we have a shell view. */
+}
+
+GType
+e_shell_sidebar_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EShellSidebarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) shell_sidebar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EShellSidebar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) shell_sidebar_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_BIN, "EShellSidebar", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * e_shell_sidebar_new:
+ * @shell_view: an #EShellView
+ *
+ * Creates a new #EShellSidebar instance belonging to @shell_view.
+ *
+ * Returns: a new #EShellSidebar instance
+ **/
+GtkWidget *
+e_shell_sidebar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_SHELL_SIDEBAR,
+ "shell-view", shell_view, NULL);
+}
+
+/**
+ * e_shell_sidebar_check_state:
+ * @shell_sidebar: an #EShellSidebar
+ *
+ * #EShellSidebar subclasses should implement the
+ * <structfield>check_state</structfield> method in #EShellSidebarClass
+ * to return a set of flags describing the current sidebar selection.
+ * Subclasses are responsible for defining their own flags. This is
+ * primarily used to assist shell views with updating actions (see
+ * e_shell_view_update_actions()).
+ *
+ * Returns: a set of flags describing the current @shell_sidebar selection
+ **/
+guint32
+e_shell_sidebar_check_state (EShellSidebar *shell_sidebar)
+{
+ EShellSidebarClass *shell_sidebar_class;
+
+ g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), 0);
+
+ shell_sidebar_class = E_SHELL_SIDEBAR_GET_CLASS (shell_sidebar);
+ g_return_val_if_fail (shell_sidebar_class->check_state != NULL, 0);
+
+ return shell_sidebar_class->check_state (shell_sidebar);
+}
+
+/**
+ * e_shell_sidebar_get_shell_view:
+ * @shell_sidebar: an #EShellSidebar
+ *
+ * Returns the #EShellView that was passed to e_shell_sidebar_new().
+ *
+ * Returns: the #EShellView to which @shell_sidebar belongs
+ **/
+EShellView *
+e_shell_sidebar_get_shell_view (EShellSidebar *shell_sidebar)
+{
+ g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), NULL);
+
+ return E_SHELL_VIEW (shell_sidebar->priv->shell_view);
+}
+
+/**
+ * e_shell_sidebar_get_icon_name:
+ * @shell_sidebar: an #EShellSidebar
+ *
+ * Returns the icon name displayed at the top of the sidebar.
+ *
+ * Returns: the icon name for @shell_sidebar
+ **/
+const gchar *
+e_shell_sidebar_get_icon_name (EShellSidebar *shell_sidebar)
+{
+ GtkImage *image;
+ const gchar *icon_name;
+
+ g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), NULL);
+
+ image = GTK_IMAGE (shell_sidebar->priv->image);
+ gtk_image_get_icon_name (image, &icon_name, NULL);
+
+ return icon_name;
+}
+
+/**
+ * e_shell_sidebar_set_icon_name:
+ *
+ * Sets the icon name displayed at the top of the sidebar.
+ **/
+void
+e_shell_sidebar_set_icon_name (EShellSidebar *shell_sidebar,
+ const gchar *icon_name)
+{
+ GtkImage *image;
+
+ g_return_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar));
+
+ image = GTK_IMAGE (shell_sidebar->priv->image);
+ gtk_image_set_from_icon_name (image, icon_name, GTK_ICON_SIZE_MENU);
+
+ g_object_notify (G_OBJECT (shell_sidebar), "icon-name");
+}
+
+/**
+ * e_shell_sidebar_get_primary_text:
+ * @shell_sidebar: an #EShellSidebar
+ *
+ * Returns the primary text for @shell_sidebar.
+ *
+ * The primary text is displayed in bold at the top of the sidebar. It
+ * defaults to the shell view's label (as seen on the switcher button),
+ * but typically shows the name of the selected item in the sidebar.
+ *
+ * Returns: the primary text for @shell_sidebar
+ **/
+const gchar *
+e_shell_sidebar_get_primary_text (EShellSidebar *shell_sidebar)
+{
+ g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), NULL);
+
+ return shell_sidebar->priv->primary_text;
+}
+
+/**
+ * e_shell_sidebar_set_primary_text:
+ * @shell_sidebar: an #EShellSidebar
+ * @primary_text: text to be displayed in a bold font
+ *
+ * Sets the primary text for @shell_sidebar.
+ *
+ * The primary text is displayed in bold at the top of the sidebar. It
+ * defaults to the shell view's label (as seen on the switcher button),
+ * but typically shows the name of the selected item in the sidebar.
+ **/
+void
+e_shell_sidebar_set_primary_text (EShellSidebar *shell_sidebar,
+ const gchar *primary_text)
+{
+ GtkLabel *label;
+ gchar *markup;
+
+ g_return_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar));
+
+ g_free (shell_sidebar->priv->primary_text);
+ shell_sidebar->priv->primary_text = g_strdup (primary_text);
+
+ if (primary_text == NULL)
+ primary_text = "";
+
+ label = GTK_LABEL (shell_sidebar->priv->primary_label);
+ markup = g_markup_printf_escaped ("<b>%s</b>", primary_text);
+ gtk_label_set_markup (label, markup);
+ g_free (markup);
+
+ gtk_widget_queue_resize (GTK_WIDGET (shell_sidebar));
+ g_object_notify (G_OBJECT (shell_sidebar), "primary-text");
+}
+
+/**
+ * e_shell_sidebar_get_secondary_text:
+ * @shell_sidebar: an #EShellSidebar
+ *
+ * Returns the secondary text for @shell_sidebar.
+ *
+ * The secondary text is displayed in a smaller font at the top of the
+ * sidebar. It typically shows information about the contents of the
+ * selected sidebar item, such as total number of items, number of
+ * selected items, etc.
+ *
+ * Returns: the secondary text for @shell_sidebar
- **/
++ **/
+const gchar *
+e_shell_sidebar_get_secondary_text (EShellSidebar *shell_sidebar)
+{
+ g_return_val_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar), NULL);
+
+ return shell_sidebar->priv->secondary_text;
+}
+
+/**
+ * e_shell_sidebar_set_secondary_text:
+ * @shell_sidebar: an #EShellSidebar
+ * @secondary_text: text to be displayed in a smaller font
+ *
+ * Sets the secondary text for @shell_sidebar.
+ *
+ * The secondary text is displayed in a smaller font at the top of the
+ * sidebar. It typically shows information about the contents of the
+ * selected sidebar item, such as total number of items, number of
+ * selected items, etc.
+ **/
+void
+e_shell_sidebar_set_secondary_text (EShellSidebar *shell_sidebar,
+ const gchar *secondary_text)
+{
+ GtkLabel *label;
+ gchar *markup;
+
+ g_return_if_fail (E_IS_SHELL_SIDEBAR (shell_sidebar));
+
+ g_free (shell_sidebar->priv->secondary_text);
+ shell_sidebar->priv->secondary_text = g_strdup (secondary_text);
+
+ if (secondary_text == NULL)
+ secondary_text = "";
+
+ label = GTK_LABEL (shell_sidebar->priv->secondary_label);
+ markup = g_markup_printf_escaped ("<small>%s</small>", secondary_text);
+ gtk_label_set_markup (label, markup);
+ g_free (markup);
+
+ gtk_widget_queue_resize (GTK_WIDGET (shell_sidebar));
+ g_object_notify (G_OBJECT (shell_sidebar), "secondary-text");
+}
diff --cc shell/e-shell-sidebar.h
index 27966e5,0000000..5999aa9
mode 100644,000000..100644
--- a/shell/e-shell-sidebar.h
+++ b/shell/e-shell-sidebar.h
@@@ -1,97 -1,0 +1,97 @@@
+/*
+ * e-shell-sidebar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/**
+ * SECTION: e-shell-sidebar
+ * @short_description: the left side of the main window
+ * @include: shell/e-shell-sidebar.h
+ **/
+
+#ifndef E_SHELL_SIDEBAR_H
+#define E_SHELL_SIDEBAR_H
+
+#include <shell/e-shell-common.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SHELL_SIDEBAR \
+ (e_shell_sidebar_get_type ())
+#define E_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SHELL_SIDEBAR, EShellSidebar))
+#define E_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SHELL_SIDEBAR, EShellSidebarClass))
+#define E_IS_SHELL_SIDEBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SHELL_SIDEBAR))
+#define E_IS_SHELL_SIDEBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((obj), E_TYPE_SHELL_SIDEBAR))
+#define E_SHELL_SIDEBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SHELL_SIDEBAR, EShellSidebarClass))
+
+G_BEGIN_DECLS
+
+/* Avoid including <e-shell-view.h>, because it includes us! */
+struct _EShellView;
+
+typedef struct _EShellSidebar EShellSidebar;
+typedef struct _EShellSidebarClass EShellSidebarClass;
+typedef struct _EShellSidebarPrivate EShellSidebarPrivate;
+
+/**
+ * EShellSidebar:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _EShellSidebar {
+ GtkBin parent;
+ EShellSidebarPrivate *priv;
+};
+
+struct _EShellSidebarClass {
+ GtkBinClass parent_class;
+
+ guint32 (*check_state) (EShellSidebar *shell_sidebar);
+};
+
+GType e_shell_sidebar_get_type (void);
+GtkWidget * e_shell_sidebar_new (struct _EShellView *shell_view);
+guint32 e_shell_sidebar_check_state (EShellSidebar *shell_sidebar);
+struct _EShellView *
+ e_shell_sidebar_get_shell_view (EShellSidebar *shell_sidebar);
+const gchar * e_shell_sidebar_get_icon_name (EShellSidebar *shell_sidebar);
+void e_shell_sidebar_set_icon_name (EShellSidebar *shell_sidebar,
+ const gchar *icon_name);
+const gchar * e_shell_sidebar_get_primary_text(EShellSidebar *shell_sidebar);
+void e_shell_sidebar_set_primary_text(EShellSidebar *shell_sidebar,
+ const gchar *primary_text);
+const gchar * e_shell_sidebar_get_secondary_text
+ (EShellSidebar *shell_sidebar);
+void e_shell_sidebar_set_secondary_text
+ (EShellSidebar *shell_sidebar,
+ const gchar *secondary_text);
+
+G_END_DECLS
+
+#endif /* E_SHELL_SIDEBAR_H */
diff --cc shell/e-shell-switcher.c
index 2980bd9,0000000..2944aac
mode 100644,000000..100644
--- a/shell/e-shell-switcher.c
+++ b/shell/e-shell-switcher.c
@@@ -1,700 -1,0 +1,700 @@@
+/*
+ * e-shell-switcher.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-switcher.h"
+
+#include <glib/gi18n.h>
+
+#define E_SHELL_SWITCHER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SHELL_SWITCHER, EShellSwitcherPrivate))
+
+#define H_PADDING 6
+#define V_PADDING 6
+
+struct _EShellSwitcherPrivate {
+ GList *proxies;
+ gboolean style_set;
+ GtkToolbarStyle style;
+ GtkSettings *settings;
+ gulong settings_handler_id;
+ gboolean toolbar_visible;
+};
+
+enum {
+ PROP_0,
+ PROP_TOOLBAR_STYLE,
+ PROP_TOOLBAR_VISIBLE
+};
+
+enum {
+ STYLE_CHANGED,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static gint
+shell_switcher_layout_actions (EShellSwitcher *switcher)
+{
+ GtkAllocation *allocation;
+ int num_btns = g_list_length (switcher->priv->proxies), btns_per_row;
+ GList **rows, *p;
+ gboolean icons_only;
+ gint row_number;
+ gint max_width = 0;
+ gint max_height = 0;
+ gint row_last;
+ gint x, y;
+ gint i;
+
+ allocation = >K_WIDGET (switcher)->allocation;
+ y = allocation->y + allocation->height;
+
+ if (num_btns == 0)
+ return allocation->height;
+
+ icons_only = (switcher->priv->style == GTK_TOOLBAR_ICONS);
+
+ /* Figure out the max width and height. */
+ for (p = switcher->priv->proxies; p != NULL; p = p->next) {
+ GtkWidget *widget = p->data;
+ GtkRequisition requisition;
+
+ gtk_widget_size_request (widget, &requisition);
+ max_height = MAX (max_height, requisition.height);
+ max_width = MAX (max_width, requisition.width);
+ }
+
+ /* Figure out how many rows and columns we'll use. */
+ btns_per_row = MAX (1, allocation->width / (max_width + H_PADDING));
+ if (!icons_only) {
+ /* If using text buttons, we want to try to have a
+ * completely filled-in grid, but if we can't, we want
+ * the odd row to have just a single button. */
+ while (num_btns % btns_per_row > 1)
+ btns_per_row--;
+ }
+
+ /* Assign buttons to rows. */
+ rows = g_new0 (GList *, num_btns / btns_per_row + 1);
+
+ if (!icons_only && num_btns % btns_per_row != 0) {
+ rows[0] = g_list_append (rows[0], switcher->priv->proxies->data);
+
+ p = switcher->priv->proxies->next;
+ row_number = p ? 1 : 0;
+ } else {
+ p = switcher->priv->proxies;
+ row_number = 0;
+ }
+
+ for (; p != NULL; p = p->next) {
+ GtkWidget *widget = p->data;
+
+ if (g_list_length (rows[row_number]) == btns_per_row)
+ row_number++;
+
+ rows[row_number] = g_list_append (rows[row_number], widget);
+ }
+
+ row_last = row_number;
+
+ /* Layout the buttons. */
+ for (i = row_last; i >= 0; i--) {
+ int len, extra_width;
+
+ x = H_PADDING + allocation->x;
+ y -= max_height;
+ len = g_list_length (rows[i]);
+ if (!icons_only)
+ extra_width = (allocation->width - (len * max_width ) - (len * H_PADDING)) / len;
+ else
+ extra_width = 0;
+ for (p = rows [i]; p != NULL; p = p->next) {
+ GtkAllocation child_allocation;
+
+ child_allocation.x = x;
+ child_allocation.y = y;
+ child_allocation.width = max_width + extra_width;
+ child_allocation.height = max_height;
+
+ gtk_widget_size_allocate (GTK_WIDGET (p->data), &child_allocation);
+
+ x += child_allocation.width + H_PADDING;
+ }
+
+ y -= V_PADDING;
+ }
+
+ for (i = 0; i <= row_last; i ++)
+ g_list_free (rows [i]);
+ g_free (rows);
+
+ return y - allocation->y;
+}
+
+static void
+shell_switcher_toolbar_style_changed_cb (EShellSwitcher *switcher)
+{
+ if (!switcher->priv->style_set) {
+ switcher->priv->style_set = TRUE;
+ e_shell_switcher_unset_style (switcher);
+ }
+}
+
+static void
+shell_switcher_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_TOOLBAR_STYLE:
+ e_shell_switcher_set_style (
+ E_SHELL_SWITCHER (object),
+ g_value_get_enum (value));
+ return;
+
+ case PROP_TOOLBAR_VISIBLE:
+ e_shell_switcher_set_visible (
+ E_SHELL_SWITCHER (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_switcher_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_TOOLBAR_STYLE:
+ g_value_set_enum (
+ value, e_shell_switcher_get_style (
+ E_SHELL_SWITCHER (object)));
+ return;
+
+ case PROP_TOOLBAR_VISIBLE:
+ g_value_set_boolean (
+ value, e_shell_switcher_get_visible (
+ E_SHELL_SWITCHER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_switcher_dispose (GObject *object)
+{
+ EShellSwitcherPrivate *priv;
+
+ priv = E_SHELL_SWITCHER_GET_PRIVATE (object);
+
+ while (priv->proxies != NULL) {
+ GtkWidget *widget = priv->proxies->data;
+ gtk_container_remove (GTK_CONTAINER (object), widget);
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+shell_switcher_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ EShellSwitcherPrivate *priv;
+ GtkWidget *child;
+ GList *iter;
+
+ priv = E_SHELL_SWITCHER_GET_PRIVATE (widget);
+
+ requisition->width = 0;
+ requisition->height = 0;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (child != NULL)
+ gtk_widget_size_request (child, requisition);
+
+ if (!priv->toolbar_visible)
+ return;
+
+ for (iter = priv->proxies; iter != NULL; iter = iter->next) {
+ GtkWidget *widget = iter->data;
+ GtkRequisition child_requisition;
+
+ gtk_widget_size_request (widget, &child_requisition);
+
+ child_requisition.width += H_PADDING;
+ child_requisition.height += V_PADDING;
+
+ requisition->width = MAX (
+ requisition->width, child_requisition.width);
+ requisition->height += child_requisition.height;
+ }
+}
+
+static void
+shell_switcher_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ EShellSwitcher *switcher;
+ GtkAllocation child_allocation;
+ GtkWidget *child;
+ gint height;
+
+ switcher = E_SHELL_SWITCHER (widget);
+
+ widget->allocation = *allocation;
+
+ if (switcher->priv->toolbar_visible)
+ height = shell_switcher_layout_actions (switcher);
+ else
+ height = allocation->height;
+
+ child_allocation.x = allocation->x;
+ child_allocation.y = allocation->y;
+ child_allocation.width = allocation->width;
+ child_allocation.height = height;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (child != NULL)
+ gtk_widget_size_allocate (child, &child_allocation);
+}
+
+static void
+shell_switcher_screen_changed (GtkWidget *widget,
+ GdkScreen *previous_screen)
+{
+ EShellSwitcherPrivate *priv;
+ GtkSettings *settings;
+
+ priv = E_SHELL_SWITCHER_GET_PRIVATE (widget);
+
+ if (gtk_widget_has_screen (widget))
+ settings = gtk_widget_get_settings (widget);
+ else
+ settings = NULL;
+
+ if (settings == priv->settings)
+ return;
+
+ if (priv->settings != NULL) {
+ g_signal_handler_disconnect (
+ priv->settings, priv->settings_handler_id);
+ g_object_unref (priv->settings);
+ }
+
+ if (settings != NULL) {
+ priv->settings = g_object_ref (settings);
+ priv->settings_handler_id = g_signal_connect_swapped (
+ settings, "notify::gtk-toolbar-style",
+ G_CALLBACK (shell_switcher_toolbar_style_changed_cb),
+ widget);
+ } else
+ priv->settings = NULL;
+
+ shell_switcher_toolbar_style_changed_cb (E_SHELL_SWITCHER (widget));
+}
+
+static void
+shell_switcher_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ EShellSwitcherPrivate *priv;
+ GList *link;
+
+ priv = E_SHELL_SWITCHER_GET_PRIVATE (container);
+
+ /* Look in the internal widgets first. */
+
+ link = g_list_find (priv->proxies, widget);
+ if (link != NULL) {
+ GtkWidget *widget = link->data;
+
+ gtk_widget_unparent (widget);
+ priv->proxies = g_list_delete_link (priv->proxies, link);
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+ return;
+ }
+
+ /* Chain up to parent's remove() method. */
+ GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
+}
+
+static void
+shell_switcher_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EShellSwitcherPrivate *priv;
+
+ priv = E_SHELL_SWITCHER_GET_PRIVATE (container);
+
+ if (include_internals)
+ g_list_foreach (
+ priv->proxies, (GFunc) callback, callback_data);
+
+ /* Chain up to parent's forall() method. */
+ GTK_CONTAINER_CLASS (parent_class)->forall (
+ container, include_internals, callback, callback_data);
+}
+
+static void
+shell_switcher_style_changed (EShellSwitcher *switcher,
+ GtkToolbarStyle style)
+{
+ if (switcher->priv->style == style)
+ return;
+
+ switcher->priv->style = style;
+
+ g_list_foreach (
+ switcher->priv->proxies,
+ (GFunc) gtk_tool_item_toolbar_reconfigured, NULL);
+
+ gtk_widget_queue_resize (GTK_WIDGET (switcher));
+ g_object_notify (G_OBJECT (switcher), "toolbar-style");
+}
+
+static GtkIconSize
+shell_switcher_get_icon_size (GtkToolShell *shell)
+{
+ return GTK_ICON_SIZE_LARGE_TOOLBAR;
+}
+
+static GtkOrientation
+shell_switcher_get_orientation (GtkToolShell *shell)
+{
+ return GTK_ORIENTATION_HORIZONTAL;
+}
+
+static GtkToolbarStyle
+shell_switcher_get_style (GtkToolShell *shell)
+{
+ return e_shell_switcher_get_style (E_SHELL_SWITCHER (shell));
+}
+
+static GtkReliefStyle
+shell_switcher_get_relief_style (GtkToolShell *shell)
+{
+ return GTK_RELIEF_NORMAL;
+}
+
+static void
+shell_switcher_class_init (EShellSwitcherClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkContainerClass *container_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EShellSwitcherPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = shell_switcher_set_property;
+ object_class->get_property = shell_switcher_get_property;
+ object_class->dispose = shell_switcher_dispose;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->size_request = shell_switcher_size_request;
+ widget_class->size_allocate = shell_switcher_size_allocate;
+ widget_class->screen_changed = shell_switcher_screen_changed;
+
+ container_class = GTK_CONTAINER_CLASS (class);
+ container_class->remove = shell_switcher_remove;
+ container_class->forall = shell_switcher_forall;
+
+ class->style_changed = shell_switcher_style_changed;
+
+ /**
+ * EShellSwitcher:toolbar-style
+ *
+ * The switcher's toolbar style.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_TOOLBAR_STYLE,
+ g_param_spec_enum (
+ "toolbar-style",
+ _("Toolbar Style"),
+ _("The switcher's toolbar style"),
+ GTK_TYPE_TOOLBAR_STYLE,
+ E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ /**
+ * EShellSwitcher:toolbar-visible
+ *
+ * Whether the switcher is visible.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_TOOLBAR_VISIBLE,
+ g_param_spec_boolean (
+ "toolbar-visible",
+ _("Toolbar Visible"),
+ _("Whether the switcher is visible"),
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ /**
+ * EShellSwitcher::style-changed
+ * @switcher: the #EShellSwitcher which emitted the signal
+ * @style: the new #GtkToolbarStyle of the switcher
+ *
+ * Emitted when the style of the switcher changes.
+ **/
+ signals[STYLE_CHANGED] = g_signal_new (
+ "style-changed",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (EShellSwitcherClass, style_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_TOOLBAR_STYLE);
+}
+
+static void
+shell_switcher_init (EShellSwitcher *switcher)
+{
+ switcher->priv = E_SHELL_SWITCHER_GET_PRIVATE (switcher);
+
+ GTK_WIDGET_SET_FLAGS (switcher, GTK_NO_WINDOW);
+}
+
+static void
+shell_switcher_tool_shell_iface_init (GtkToolShellIface *iface)
+{
+ iface->get_icon_size = shell_switcher_get_icon_size;
+ iface->get_orientation = shell_switcher_get_orientation;
+ iface->get_style = shell_switcher_get_style;
+ iface->get_relief_style = shell_switcher_get_relief_style;
+}
+
+GType
+e_shell_switcher_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EShellSwitcherClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) shell_switcher_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EShellSwitcher),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) shell_switcher_init,
+ NULL /* value_table */
+ };
+
+ static const GInterfaceInfo tool_shell_info = {
+ (GInterfaceInitFunc) shell_switcher_tool_shell_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_BIN, "EShellSwitcher", &type_info, 0);
+
+ g_type_add_interface_static (
+ type, GTK_TYPE_TOOL_SHELL, &tool_shell_info);
+ }
+
+ return type;
+}
+
+/**
+ * e_shell_switcher_new:
+ *
+ * Creates a new #EShellSwitcher instance.
+ *
+ * Returns: a new #EShellSwitcher instance
+ **/
+GtkWidget *
+e_shell_switcher_new (void)
+{
+ return g_object_new (E_TYPE_SHELL_SWITCHER, NULL);
+}
+
+/**
+ * e_shell_switcher_add_action:
+ * @switcher: an #EShellSwitcher
+ * @action: a #GtkAction
+ *
+ * Adds a button to @switcher that proxies for @action. Switcher buttons
+ * appear in the order they were added.
+ *
+ * #EShellWindow adds switcher actions in the order given by the
+ * <structfield>sort_order</structfield> field in #EShellBackendClass.
+ **/
+void
+e_shell_switcher_add_action (EShellSwitcher *switcher,
+ GtkAction *action)
+{
+ GtkWidget *widget;
+
+ g_return_if_fail (E_IS_SHELL_SWITCHER (switcher));
+ g_return_if_fail (GTK_IS_ACTION (action));
+
+ g_object_ref (action);
+ widget = gtk_action_create_tool_item (action);
+ gtk_tool_item_set_is_important (GTK_TOOL_ITEM (widget), TRUE);
+ gtk_widget_show (widget);
+
+ switcher->priv->proxies = g_list_append (
+ switcher->priv->proxies, widget);
+
+ gtk_widget_set_parent (widget, GTK_WIDGET (switcher));
+ gtk_widget_queue_resize (GTK_WIDGET (switcher));
+}
+
+/**
+ * e_shell_switcher_get_style:
+ * @switcher: an #EShellSwitcher
+ *
+ * Returns whether @switcher has text, icons or both.
+ *
+ * Returns: the current style of @shell
+ **/
+GtkToolbarStyle
+e_shell_switcher_get_style (EShellSwitcher *switcher)
+{
+ g_return_val_if_fail (
+ E_IS_SHELL_SWITCHER (switcher),
+ E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE);
+
+ return switcher->priv->style;
+}
+
+/**
+ * e_shell_switcher_set_style:
+ * @switcher: an #EShellSwitcher
+ * @style: the new style for @switcher
+ *
+ * Alters the view of @switcher to display either icons only, text only,
+ * or both.
+ **/
+void
+e_shell_switcher_set_style (EShellSwitcher *switcher,
+ GtkToolbarStyle style)
+{
+ g_return_if_fail (E_IS_SHELL_SWITCHER (switcher));
+
+ switcher->priv->style_set = TRUE;
+ g_signal_emit (switcher, signals[STYLE_CHANGED], 0, style);
+}
+
+/**
+ * e_shell_switcher_unset_style:
+ * @switcher: an #EShellSwitcher
+ *
+ * Unsets a switcher style set with e_shell_switcher_set_style(), so
+ * that user preferences will be used to determine the switcher style.
+ **/
+void
+e_shell_switcher_unset_style (EShellSwitcher *switcher)
+{
+ GtkSettings *settings;
+ GtkToolbarStyle style;
+
+ g_return_if_fail (E_IS_SHELL_SWITCHER (switcher));
+
+ if (!switcher->priv->style_set)
+ return;
+
+ settings = switcher->priv->settings;
+ if (settings != NULL)
+ g_object_get (settings, "gtk-toolbar-style", &style, NULL);
+ else
+ style = E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE;
+
+ if (style == GTK_TOOLBAR_BOTH)
+ style = GTK_TOOLBAR_BOTH_HORIZ;
+
+ if (style != switcher->priv->style)
+ g_signal_emit (switcher, signals[STYLE_CHANGED], 0, style);
+
+ switcher->priv->style_set = FALSE;
+}
+
+/**
+ * e_shell_switcher_get_visible:
+ * @switcher: an #EShellSwitcher
+ *
+ * Returns %TRUE if the switcher buttons are visible.
+ *
+ * Note that switcher button visibility is different than
+ * @switcher<!-- -->'s GTK_VISIBLE flag, since #EShellSwitcher
+ * is actually a container widget for #EShellSidebar.
+ *
+ * Returns: %TRUE if the switcher buttons are visible
+ **/
+gboolean
+e_shell_switcher_get_visible (EShellSwitcher *switcher)
+{
+ g_return_val_if_fail (E_IS_SHELL_SWITCHER (switcher), FALSE);
+
+ return switcher->priv->toolbar_visible;
+}
+
+/**
+ * e_shell_switcher_set_visible:
+ * @switcher: an #EShellSwitcher
+ * @visible: whether the switcher buttons should be visible
+ *
+ * Sets the switcher button visiblity to @visible.
+ *
+ * Note that switcher button visibility is different than
+ * @switcher<!-- -->'s GTK_VISIBLE flag, since #EShellSwitcher
+ * is actually a container widget for #EShellSidebar.
+ **/
+void
+e_shell_switcher_set_visible (EShellSwitcher *switcher,
+ gboolean visible)
+{
+ GList *iter;
+
+ g_return_if_fail (E_IS_SHELL_SWITCHER (switcher));
+
+ switcher->priv->toolbar_visible = visible;
+
+ for (iter = switcher->priv->proxies; iter != NULL; iter = iter->next)
+ g_object_set (iter->data, "visible", visible, NULL);
+
+ gtk_widget_queue_resize (GTK_WIDGET (switcher));
+
+ g_object_notify (G_OBJECT (switcher), "toolbar-visible");
+}
diff --cc shell/e-shell-switcher.h
index f04cec1,0000000..1cc6445
mode 100644,000000..100644
--- a/shell/e-shell-switcher.h
+++ b/shell/e-shell-switcher.h
@@@ -1,92 -1,0 +1,92 @@@
+/*
+ * e-shell-switcher.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/**
+ * SECTION: e-shell-switcher
+ * @short_description: buttons for switching views
+ * @include: shell/e-shell-switcher.h
+ **/
+
+#ifndef E_SHELL_SWITCHER_H
+#define E_SHELL_SWITCHER_H
+
+#include <e-shell-common.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SHELL_SWITCHER \
+ (e_shell_switcher_get_type ())
+#define E_SHELL_SWITCHER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SHELL_SWITCHER, EShellSwitcher))
+#define E_SHELL_SWITCHER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SHELL_SWITCHER, EShellSwitcherClass))
+#define E_IS_SHELL_SWITCHER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SHELL_SWITCHER))
+#define E_IS_SHELL_SWITCHER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((obj), E_TYPE_SHELL_SWITCHER))
+#define E_SHELL_SWITCHER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SHELL_SWITCHER, EShellSwitcherClass))
+
+#define E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH_HORIZ
+
+G_BEGIN_DECLS
+
+typedef struct _EShellSwitcher EShellSwitcher;
+typedef struct _EShellSwitcherClass EShellSwitcherClass;
+typedef struct _EShellSwitcherPrivate EShellSwitcherPrivate;
+
+/**
+ * EShellSwitcher:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _EShellSwitcher {
+ GtkBin parent;
+ EShellSwitcherPrivate *priv;
+};
+
+struct _EShellSwitcherClass {
+ GtkBinClass parent_class;
+
+ void (*style_changed) (EShellSwitcher *switcher,
+ GtkToolbarStyle style);
+};
+
+GType e_shell_switcher_get_type (void);
+GtkWidget * e_shell_switcher_new (void);
+void e_shell_switcher_add_action (EShellSwitcher *switcher,
+ GtkAction *action);
+GtkToolbarStyle e_shell_switcher_get_style (EShellSwitcher *switcher);
+void e_shell_switcher_set_style (EShellSwitcher *switcher,
+ GtkToolbarStyle style);
+void e_shell_switcher_unset_style (EShellSwitcher *switcher);
+gboolean e_shell_switcher_get_visible (EShellSwitcher *switcher);
+void e_shell_switcher_set_visible (EShellSwitcher *switcher,
+ gboolean visible);
+
+G_END_DECLS
+
+#endif /* E_SHELL_SWITCHER_H */
diff --cc shell/e-shell-taskbar.c
index c81f408,0000000..61f27fb
mode 100644,000000..100644
--- a/shell/e-shell-taskbar.c
+++ b/shell/e-shell-taskbar.c
@@@ -1,421 -1,0 +1,421 @@@
+/*
+ * e-shell-taskbar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-taskbar.h"
+
+#include <e-shell-view.h>
+
+#include <widgets/misc/e-activity-proxy.h>
+
+#define E_SHELL_TASKBAR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SHELL_TASKBAR, EShellTaskbarPrivate))
+
+struct _EShellTaskbarPrivate {
+
+ gpointer shell_view; /* weak pointer */
+
+ GtkWidget *label;
+ GtkWidget *hbox;
+
+ GHashTable *proxy_table;
+};
+
+enum {
+ PROP_0,
+ PROP_MESSAGE,
+ PROP_SHELL_VIEW
+};
+
+static gpointer parent_class;
+
+static void
+shell_taskbar_activity_remove (EShellTaskbar *shell_taskbar,
+ EActivity *activity)
+{
+ GtkBox *box;
+ GtkWidget *proxy;
+ GHashTable *proxy_table;
+
+ box = GTK_BOX (shell_taskbar->priv->hbox);
+ proxy_table = shell_taskbar->priv->proxy_table;
+ proxy = g_hash_table_lookup (proxy_table, activity);
+ g_return_if_fail (proxy != NULL);
+
+ g_hash_table_remove (proxy_table, activity);
+ gtk_container_remove (GTK_CONTAINER (box), proxy);
+
+ if (box->children == NULL)
+ gtk_widget_hide (GTK_WIDGET (box));
+}
+
+static void
+shell_taskbar_activity_add (EShellTaskbar *shell_taskbar,
+ EActivity *activity)
+{
+ GtkBox *box;
+ GtkWidget *proxy;
+
+ proxy = e_activity_proxy_new (activity);
+ box = GTK_BOX (shell_taskbar->priv->hbox);
+ gtk_box_pack_start (box, proxy, TRUE, TRUE, 0);
+ gtk_box_reorder_child (box, proxy, 0);
+ gtk_widget_show (GTK_WIDGET (box));
+ gtk_widget_show (proxy);
+
+ g_hash_table_insert (
+ shell_taskbar->priv->proxy_table,
+ g_object_ref (activity), g_object_ref (proxy));
+
+ g_signal_connect_swapped (
+ activity, "cancelled",
+ G_CALLBACK (shell_taskbar_activity_remove), shell_taskbar);
+
+ g_signal_connect_swapped (
+ activity, "completed",
+ G_CALLBACK (shell_taskbar_activity_remove), shell_taskbar);
+}
+
+static void
+shell_taskbar_set_shell_view (EShellTaskbar *shell_taskbar,
+ EShellView *shell_view)
+{
+ g_return_if_fail (shell_taskbar->priv->shell_view == NULL);
+
+ shell_taskbar->priv->shell_view = shell_view;
+
+ g_object_add_weak_pointer (
+ G_OBJECT (shell_view),
+ &shell_taskbar->priv->shell_view);
+}
+
+static void
+shell_taskbar_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MESSAGE:
+ e_shell_taskbar_set_message (
+ E_SHELL_TASKBAR (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_SHELL_VIEW:
+ shell_taskbar_set_shell_view (
+ E_SHELL_TASKBAR (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_taskbar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MESSAGE:
+ g_value_set_string (
+ value, e_shell_taskbar_get_message (
+ E_SHELL_TASKBAR (object)));
+ return;
+
+ case PROP_SHELL_VIEW:
+ g_value_set_object (
+ value, e_shell_taskbar_get_shell_view (
+ E_SHELL_TASKBAR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_taskbar_dispose (GObject *object)
+{
+ EShellTaskbarPrivate *priv;
+
+ priv = E_SHELL_TASKBAR_GET_PRIVATE (object);
+
+ if (priv->shell_view != NULL) {
+ g_object_remove_weak_pointer (
+ G_OBJECT (priv->shell_view), &priv->shell_view);
+ priv->shell_view = NULL;
+ }
+
+ if (priv->label != NULL) {
+ g_object_unref (priv->label);
+ priv->label = NULL;
+ }
+
+ if (priv->hbox != NULL) {
+ g_object_unref (priv->hbox);
+ priv->hbox = NULL;
+ }
+
+ g_hash_table_remove_all (priv->proxy_table);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+shell_taskbar_finalize (GObject *object)
+{
+ EShellTaskbarPrivate *priv;
+
+ priv = E_SHELL_TASKBAR_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->proxy_table);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+shell_taskbar_constructed (GObject *object)
+{
+ EShellView *shell_view;
+ EShellBackend *shell_backend;
+ EShellTaskbar *shell_taskbar;
+
+ shell_taskbar = E_SHELL_TASKBAR (object);
+ shell_view = e_shell_taskbar_get_shell_view (shell_taskbar);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+
+ g_signal_connect_swapped (
+ shell_backend, "activity-added",
+ G_CALLBACK (shell_taskbar_activity_add), shell_taskbar);
+}
+
+static void
+shell_taskbar_class_init (EShellTaskbarClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EShellTaskbarPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = shell_taskbar_set_property;
+ object_class->get_property = shell_taskbar_get_property;
+ object_class->dispose = shell_taskbar_dispose;
+ object_class->finalize = shell_taskbar_finalize;
+ object_class->constructed = shell_taskbar_constructed;
+
+ /**
+ * EShellTaskbar:message
+ *
+ * The message to display in the taskbar.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_MESSAGE,
+ g_param_spec_string (
+ "message",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ /**
+ * EShellTaskbar:shell-view
+ *
+ * The #EShellView to which the taskbar widget belongs.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_SHELL_VIEW,
+ g_param_spec_object (
+ "shell-view",
+ NULL,
+ NULL,
+ E_TYPE_SHELL_VIEW,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+shell_taskbar_init (EShellTaskbar *shell_taskbar)
+{
+ GtkWidget *widget;
+ GHashTable *proxy_table;
+ gint height;
+
+ proxy_table = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) g_object_unref);
+
+ shell_taskbar->priv = E_SHELL_TASKBAR_GET_PRIVATE (shell_taskbar);
+ shell_taskbar->priv->proxy_table = proxy_table;
+
+ gtk_box_set_spacing (GTK_BOX (shell_taskbar), 12);
+
+ widget = gtk_label_new (NULL);
+ gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
+ gtk_box_pack_start (GTK_BOX (shell_taskbar), widget, TRUE, TRUE, 0);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ shell_taskbar->priv->label = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ widget = gtk_hbox_new (FALSE, 3);
+ gtk_box_pack_start (GTK_BOX (shell_taskbar), widget, TRUE, TRUE, 0);
+ shell_taskbar->priv->hbox = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ /* Make the taskbar large enough to accomodate a small icon.
+ * XXX The "* 2" is a fudge factor to allow for some padding
+ * The true value is probably buried in a style property. */
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &height);
+ gtk_widget_set_size_request (
+ GTK_WIDGET (shell_taskbar), -1, (height * 2));
+}
+
+GType
+e_shell_taskbar_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EShellTaskbarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) shell_taskbar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EShellTaskbar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) shell_taskbar_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_HBOX, "EShellTaskbar", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * e_shell_taskbar_new:
+ * @shell_view: an #EShellView
+ *
+ * Creates a new #EShellTaskbar instance belonging to @shell_view.
+ *
+ * Returns: a new #EShellTaskbar instance
+ **/
+GtkWidget *
+e_shell_taskbar_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_SHELL_TASKBAR, "shell-view", shell_view, NULL);
+}
+
+/**
+ * e_shell_taskbar_get_shell_view:
+ * @shell_taskbar: an #EShellTaskbar
+ *
+ * Returns the #EShellView that was passed to e_shell_taskbar_new().
+ *
+ * Returns: the #EShellView to which @shell_taskbar belongs
+ **/
+EShellView *
+e_shell_taskbar_get_shell_view (EShellTaskbar *shell_taskbar)
+{
+ g_return_val_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar), NULL);
+
+ return shell_taskbar->priv->shell_view;
+}
+
+/**
+ * e_shell_taskbar_get_message:
+ * @shell_taskbar: an #EShellTaskbar
+ *
+ * Returns the message currently shown in the taskbar, or an empty string
+ * if no message is shown. Taskbar messages are used primarily for menu
+ * tooltips.
+ *
+ * Returns: the current taskbar message
+ **/
+const gchar *
+e_shell_taskbar_get_message (EShellTaskbar *shell_taskbar)
+{
+ GtkWidget *label;
+
+ g_return_val_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar), NULL);
+
+ label = shell_taskbar->priv->label;
+
+ return gtk_label_get_text (GTK_LABEL (label));
+}
+
+/**
+ * e_shell_taskbar_set_message:
+ * @shell_taskbar: an #EShellTaskbar
+ * @message: the message to show
+ *
+ * Shows a message in the taskbar. If @message is %NULL or an empty string,
+ * the taskbar message is cleared. Taskbar messages are used primarily for
+ * menu tooltips.
+ **/
+void
+e_shell_taskbar_set_message (EShellTaskbar *shell_taskbar,
+ const gchar *message)
+{
+ GtkWidget *label;
+
+ g_return_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar));
+
+ label = shell_taskbar->priv->label;
+ gtk_label_set_text (GTK_LABEL (label), message);
+
+ if (message != NULL && *message != '\0')
+ gtk_widget_show (label);
+ else
+ gtk_widget_hide (label);
+
+ g_object_notify (G_OBJECT (shell_taskbar), "message");
+}
+
+/**
+ * e_shell_taskbar_unset_message:
+ * @shell_taskbar: an #EShellTaskbar
+ *
+ * This is equivalent to passing a %NULL message to
+ * e_shell_taskbar_set_message().
+ **/
+void
+e_shell_taskbar_unset_message (EShellTaskbar *shell_taskbar)
+{
+ g_return_if_fail (E_IS_SHELL_TASKBAR (shell_taskbar));
+
+ e_shell_taskbar_set_message (shell_taskbar, NULL);
+}
diff --cc shell/e-shell-taskbar.h
index b0aab3b,0000000..3c3d400
mode 100644,000000..100644
--- a/shell/e-shell-taskbar.h
+++ b/shell/e-shell-taskbar.h
@@@ -1,87 -1,0 +1,87 @@@
+/*
+ * e-shell-taskbar.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/**
+ * SECTION: e-shell-taskbar
+ * @short_description: the bottom of the main window
+ * @include: shell/e-shell-taskbar.h
+ **/
+
+#ifndef E_SHELL_TASKBAR_H
+#define E_SHELL_TASKBAR_H
+
+#include <shell/e-shell-common.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SHELL_TASKBAR \
+ (e_shell_taskbar_get_type ())
+#define E_SHELL_TASKBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SHELL_TASKBAR, EShellTaskbar))
+#define E_SHELL_TASKBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SHELL_TASKBAR, EShellTaskbarClass))
+#define E_IS_SHELL_TASKBAR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SHELL_TASKBAR))
+#define E_IS_SHELL_TASKBAR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SHELL_TASKBAR))
+#define E_SHELL_TASKBAR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SHELL_TASKBAR, EShellTaskbarClass))
+
+G_BEGIN_DECLS
+
+/* Avoid including <e-shell-view.h>, because it includes us! */
+struct _EShellView;
+
+typedef struct _EShellTaskbar EShellTaskbar;
+typedef struct _EShellTaskbarClass EShellTaskbarClass;
+typedef struct _EShellTaskbarPrivate EShellTaskbarPrivate;
+
+/**
+ * EShellTaskbar:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ **/
+struct _EShellTaskbar {
+ GtkHBox parent;
+ EShellTaskbarPrivate *priv;
+};
+
+struct _EShellTaskbarClass {
+ GtkHBoxClass parent_class;
+};
+
+GType e_shell_taskbar_get_type (void);
+GtkWidget * e_shell_taskbar_new (struct _EShellView *shell_view);
+struct _EShellView *
+ e_shell_taskbar_get_shell_view (EShellTaskbar *shell_taskbar);
+const gchar * e_shell_taskbar_get_message (EShellTaskbar *shell_taskbar);
+void e_shell_taskbar_set_message (EShellTaskbar *shell_taskbar,
+ const gchar *message);
+void e_shell_taskbar_unset_message (EShellTaskbar *shell_taskbar);
+
+G_END_DECLS
+
+#endif /* E_SHELL_TASKBAR_H */
diff --cc shell/e-shell-view.c
index 7c5332a,a6d071c..cf89442
--- a/shell/e-shell-view.c
+++ b/shell/e-shell-view.c
@@@ -12,9 -12,12 +12,9 @@@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Michael Zucchi <notzed ximian com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
diff --cc shell/e-shell-window-actions.c
index 846bb82,0000000..a53412c
mode 100644,000000..100644
--- a/shell/e-shell-window-actions.c
+++ b/shell/e-shell-window-actions.c
@@@ -1,2226 -1,0 +1,2226 @@@
+/*
+ * e-shell-window-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-window-private.h"
+
+#include <e-util/e-dialog-utils.h>
+#include <e-util/e-error.h>
+#include <e-util/e-print.h>
+#include <gal-define-views-dialog.h>
+
+#include <libedataserverui/e-passwords.h>
+
+#include "e-shell-importer.h"
+
+#define EVOLUTION_COPYRIGHT \
+ "Copyright \xC2\xA9 1999 - 2008 Novell, Inc. and Others"
+
+#define EVOLUTION_FAQ \
+ "http://www.go-evolution.org/FAQ"
+
+#define EVOLUTION_WEBSITE \
+ "http://www.gnome.org/projects/evolution/"
+
+/* Authors and Documenters
+ *
+ * The names below must be in UTF-8. The breaking of escaped strings
+ * is so the hexadecimal sequences don't swallow too many characters.
+ *
+ * SO THAT MEANS, FOR 8-BIT CHARACTERS USE \xXX HEX ENCODING ONLY!
+ *
+ * Not all environments are UTF-8 and not all editors can handle it.
+ */
+static const gchar *authors[] = {
+ "Aaron Weber",
+ "Abel Cheung",
+ "Abhishek Parwal",
+ "Adam Weinberger",
+ "Adi Attar",
+ "Ahmad Riza H Nst",
+ "Aidan Delaney",
+ "Aishwarya K",
+ "Akagic Amila",
+ "Akhil Laddha",
+ "Akira Tagoh",
+ "Alastair McKinstry",
+ "Alastair Tse",
+ "Alejandro Andres",
+ "Alessandro Decina",
+ "Alex Graveley",
+ "Alex Jiang",
+ "Alex Jones",
+ "Alex Kloss",
+ "Alexander Shopov",
+ "Alfred Peng",
+ "Ali Abdin",
+ "Ali Akcaagac",
+ "Almer S. Tigelaar",
+ "Amish",
+ "Anand V M",
+ "Anders Carlsson",
+ "Andre Klapper",
+ "Andrea Campi",
+ "Andreas Henriksson",
+ "Andreas Hyden",
+ "Andreas J. Guelzow",
+ "Andreas K\xC3\xB6hler",
+ "Andreas Köhler",
+ "Andrew Ruthven",
+ "Andrew T. Veliath",
+ "Andrew Wu",
+ "Ankit Patel",
+ "Anna Marie Dirks",
+ "Antonio Xu",
+ "Arafat Medini",
+ "Arangel Angov",
+ "Archit Baweja",
+ "Ariel Rios",
+ "Arik Devens",
+ "Armin Bauer",
+ "Arturo Espinosa Aldama",
+ "Arulanandan P",
+ "Arun Prakash",
+ "Arvind Sundararajan",
+ "Arvind",
+ "Ashish",
+ "B S Srinidhi",
+ "Bastien Nocera",
+ "Behnam Esfahbod",
+ "Ben Gamari",
+ "Benjamin Berg",
+ "Benjamin Kahn",
+ "Benoît Dejean",
+ "Bernard Leach",
+ "Bertrand Guiheneuf",
+ "Bharath Acharya",
+ "Bill Zhu",
+ "Bj\xC3\xB6rn Torkelsson",
+ "Bj�¶rn Lindqvist",
+ "Bob Doan",
+ "Bob Mauchin",
+ "Boby Wang",
+ "Bolian Yin",
+ "Brian Mury",
+ "Brian Pepple",
+ "Bruce Tao",
+ "Calvin Liu",
+ "Cantona Su",
+ "Carl Sun",
+ "Carlos Garcia Campos",
+ "Carlos Garnacho Parro",
+ "Carlos Perell\xC3\xB3" " Mar\xC3\xAD" "n",
+ "Carsten Guenther",
+ "Carsten Schaar",
+ "Changwoo Ryu",
+ "Chao-Hsiung Liao",
+ "Charles Zhang",
+ "Chema Celorio",
+ "Chenthill Palanisamy",
+ "Chpe",
+ "Chris Halls",
+ "Chris Heath",
+ "Chris Phelps",
+ "Chris Toshok",
+ "Christian Hammond",
+ "Christian Kellner",
+ "Christian Kirbach",
+ "Christian Krause",
+ "Christian Kreibich",
+ "Christian Neumair",
+ "Christophe Fergeau",
+ "Christophe Merlet",
+ "Christopher Blizzard",
+ "Christopher J. Lahey",
+ "Christopher R. Gabriel",
+ "Claude Paroz",
+ "Claudio Saavedra",
+ "Clifford R. Conover",
+ "Cody Russell",
+ "Colin Leroy",
+ "Craig Small",
+ "Dafydd Harries",
+ "Damian Ivereigh",
+ "Damien Carbery",
+ "Damon Chaplin",
+ "Dan Berger",
+ "Dan Damian",
+ "Dan Nguyen",
+ "Dan Winship",
+ "Daniel Gryniewicz",
+ "Daniel Nylander",
+ "Daniel van Eeden",
+ "Daniel Veillard",
+ "Daniel Yacob",
+ "Danilo \xC5\xA0" "egan",
+ "Danilo Segan",
+ "Darin Adler",
+ "Dave Benson",
+ "Dave Camp",
+ "Dave Fallon",
+ "Dave Malcolm",
+ "Dave West",
+ "David Farning",
+ "David Kaelbling",
+ "David Malcolm",
+ "David Moore",
+ "David Mosberger",
+ "David Richards",
+ "David Trowbridge",
+ "David Turner",
+ "David Woodhouse",
+ "Denis Washington",
+ "Devashish Sharma",
+ "Diego Escalante Urrelo",
+ "Diego Gonzalez",
+ "Diego Sevilla Ruiz",
+ "Dietmar Maurer",
+ "Dinesh Layek",
+ "Djihed Afifi",
+ "Dmitry Mastrukov",
+ "Dodji Seketeli",
+ "Duarte Loreto",
+ "Dulmandakh Sukhbaatar",
+ "Duncan Mak",
+ "Ebby Wiselyn",
+ "Ed Catmur",
+ "Edd Dumbill",
+ "Edgar Luna DÃaz",
+ "Edward Rudd",
+ "Elijah Newren",
+ "Elizabeth Greene",
+ "Elliot Lee",
+ "Elliot Turner",
+ "Eneko Lacunza",
+ "Enver Altin",
+ "Erdal Ronahi",
+ "Eric Busboom",
+ "Eric Zhao",
+ "Eskil Heyn Olsen",
+ "Ettore Perazzoli",
+ "Evan Yan",
+ "Fatih Demir",
+ "Fazlu & Hannah",
+ "Federico Mena Quintero",
+ "Fernando Herrera",
+ "Francisco Javier F. Serrador",
+ "Frank Arnold",
+ "Frank Belew",
+ "Frederic Crozat",
+ "Frederic Peters",
+ "Funda Wang",
+ "Gabor Kelemen",
+ "Ganesh",
+ "Gareth Owen",
+ "Gary Coady",
+ "Gary Ekker",
+ "Gavin Scott",
+ "Gediminas Paulauskas",
+ "Gerg\xC5\x91 \xC3\x89rdi",
+ "George Lebl",
+ "Gerardo Marin",
+ "Gert Kulyk",
+ "Giancarlo Capella",
+ "Gil Osher",
+ "Gilbert Fang",
+ "Gilles Dartiguelongue",
+ "Grahame Bowland",
+ "Greg Hudson",
+ "Gregory Leblanc",
+ "Gregory McLean",
+ "Grzegorz Goawski",
+ "Gustavo Gir\xC3\x8E" "ldez",
+ "Gustavo Maciel Dias Vieira",
+ "H P Nadig",
+ "H\xC3\xA9" "ctor Garc\xC3\xAD" "a \xC3\x81" "lvarez",
+ "Hans Petter Jansson",
+ "Hao Sheng",
+ "Hari Prasad Nadig",
+ "Harish K",
+ "Harish Krishnaswamy",
+ "Harry Lu",
+ "Hasbullah Bin Pit",
+ "Havoc Pennington",
+ "Heath Harrelson",
+ "Hein-Pieter van Braam",
+ "Herbert V. Riedel",
+ "Hiroyuki Ikezoe",
+ "Iain Buchanan",
+ "Iain Holmes",
+ "Ian Campbell",
+ "Ilkka Tuohela",
+ "Irene Huang",
+ "Ismael Olea",
+ "Israel Escalante",
+ "Iv\xC3\xA1" "n Frade",
+ "Iv�¡n Frade",
+ "J.H.M. Dassen (Ray)",
+ "JP Rosevear",
+ "J\xC3\xBC" "rg Billeter",
+ "J��¼rg Billeter",
+ "Jack Jia",
+ "Jacob Ulysses Berkman",
+ "Jacob Berkman",
+ "Jaka Mocnik",
+ "Jakub Steiner",
+ "James Doc Livingston",
+ "James Bowes",
+ "James Henstridge",
+ "James Willcox",
+ "Jan Arne Petersen",
+ "Jan Tichavsky",
+ "Jan Van Buggenhout",
+ "Jared Moore",
+ "Jarkko Ranta",
+ "Jason Leach",
+ "Jason Tackaberry",
+ "Jayaradha",
+ "Jean-Noel Guiheneuf",
+ "Jedy Wang",
+ "Jeff Bailey",
+ "Jeff Cai",
+ "Jeff Garzik",
+ "Jeffrey Stedfast",
+ "Jens Granseuer",
+ "Jens Seidel",
+ "Jeremy Katz",
+ "Jeremy Wise",
+ "Jerome Lacoste",
+ "Jerry Yu",
+ "Jes\xC3\xBA" "s Bravo \xC3\x81" "lvarez",
+ "Jesse Pavel",
+ "Ji Lee",
+ "Joan Sanfeliu",
+ "Jody Goldberg",
+ "Joe Marcus Clarke",
+ "Joe Shaw",
+ "John Gotts",
+ "Johnny Jacob",
+ "Johnny",
+ "Jon Ander Hernandez",
+ "Jon K Hellan",
+ "Jon Oberheide",
+ "Jon Trowbridge",
+ "Jonas Borgstr",
+ "Jonathan Blandford",
+ "Jonathan Dieter",
+ "Jos Dehaes",
+ "Josselin Mouette",
+ "JP Rosvear",
+ "Jukka Zitting",
+ "Jules Colding",
+ "Julian Missig",
+ "Julio M. Merino Vidal",
+ "Jürg Billeter",
+ "Karl Eichwalder",
+ "Karl Relton",
+ "Karsten Br\xC3\xA4" "ckelmann",
+ "Kaushal Kumar",
+ "Kenneth Christiansen",
+ "Kenny Graunke",
+ "Keshav Upadhyaya",
+ "Kevin Breit",
+ "Kevin Piche",
+ "Kevin Vandersloot",
+ "Khasim Shaheed",
+ "Kidd Wang",
+ "Kjartan Maraas",
+ "Krishnan R",
+ "Krisztian Pifko",
+ "Kyle Ambroff",
+ "Larry Ewing",
+ "Laszlo (Laca) Peter",
+ "Laurent Dhima",
+ "Lauris Kaplinski",
+ "Leon Zhang",
+ "Li Yuan",
+ "Lo�¯c Minier",
+ "Loïc Minier",
+ "Lorenzo Gil Sanchez",
+ "Luca Ferretti",
+ "Lucky Wankhede",
+ "Luis Villa",
+ "Lutz M",
+ "M Victor Aloysius J",
+ "Maciej Stachowiak",
+ "Makuchaku",
+ "Malcolm Tredinnick",
+ "Marco Pesenti Gritti",
+ "Marius Andreiana",
+ "Marius Vollmer",
+ "Mark Crichton",
+ "Mark G. Adams",
+ "Mark Gordon",
+ "Mark McLoughlin",
+ "Mark Moulder",
+ "Mark Tearle",
+ "Martha Burke",
+ "Martin Baulig",
+ "Martin Hicks",
+ "Martin Meyer",
+ "Martin Norb\xC3\xA4" "ck",
+ "Martyn Russell",
+ "Masahiro Sakai",
+ "Mathieu Lacage",
+ "Matias Mutchinick",
+ "Matt Bissiri",
+ "Matt Brown",
+ "Matt Loper",
+ "Matt Martin",
+ "Matt Wilson",
+ "Matthew Barnes",
+ "Matthew Daniel",
+ "Matthew Hall",
+ "Matthew Loper",
+ "Matthew Wilson",
+ "Matthias Clasen",
+ "Max Horn",
+ "Maxx Cao",
+ "Mayank Jain",
+ "Meilof Veeningen",
+ "Mengjie Yu",
+ "Michael Granger",
+ "Michael M. Morrison",
+ "Michael MacDonald",
+ "Michael Meeks",
+ "Michael Monreal",
+ "Michael Terry",
+ "Michael Zucchi",
+ "Michel Daenzer",
+ "Miguel Angel Lopez Hernandez",
+ "Miguel de Icaza",
+ "Mikael Hallendal",
+ "Mikael Nilsson",
+ "Mike Castle",
+ "Mike Kestner",
+ "Mike McEwan",
+ "Mikhail Zabaluev",
+ "Milan Crha",
+ "Miles Lane",
+ "Mohammad Damt",
+ "Morten Welinder",
+ "Mubeen Jukaku",
+ "Murray Cumming",
+ "Naba Kumar",
+ "Nagappan Alagappan",
+ "Nancy Cai",
+ "Nat Friedman",
+ "Nathan Owens",
+ "Nicel KM",
+ "Nicholas J Kreucher",
+ "Nicholas Miell",
+ "Nick Sukharev",
+ "Nickolay V. Shmyrev",
+ "Nike Gerdts",
+ "Noel",
+ "Nuno Ferreira",
+ "Nyall Dawson",
+ "Ondrej Jirman",
+ "Oswald Rodrigues",
+ "Owen Taylor",
+ "Oystein Gisnas",
+ "P Chenthill",
+ "P S Chakravarthi",
+ "Pablo Gonzalo del Campo",
+ "Pablo Saratxaga",
+ "Pamplona Hackers",
+ "Paolo Molaro",
+ "Parag Goel",
+ "Parthasarathi Susarla",
+ "Pascal Terjan",
+ "Patrick Ohly",
+ "Paul Bolle",
+ "Paul Lindner",
+ "Pavel Cisler",
+ "Pavel Roskin",
+ "Pavithran",
+ "Pawan Chitrakar",
+ "Pedro Villavicencio",
+ "Peter Pouliot",
+ "Peter Teichman",
+ "Peter Williams",
+ "Peteris Krisjanis",
+ "Petta Pietikainen",
+ "Phil Goembel",
+ "Philip Van Hoof",
+ "Philip Zhao",
+ "Poornima Nayak",
+ "Pratik V. Parikh",
+ "Praveen Kumar",
+ "Priit Laes",
+ "Priyanshu Raj",
+ "Radek Doul\xC3\xADk",
+ "Raghavendran R",
+ "Raja R Harinath",
+ "Rajeev Ramanathan",
+ "Rajesh Ranjan",
+ "Rakesh k.g",
+ "Ramiro Estrugo",
+ "Ranjan Somani",
+ "Ray Strode",
+ "Rhys Jones",
+ "Ricardo Markiewicz",
+ "Richard Boulton",
+ "Richard Hult",
+ "Richard Li",
+ "Rob Bradford",
+ "Robert Brady",
+ "Robert Sedak",
+ "Robin Slomkowski",
+ "Rodney Dawes",
+ "Rodrigo Moya",
+ "Rohini S",
+ "Rohini",
+ "Roland Illig",
+ "Ronald Kuetemeier",
+ "Roozbeh Pournader",
+ "Ross Burton",
+ "Rouslan Solomakhin",
+ "Runa Bhattacharjee",
+ "Russell Steinthal",
+ "Rusty Conover",
+ "Ryan P. Skadberg",
+ "S Antony Vincent Pandian",
+ "S N Tejasvi",
+ "S. \xC3\x87" "a\xC4\x9F" "lar Onur",
+ "S.Antony Vincent Pandian",
+ "S. Caglar Onur",
+ "Sam Creasey",
+ "Sam Yang",
+ "Sam\xC3\xBA" "el J\xC3\xB3" "n Gunnarsson",
+ "Sankar P",
+ "Sanlig Badral",
+ "Sanshao Jiang",
+ "Sarfraaz Ahmed",
+ "Sayamindu Dasgupta",
+ "Sean Atkinson",
+ "Sean Gao",
+ "Sebastian Rittau",
+ "Sebastian Wilhelmi",
+ "Sebastien Bacher",
+ "Sergey Panov",
+ "Seth Alves",
+ "Seth Nickell",
+ "Shakti Sen",
+ "Shi Pu",
+ "Shilpa C",
+ "Shree Krishnan",
+ "Shreyas Srinivasan",
+ "Simon Zheng",
+ "Simos Xenitellis",
+ "Sivaiah Nallagatla",
+ "Srinivasa Ragavan",
+ "Stanislav Brabec",
+ "Stanislav Visnovsky",
+ "Stéphane Raimbault",
+ "Stephen Cook",
+ "Steve Murphy",
+ "Steven Zhang",
+ "Stuart Parmenter",
+ "Subodh Soni",
+ "Suman Manjunath",
+ "Sunil Mohan Adapa",
+ "Suresh Chandrasekharan",
+ "Sushma Rai",
+ "Sven Herzberg",
+ "Szabolcs Ban",
+ "T\xC3\xB5" "ivo Leedj\xC3\xA4" "rv",
+ "Takao Fujiwara",
+ "Takayuki Kusano",
+ "Takeshi Aihana",
+ "Tambet Ingo",
+ "Taylor Hayward",
+ "Ted Percival",
+ "Theppitak Karoonboonyanan",
+ "Thomas Cataldo",
+ "Thomas Klausner",
+ "Thomas Mirlacher",
+ "Thouis R. Jones",
+ "Tim Wo",
+ "Tim Yamin",
+ "Timo Hoenig",
+ "Timo Sirainen",
+ "Timothy Lee",
+ "Timur Bakeyev",
+ "Tino Meinen",
+ "Tobias Mueller",
+ "Tõivo Leedjärv",
+ "Tom Tromey",
+ "Tomas Ogren",
+ "Tomasz K\xC5\x82" "oczko",
+ "Tomislav Vujec",
+ "Tommi Komulainen",
+ "Tommi Vainikainen",
+ "Tony Tsui",
+ "Tor Lillqvist",
+ "Trent Lloyd",
+ "Tuomas J. Lukka",
+ "Tuomas Kuosmanen",
+ "Ulrich Neumann",
+ "Umesh Tiwari",
+ "Umeshtej",
+ "Ushveen Kaur",
+ "V Ravi Kumar Raju",
+ "Vadim Strizhevsky",
+ "Valek Filippov",
+ "Vandana Shenoy .B",
+ "Vardhman Jain",
+ "Veerapuram Varadhan",
+ "Vincent Noel",
+ "Vincent van Adrighem",
+ "Viren",
+ "Vivek Jain",
+ "Vladimer Sichinava",
+ "Vladimir Vukicevic",
+ "Wadim Dziedzic",
+ "Wang Jian",
+ "Wang Xin",
+ "Wayne Davis",
+ "William Jon McCann",
+ "Wouter Bolsterlee",
+ "Xan Lopez",
+ "Xiurong Simon Zheng",
+ "Yanko Kaneti",
+ "Yi Jin",
+ "Yong Sun",
+ "Yu Mengjie",
+ "Yuedong Du",
+ "Yukihiro Nakai",
+ "Yuri Pankov",
+ "Yuri Syrota",
+ "Zach Frey",
+ "Zan Lynx",
+ "Zbigniew Chyla",
+ "\xC3\x98ystein Gisn\xC3\xA5s",
+ "\xC5\xBDygimantas Beru\xC4\x8Dka",
+ NULL
+};
+
+static const gchar *documenters[] = {
+ "Aaron Weber",
+ "Binika Preet",
+ "Dan Winship",
+ "David Trowbridge",
+ "Jessica Prabhakar",
+ "JP Rosevear",
+ "Radhika Nair",
+ NULL
+};
+
+/**
+ * E_SHELL_WINDOW_ACTION_ABOUT:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action displays the application's About dialog.
+ *
+ * Main menu item: Help -> About
+ **/
+static void
+action_about_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ gchar *translator_credits;
+
+ /* The translator-credits string is for translators to list
+ * per-language credits for translation, displayed in the
+ * about dialog. */
+ translator_credits = _("translator-credits");
+ if (strcmp (translator_credits, "translator-credits") == 0)
+ translator_credits = NULL;
+
+ gtk_show_about_dialog (
+ GTK_WINDOW (shell_window),
+ "program-name", "Evolution",
+ "version", VERSION,
+ "copyright", EVOLUTION_COPYRIGHT,
+ "comments", _("Groupware Suite"),
+ "website", EVOLUTION_WEBSITE,
+ "website-label", _("Evolution Website"),
+ "authors", authors,
+ "documenters", documenters,
+ "translator-credits", translator_credits,
+ "logo-icon-name", "evolution",
+ NULL);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_CLOSE:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action closes @window. If this is the last window,
+ * the application initiates shutdown.
+ *
+ * Main menu item: File -> Close
+ **/
+static void
+action_close_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ GtkWidget *widget = GTK_WIDGET (shell_window);
+ GdkEvent *event;
+
+ /* Synthesize a delete_event on this window. */
+ event = gdk_event_new (GDK_DELETE);
+ event->any.window = g_object_ref (widget->window);
+ event->any.send_event = TRUE;
+ gtk_main_do_event (event);
+ gdk_event_free (event);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_CONTENTS:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens the application's user manual.
+ *
+ * Main menu item: Help -> Contents
+ **/
+static void
+action_contents_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ e_display_help (GTK_WINDOW (shell_window), NULL);
+}
+
+static void
+action_custom_rule_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ FilterRule *rule;
+ EShellView *shell_view;
+ EShellContent *shell_content;
+ 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);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+
+ rule = g_object_get_data (G_OBJECT (action), "rule");
+ g_return_if_fail (IS_FILTER_RULE (rule));
+
+ e_shell_content_set_search_rule (shell_content, rule);
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_FAQ:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens a web page with answers to frequently
+ * asked questions about this application.
+ *
+ * Main menu item: Help -> Evolution FAQ
+ **/
+static void
+action_faq_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ e_show_uri (GTK_WINDOW (shell_window), EVOLUTION_FAQ);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_FORGET_PASSWORDS:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action deletes all stored passwords.
+ *
+ * Main menu item: File -> Forget Passwords
+ **/
+static void
+action_forget_passwords_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ gint response;
+
+ response = e_error_run (
+ GTK_WINDOW (shell_window), "shell:forget-passwords", NULL);
+
+ if (response == GTK_RESPONSE_OK)
+ e_passwords_forget_passwords ();
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_GAL_DEFINE_VIEWS:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens a dialog for editing GAL views for
+ * the current shell view.
+ *
+ * Main menu item: View -> Current View -> Define Views...
+ **/
+static void
+action_gal_define_views_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ GalViewCollection *view_collection;
+ GtkWidget *dialog;
+ 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_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ view_collection = shell_view_class->view_collection;
+ g_return_if_fail (view_collection != NULL);
+
+ dialog = gal_define_views_dialog_new (view_collection);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gal_view_collection_save (view_collection);
+ gtk_widget_destroy (dialog);
+
+ e_shell_window_update_view_menu (shell_window);
+}
+
+/**
+ * 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...
+ **/
+
+/**
+ * E_SHELL_WINDOW_ACTION_IMPORT:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens the Evolution Import Assistant.
+ *
+ * Main menu item: File -> Import...
+ **/
+static void
+action_import_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ e_shell_importer_start_import (shell_window);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_NEW_WINDOW:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens a new shell window.
+ *
+ * Main menu item: File -> New Window
+ **/
+static void
+action_new_window_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ const gchar *view_name;
+
+ shell = e_shell_window_get_shell (shell_window);
+ view_name = e_shell_window_get_active_view (shell_window);
+
+ e_shell_create_shell_window (shell, view_name);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_PAGE_SETUP:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens the application's Page Setup dialog.
+ *
+ * Main menu item: File -> Page Setup...
+ **/
+static void
+action_page_setup_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ e_print_run_page_setup_dialog (GTK_WINDOW (shell_window));
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_PREFERENCES:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens the application's Preferences window.
+ *
+ * Main menu item: Edit -> Preferences
+ **/
+static void
+action_preferences_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ GtkWidget *preferences_window;
+
+ shell = e_shell_window_get_shell (shell_window);
+ preferences_window = e_shell_get_preferences_window (shell);
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (preferences_window),
+ GTK_WINDOW (shell_window));
+ gtk_window_set_position (
+ GTK_WINDOW (preferences_window),
+ GTK_WIN_POS_CENTER_ON_PARENT);
+ gtk_window_present (GTK_WINDOW (preferences_window));
+
+ /* FIXME Switch to a page appropriate for the current view. */
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_QUICK_REFERENCE:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens a printable table of useful shortcut
+ * keys for this application.
+ *
+ * Main menu item: Help -> Quick Reference
+ **/
+static void
+action_quick_reference_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ const gchar * const *language_names;
+
+ language_names = g_get_language_names ();
+ while (*language_names != NULL) {
+ const gchar *language = *language_names++;
+ gchar *filename;
+
+ /* This must be a valid language AND a language with
+ * no encoding suffix. The next language should have
+ * no encoding suffix. */
+ if (language == NULL || strchr (language, '.') != NULL)
+ continue;
+
+ filename = g_build_filename (
+ EVOLUTION_HELPDIR, "quickref",
+ language, "quickref.pdf", NULL);
+
+ if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ GFile *file;
+ gchar *uri;
+ GError *error = NULL;
+
+ file = g_file_new_for_path (filename);
+ uri = g_file_get_uri (file);
+
+ g_app_info_launch_default_for_uri (uri, NULL, &error);
+
+ if (error != NULL) {
+ /* FIXME Show an error dialog. */
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ g_object_unref (file);
+ g_free (uri);
+ }
+
+ g_free (filename);
+ }
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_QUIT:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action initiates application shutdown.
+ *
+ * Main menu item: File -> Quit
+ **/
+static void
+action_quit_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+
+ shell = e_shell_window_get_shell (shell_window);
+ e_shell_quit (shell);
+}
+
+/**
+ * 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;
+ 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_set_search_rule (shell_content, NULL);
+ e_shell_content_set_search_text (shell_content, NULL);
+
+ gtk_action_activate (ACTION (SEARCH_EXECUTE));
+
+ e_shell_window_update_search_menu (shell_window);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action executes the current search conditions.
+ *
+ * Main menu item: Search -> Find Now
+ **/
+
+/**
+ * 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;
+ const gchar *view_name;
+ const gchar *widget_path;
+
+ 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;
+ e_shell_view_show_popup_menu (shell_view, widget_path, NULL);
+}
+
+/**
+ * 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_SEND_RECEIVE:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens the Send & Receive Mail dialog.
+ *
+ * Main menu item: File -> Send / Receive
+ **/
+static void
+action_send_receive_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+
+ shell = e_shell_window_get_shell (shell_window);
+ e_shell_send_receive (shell, GTK_WINDOW (shell_window));
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_SHOW_SIDEBAR:
+ * @window: an #EShellWindow
+ *
+ * This toggle action controls whether the side bar is visible.
+ *
+ * Main menu item: View -> Layout -> Show Side Bar
+ **/
+static void
+action_show_sidebar_cb (GtkToggleAction *action,
+ EShellWindow *shell_window)
+{
+ GtkPaned *paned;
+ GtkWidget *widget;
+ gboolean active;
+
+ paned = GTK_PANED (shell_window->priv->content_pane);
+
+ widget = gtk_paned_get_child1 (paned);
+ active = gtk_toggle_action_get_active (action);
+ g_object_set (widget, "visible", active, NULL);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_SHOW_STATUSBAR:
+ * @window: an #EShellWindow
+ *
+ * This toggle action controls whether the status bar is visible.
+ *
+ * Main menu item: View -> Layout -> Show Status Bar
+ **/
+static void
+action_show_statusbar_cb (GtkToggleAction *action,
+ EShellWindow *shell_window)
+{
+ GtkWidget *widget;
+ gboolean active;
+
+ widget = shell_window->priv->status_area;
+ active = gtk_toggle_action_get_active (action);
+ g_object_set (widget, "visible", active, NULL);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_SHOW_SWITCHER:
+ * @window: an #EShellWindow
+ *
+ * This toggle action controls whether the switcher buttons are visible.
+ *
+ * Main menu item: View -> Switcher Appearance -> Show Buttons
+ **/
+static void
+action_show_switcher_cb (GtkToggleAction *action,
+ EShellWindow *shell_window)
+{
+ EShellSwitcher *switcher;
+ gboolean active;
+
+ switcher = E_SHELL_SWITCHER (shell_window->priv->switcher);
+ active = gtk_toggle_action_get_active (action);
+ e_shell_switcher_set_visible (switcher, active);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_SHOW_TOOLBAR:
+ * @window: an #EShellWindow
+ *
+ * This toggle action controls whether the tool bar is visible.
+ *
+ * Main menu item: View -> Layout -> Show Tool Bar
+ **/
+static void
+action_show_toolbar_cb (GtkToggleAction *action,
+ EShellWindow *shell_window)
+{
+ GtkWidget *widget;
+ gboolean active;
+
+ widget = shell_window->priv->main_toolbar;
+ active = gtk_toggle_action_get_active (action);
+ g_object_set (widget, "visible", active, NULL);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_SUBMIT_BUG:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action allows users to report a bug using
+ * Bug Buddy.
+ *
+ * Main menu item: Help -> Submit Bug Report
+ **/
+static void
+action_submit_bug_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ const gchar *command_line;
+ GError *error = NULL;
+
+ command_line = "bug-buddy --sm-disable --package=Evolution";
+
+ g_debug ("Spawning: %s", command_line);
+ g_spawn_command_line_async (command_line, &error);
+
+ if (error != NULL) {
+ const gchar *message;
+
+ if (error->code == G_SPAWN_ERROR_NOENT)
+ message = _("Bug Buddy is not installed.");
+ else
+ message = _("Bug Buddy could not be run.");
+ e_notice (shell_window, GTK_MESSAGE_ERROR, message);
+ g_error_free (error);
+ }
+}
+
+static void
+action_switcher_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EShellWindow *shell_window)
+{
+ const gchar *view_name;
+
+ view_name = g_object_get_data (G_OBJECT (current), "view-name");
+ e_shell_window_switch_to_view (shell_window, 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_SYNC_OPTIONS:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action opens the Gnome Pilot settings.
+ *
+ * Main menu item: Edit -> Synchronization Options...
+ **/
+static void
+action_sync_options_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ const gchar *command_line;
+ GError *error = NULL;
+
+ command_line = "gpilotd-control-applet";
+
+ g_debug ("Spawning: %s", command_line);
+ g_spawn_command_line_async (command_line, &error);
+
+ if (error != NULL) {
+ const gchar *message;
+
+ if (error->code == G_SPAWN_ERROR_NOENT)
+ message = _("GNOME Pilot is not installed.");
+ else
+ message = _("GNOME Pilot could not be run.");
+ e_notice (shell_window, GTK_MESSAGE_ERROR, message);
+ g_error_free (error);
+ }
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_WORK_OFFLINE:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action puts the application into offline mode.
+ *
+ * Main menu item: File -> Work Offline
+ **/
+static void
+action_work_offline_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+
+ shell = e_shell_window_get_shell (shell_window);
+ e_shell_set_online (shell, FALSE);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_WORK_ONLINE:
+ * @window: an #EShellWindow
+ *
+ * Activation of this action puts the application into online mode.
+ *
+ * Main menu item: File -> Work Online
+ **/
+static void
+action_work_online_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+
+ shell = e_shell_window_get_shell (shell_window);
+ e_shell_set_online (shell, TRUE);
+}
+
+/**
+ * E_SHELL_WINDOW_ACTION_GROUP_CUSTOM_RULES:
+ * @window: an #EShellWindow
+ **/
+
+/**
+ * E_SHELL_WINDOW_ACTION_GROUP_GAL_VIEW:
+ * @window: an #EShellWindow
+ **/
+
+/**
+ * E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM:
+ * @window: an #EShellWindow
+ **/
+
+/**
+ * E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE:
+ * @window: an #EShellWindow
+ **/
+
+/**
+ * E_SHELL_WINDOW_ACTION_GROUP_SHELL:
+ * @window: an #EShellWindow
+ **/
+
+/**
+ * E_SHELL_WINDOW_ACTION_GROUP_SWITCHER:
+ * @window: an #EShellWindow
+ **/
+
+static GtkActionEntry shell_entries[] = {
+
+ { "about",
+ GTK_STOCK_ABOUT,
+ NULL,
+ NULL,
+ N_("Show information about Evolution"),
+ G_CALLBACK (action_about_cb) },
+
+ { "close",
+ GTK_STOCK_CLOSE,
+ N_("_Close Window"),
+ "<Control>w",
+ N_("Close this window"),
+ G_CALLBACK (action_close_cb) },
+
+ { "contents",
+ GTK_STOCK_HELP,
+ N_("_Contents"),
+ "F1",
+ N_("Open the Evolution User Guide"),
+ G_CALLBACK (action_contents_cb) },
+
+ { "faq",
+ "help-faq",
+ N_("Evolution _FAQ"),
+ NULL,
+ N_("Open the Frequently Asked Questions webpage"),
+ G_CALLBACK (action_faq_cb) },
+
+ { "forget-passwords",
+ NULL,
+ N_("_Forget Passwords"),
+ NULL,
+ N_("Forget all remembered passwords"),
+ G_CALLBACK (action_forget_passwords_cb) },
+
+ { "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"),
+ "<Control><Shift>w",
+ N_("Create a new window displaying this view"),
+ G_CALLBACK (action_new_window_cb) },
+
+ { "preferences",
+ GTK_STOCK_PREFERENCES,
+ NULL,
+ "<Control><Shift>s",
+ N_("Configure Evolution"),
+ G_CALLBACK (action_preferences_cb) },
+
+ { "quick-reference",
+ NULL,
+ N_("_Quick Reference"),
+ NULL,
+ N_("Show Evolution's shortcut keys"),
+ G_CALLBACK (action_quick_reference_cb) },
+
+ { "quit",
+ GTK_STOCK_QUIT,
+ NULL,
+ NULL,
+ N_("Exit the program"),
+ G_CALLBACK (action_quit_cb) },
+
+ { "search-advanced",
+ NULL,
+ N_("_Advanced Search..."),
+ NULL,
+ N_("Construct a more advanced search"),
+ G_CALLBACK (action_search_advanced_cb) },
+
+ { "search-clear",
+ GTK_STOCK_CLEAR,
+ NULL,
+ "<Control><Shift>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-execute",
+ GTK_STOCK_FIND,
+ N_("_Find Now"),
+ "", /* Block the default Ctrl+F. */
+ N_("Execute the current search parameters"),
+ NULL }, /* Handled by EShellContent and subclasses. */
+
+ { "search-options",
+ GTK_STOCK_FIND,
+ NULL,
+ NULL,
+ N_("Click here to change the search type"),
+ G_CALLBACK (action_search_options_cb) },
+
+ { "search-save",
+ NULL,
+ N_("_Save Search..."),
+ NULL,
+ N_("Save the current search parameters"),
+ G_CALLBACK (action_search_save_cb) },
+
+ { "send-receive",
+ "mail-send-receive",
+ N_("Send / _Receive"),
+ "F9",
+ N_("Send queued items and retrieve new items"),
+ G_CALLBACK (action_send_receive_cb) },
+
+ { "submit-bug",
+ NULL,
+ N_("Submit _Bug Report"),
+ NULL,
+ N_("Submit a bug report using Bug Buddy"),
+ G_CALLBACK (action_submit_bug_cb) },
+
+ { "sync-options",
+ NULL,
+ N_("_Synchronization Options..."),
+ NULL,
+ N_("Set up Pilot configuration"),
+ G_CALLBACK (action_sync_options_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",
+ GTK_STOCK_NEW,
+ N_("_New"),
+ "",
+ 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 GtkToggleActionEntry shell_toggle_entries[] = {
+
+ { "show-sidebar",
+ NULL,
+ N_("Show Side _Bar"),
+ NULL,
+ N_("Show the side bar"),
+ G_CALLBACK (action_show_sidebar_cb),
+ TRUE },
+
+ { "show-statusbar",
+ NULL,
+ N_("Show _Status Bar"),
+ NULL,
+ N_("Show the status bar"),
+ G_CALLBACK (action_show_statusbar_cb),
+ TRUE },
+
+ { "show-switcher",
+ NULL,
+ N_("Show _Buttons"),
+ NULL,
+ N_("Show the switcher buttons"),
+ G_CALLBACK (action_show_switcher_cb),
+ TRUE },
+
+ { "show-toolbar",
+ NULL,
+ N_("Show _Tool Bar"),
+ NULL,
+ N_("Show the toolbar"),
+ G_CALLBACK (action_show_toolbar_cb),
+ 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-define-views",
+ NULL,
+ N_("Define Views..."),
+ NULL,
+ N_("Create or edit views"),
+ G_CALLBACK (action_gal_define_views_cb) },
+
+ { "gal-save-custom-view",
+ NULL,
+ N_("Save Custom View..."),
+ NULL,
+ N_("Save current custom view"),
+ NULL }, /* Handled by subclasses. */
+
+ /*** 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",
+ GTK_STOCK_PAGE_SETUP,
+ NULL,
+ 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 (strcmp (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)
+{
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
+
+ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+
+ ui_manager = e_shell_window_get_ui_manager (shell_window);
+
+ e_load_ui_definition (ui_manager, "evolution-shell.ui");
+
+ /* Shell Actions */
+ action_group = ACTION_GROUP (SHELL);
+ gtk_action_group_add_actions (
+ action_group, shell_entries,
+ G_N_ELEMENTS (shell_entries), shell_window);
+ 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);
+
+ /* Fine tuning. */
+
+ g_object_set (ACTION (SEND_RECEIVE), "is-important", TRUE, NULL);
+}
+
+GtkWidget *
+e_shell_window_create_new_menu (EShellWindow *shell_window)
+{
+ GtkActionGroup *action_group;
+ GList *new_item_actions;
+ GList *new_source_actions;
+ GList *iter, *list = NULL;
+ GtkWidget *menu;
+ GtkWidget *separator;
+
+ /* Get sorted lists of "new item" and "new source" actions. */
+
+ 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. */
+
+ separator = gtk_separator_menu_item_new ();
+ new_item_actions = g_list_prepend (new_item_actions, separator);
+ gtk_widget_show (GTK_WIDGET (separator));
+
+ separator = gtk_separator_menu_item_new ();
+ new_source_actions = g_list_prepend (new_source_actions, separator);
+ gtk_widget_show (GTK_WIDGET (separator));
+
+ /* 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;
+}
+
+void
+e_shell_window_create_switcher_actions (EShellWindow *shell_window)
+{
+ GSList *group = NULL;
+ GtkRadioAction *action;
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
+ EShellSwitcher *switcher;
+ EShell *shell;
+ GList *list, *iter;
+ guint merge_id;
+ guint ii = 0;
+
+ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+
+ action_group = ACTION_GROUP (SWITCHER);
+ 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);
+ shell = e_shell_window_get_shell (shell_window);
+ list = e_shell_get_shell_backends (shell);
+
+ /* Construct a group of radio actions from the various EShellView
+ * subclasses and register them with the EShellSwitcher. These
+ * actions are manifested as switcher buttons and View->Window
+ * menu items. */
+
+ action = GTK_RADIO_ACTION (ACTION (SWITCHER_INITIAL));
+ gtk_radio_action_set_group (action, group);
+ group = gtk_radio_action_get_group (action);
+
+ for (iter = list; iter != NULL; iter = iter->next) {
+ EShellBackend *shell_backend = iter->data;
+ EShellBackendClass *backend_class;
+ EShellViewClass *class;
+ GType view_type;
+ const gchar *view_name;
+ gchar *accelerator;
+ gchar *action_name;
+ gchar *tooltip;
+
+ /* 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;
+
+ 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;
+ }
+
+ class = g_type_class_ref (view_type);
+
+ if (class->label == NULL) {
+ g_critical (
+ "Label member not set on %s",
+ G_OBJECT_CLASS_NAME (class));
+ continue;
+ }
+
+ action_name = g_strdup_printf (SWITCHER_FORMAT, view_name);
+ tooltip = g_strdup_printf (_("Switch to %s"), class->label);
+
+ /* Note, we have to set "icon-name" separately because
+ * gtk_radio_action_new() expects a "stock-id". Sadly,
+ * GTK+ still distinguishes between the two. */
+
+ action = gtk_radio_action_new (
+ action_name, class->label,
+ tooltip, NULL, ii++);
+
+ g_object_set (
+ G_OBJECT (action),
+ "icon-name", class->icon_name, NULL);
+
+ g_object_set_data (
+ G_OBJECT (action),
+ "view-name", (gpointer) view_name);
+
+ gtk_radio_action_set_group (action, group);
+ group = gtk_radio_action_get_group (action);
+
+ /* The first nine views have accelerators Ctrl+(1-9). */
+ if (ii < 10)
+ accelerator = g_strdup_printf ("<Control>%d", ii);
+ else
+ accelerator = g_strdup ("");
+
+ gtk_action_group_add_action_with_accel (
+ action_group, GTK_ACTION (action), accelerator);
+
+ e_shell_switcher_add_action (switcher, GTK_ACTION (action));
+
+ gtk_ui_manager_add_ui (
+ ui_manager, merge_id,
+ "/main-menu/view-menu/window-menu",
+ action_name, action_name,
+ GTK_UI_MANAGER_AUTO, FALSE);
+
+ g_free (accelerator);
+ g_free (action_name);
+ g_free (tooltip);
+
+ g_type_class_unref (class);
+ }
+}
+
+void
+e_shell_window_update_view_menu (EShellWindow *shell_window)
+{
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ GalViewCollection *view_collection;
+ GtkRadioAction *radio_action;
+ GtkAction *action;
+ GSList *radio_group;
+ gboolean visible;
+ const gchar *path;
+ const gchar *view_id;
+ const gchar *view_name;
+ 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);
+
+ /* 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;
+
+ item = gal_view_collection_get_view_item (view_collection, ii);
+
+ action_name = g_strdup_printf (
+ "gal-view-%s-%d", view_name, ii);
+ tooltip = g_strdup_printf ("Select view: %s", item->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);
+
+ 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);
+ }
+
+ /* 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);
+}
+
+void
+e_shell_window_update_search_menu (EShellWindow *shell_window)
+{
+ EShellContent *shell_content;
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ RuleContext *context;
+ FilterRule *rule;
+ GtkUIManager *ui_manager;
+ GtkActionGroup *action_group;
+ const gchar *source;
+ const gchar *view_name;
+ gboolean sensitive;
+ guint merge_id;
+ gint ii = 0;
+
+ 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);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ context = e_shell_content_get_search_context (shell_content);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ source = FILTER_SOURCE_INCOMING;
+
+ /* Update sensitivity of search actions. */
+
+ sensitive = (e_shell_content_get_search_rule (shell_content) != NULL);
+ gtk_action_set_sensitive (ACTION (SEARCH_CLEAR), sensitive);
+ gtk_action_set_sensitive (ACTION (SEARCH_SAVE), sensitive);
+
+ sensitive = (shell_view_class->search_options != NULL);
+ gtk_action_set_sensitive (ACTION (SEARCH_OPTIONS), sensitive);
+
+ /* 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);
+
+ rule = rule_context_next_rule (context, NULL, source);
+ while (rule != NULL) {
+ GtkAction *action;
+ gchar *action_name;
+ gchar *action_label;
+
+ action_name = g_strdup_printf ("custom-rule-%d", ii++);
+ if (ii < 10)
+ action_label = g_strdup_printf (
+ "_%d. %s", ii, rule->name);
+ else
+ action_label = g_strdup (rule->name);
+
+ 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);
+
+ g_free (action_name);
+ g_free (action_label);
+
+ rule = rule_context_next_rule (context, rule, source);
+ }
+}
diff --cc shell/e-shell-window-actions.h
index 87ae132,0000000..3b8774a
mode 100644,000000..100644
--- a/shell/e-shell-window-actions.h
+++ b/shell/e-shell-window-actions.h
@@@ -1,123 -1,0 +1,123 @@@
+/*
+ * e-shell-window-actions.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_SHELL_WINDOW_ACTIONS_H
+#define E_SHELL_WINDOW_ACTIONS_H
+
+#define E_SHELL_WINDOW_ACTION(window, name) \
+ (e_shell_window_get_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)))
+
+/* Actions */
+#define E_SHELL_WINDOW_ACTION_ABOUT(window) \
+ E_SHELL_WINDOW_ACTION ((window), "about")
+#define E_SHELL_WINDOW_ACTION_CLOSE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "close")
+#define E_SHELL_WINDOW_ACTION_CONTENTS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "contents")
+#define E_SHELL_WINDOW_ACTION_FAQ(window) \
+ E_SHELL_WINDOW_ACTION ((window), "faq")
+#define E_SHELL_WINDOW_ACTION_FORGET_PASSWORDS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "forget-passwords")
+#define E_SHELL_WINDOW_ACTION_GAL_CUSTOM_VIEW(window) \
+ E_SHELL_WINDOW_ACTION ((window), "gal-custom-view")
+#define E_SHELL_WINDOW_ACTION_GAL_DEFINE_VIEWS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "gal-define-views")
+#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) \
+ E_SHELL_WINDOW_ACTION ((window), "new-window")
+#define E_SHELL_WINDOW_ACTION_PAGE_SETUP(window) \
+ E_SHELL_WINDOW_ACTION ((window), "page-setup")
+#define E_SHELL_WINDOW_ACTION_PREFERENCES(window) \
+ E_SHELL_WINDOW_ACTION ((window), "preferences")
+#define E_SHELL_WINDOW_ACTION_QUICK_REFERENCE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "quick-reference")
+#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_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_EXECUTE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "search-execute")
+#define E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "search-options")
+#define E_SHELL_WINDOW_ACTION_SEARCH_SAVE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "search-save")
+#define E_SHELL_WINDOW_ACTION_SEND_RECEIVE(window) \
+ E_SHELL_WINDOW_ACTION ((window), "send-receive")
+#define E_SHELL_WINDOW_ACTION_SHOW_SIDEBAR(window) \
+ E_SHELL_WINDOW_ACTION ((window), "show-sidebar")
+#define E_SHELL_WINDOW_ACTION_SHOW_STATUSBAR(window) \
+ E_SHELL_WINDOW_ACTION ((window), "show-statusbar")
+#define E_SHELL_WINDOW_ACTION_SHOW_SWITCHER(window) \
+ E_SHELL_WINDOW_ACTION ((window), "show-switcher")
+#define E_SHELL_WINDOW_ACTION_SHOW_TOOLBAR(window) \
+ E_SHELL_WINDOW_ACTION ((window), "show-toolbar")
+#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_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_SYNC_OPTIONS(window) \
+ E_SHELL_WINDOW_ACTION ((window), "sync-options")
+#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) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "lockdown-printing")
+#define E_SHELL_WINDOW_ACTION_GROUP_LOCKDOWN_PRINT_SETUP(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "lockdown-print-setup")
+#define E_SHELL_WINDOW_ACTION_GROUP_LOCKDOWN_SAVE_TO_DISK(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "lockdown-save-to-disk")
+#define E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM(window) \
+ E_SHELL_WINDOW_ACTION_GROUP ((window), "new-item")
+#define E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE(window) \
+ 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")
+
+#endif /* E_SHELL_WINDOW_ACTIONS_H */
diff --cc shell/e-shell-window-private.c
index 38d3926,0000000..bb74e35
mode 100644,000000..100644
--- a/shell/e-shell-window-private.c
+++ b/shell/e-shell-window-private.c
@@@ -1,575 -1,0 +1,575 @@@
+/*
+ * e-shell-window-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-window-private.h"
+
+static void
+shell_window_save_switcher_style_cb (GtkRadioAction *action,
+ GtkRadioAction *current,
+ EShellWindow *shell_window)
+{
+ EShell *shell;
+ GConfClient *client;
+ GtkToolbarStyle style;
+ const gchar *key;
+ const gchar *string;
+ GError *error = NULL;
+
+ shell = e_shell_window_get_shell (shell_window);
+ client = e_shell_get_gconf_client (shell);
+
+ style = gtk_radio_action_get_current_value (action);
+ key = "/apps/evolution/shell/view_defaults/buttons_style";
+
+ 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;
+ }
+
+ if (!gconf_client_set_string (client, key, string, &error)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+shell_window_init_switcher_style (EShellWindow *shell_window)
+{
+ EShell *shell;
+ GtkAction *action;
+ GConfClient *client;
+ GtkToolbarStyle style;
+ const gchar *key;
+ gchar *string;
+ GError *error = NULL;
+
+ /* XXX GConfBridge doesn't let you convert between numeric properties
+ * and string keys, so we have to create the binding manually. */
+
+ shell = e_shell_window_get_shell (shell_window);
+ client = e_shell_get_gconf_client (shell);
+
+ action = ACTION (SWITCHER_STYLE_ICONS);
+ key = "/apps/evolution/shell/view_defaults/buttons_style";
+ string = gconf_client_get_string (client, key, &error);
+
+ 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_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 *menu_item)
+{
+ GtkAction *action;
+ GtkLabel *label;
+ gchar *tooltip = NULL;
+
+ action = g_object_get_data (G_OBJECT (menu_item), "action");
+ g_return_if_fail (GTK_IS_ACTION (action));
+
+ g_object_get (action, "tooltip", &tooltip, NULL);
+
+ if (tooltip == NULL)
+ return;
+
+ label = GTK_LABEL (shell_window->priv->tooltip_label);
+ gtk_label_set_text (label, tooltip);
+ g_free (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_object_set_data_full (
+ G_OBJECT (proxy),
+ "action", g_object_ref (action),
+ (GDestroyNotify) g_object_unref);
+
+ 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 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));
+}
+
+void
+e_shell_window_private_init (EShellWindow *shell_window)
+{
+ EShellWindowPrivate *priv = shell_window->priv;
+ GHashTable *loaded_views;
+ GArray *signal_handler_ids;
+ GtkAccelGroup *accel_group;
+ GtkToolItem *item;
+ GtkWidget *container;
+ GtkWidget *widget;
+ guint merge_id;
+ gint height;
+
+ loaded_views = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ signal_handler_ids = g_array_new (FALSE, FALSE, sizeof (gulong));
+
+ priv->ui_manager = gtk_ui_manager_new ();
+ priv->loaded_views = loaded_views;
+ priv->active_view = "unknown";
+ priv->signal_handler_ids = signal_handler_ids;
+
+ 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, "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");
+
+ merge_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
+ priv->custom_rule_merge_id = merge_id;
+
+ merge_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
+ priv->gal_view_merge_id = merge_id;
+
+ e_shell_window_actions_init (shell_window);
+
+ accel_group = gtk_ui_manager_get_accel_group (priv->ui_manager);
+ gtk_window_add_accel_group (GTK_WINDOW (shell_window), accel_group);
+
+ g_signal_connect_swapped (
+ priv->ui_manager, "connect-proxy",
+ G_CALLBACK (shell_window_connect_proxy_cb), shell_window);
+
+ /* Construct window widgets. */
+
+ widget = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (shell_window), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_shell_window_get_managed_widget (
+ shell_window, "/main-menu");
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->main_menu = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = e_shell_window_get_managed_widget (
+ shell_window, "/main-toolbar");
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->main_toolbar = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* 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()
+ * returns 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 (widget), item, 0);
+ gtk_widget_show (GTK_WIDGET (item));
+
+ item = e_menu_tool_button_new (_("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 (priv->ui_manager),
+ GDK_N, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
+ gtk_toolbar_insert (GTK_TOOLBAR (widget), item, 0);
+ priv->menu_tool_button = g_object_ref (item);
+ gtk_widget_show (GTK_WIDGET (item));
+
+ widget = gtk_hpaned_new ();
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ priv->content_pane = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_hbox_new (FALSE, 3);
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ priv->status_area = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* 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 (widget, -1, (height * 2) + 6);
+
+ container = priv->content_pane;
+
+ widget = e_shell_switcher_new ();
+ gtk_paned_pack1 (GTK_PANED (container), widget, FALSE, FALSE);
+ priv->switcher = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
+ gtk_paned_pack2 (GTK_PANED (container), widget, TRUE, TRUE);
+ priv->content_notebook = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->switcher;
+
+ widget = gtk_notebook_new ();
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ priv->sidebar_notebook = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = priv->status_area;
+
+ widget = e_online_button_new ();
+ g_signal_connect (
+ widget, "clicked",
+ G_CALLBACK (shell_window_online_button_clicked_cb),
+ shell_window);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0);
+ priv->online_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new ("");
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ priv->tooltip_label = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ 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 (container), widget, TRUE, TRUE, 0);
+ priv->status_notebook = g_object_ref (widget);
+ gtk_widget_show (widget);
+}
+
+void
+e_shell_window_private_constructed (EShellWindow *shell_window)
+{
+ EShellWindowPrivate *priv = shell_window->priv;
+ EShellSettings *shell_settings;
+ EShell *shell;
+ GConfBridge *bridge;
+ GtkActionGroup *action_group;
+ GtkAction *action;
+ GObject *object;
+ const gchar *key;
+
+ shell = e_shell_window_get_shell (shell_window);
+ shell_settings = e_shell_get_shell_settings (shell);
+
+ e_shell_watch_window (shell, GTK_WINDOW (shell_window));
+
+ /* 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);
+
+ /* Support lockdown. */
+
+ action_group = ACTION_GROUP (LOCKDOWN_PRINTING);
+
+ e_binding_new_with_negation (
+ G_OBJECT (shell_settings), "disable-printing",
+ G_OBJECT (action_group), "sensitive");
+
+ action_group = ACTION_GROUP (LOCKDOWN_PRINT_SETUP);
+
+ e_binding_new_with_negation (
+ G_OBJECT (shell_settings), "disable-print-setup",
+ G_OBJECT (action_group), "sensitive");
+
+ action_group = ACTION_GROUP (LOCKDOWN_SAVE_TO_DISK);
+
+ e_binding_new_with_negation (
+ G_OBJECT (shell_settings), "disable-save-to-disk",
+ G_OBJECT (action_group), "sensitive");
+
+ /* Bind GObject properties to GObject properties. */
+
+ action = ACTION (SEND_RECEIVE);
+
+ e_binding_new (
+ G_OBJECT (shell), "online",
+ G_OBJECT (action), "sensitive");
+
+ action = ACTION (WORK_OFFLINE);
+
+ e_binding_new (
+ G_OBJECT (shell), "online",
+ G_OBJECT (action), "visible");
+
+ action = ACTION (WORK_ONLINE);
+
+ e_binding_new_with_negation (
+ G_OBJECT (shell), "online",
+ G_OBJECT (action), "visible");
+
+ e_binding_new (
+ G_OBJECT (shell), "online",
+ G_OBJECT (shell_window->priv->online_button), "online");
+
+ /* Bind GObject properties to GConf keys. */
+
+ bridge = gconf_bridge_get ();
+
+ key = "/apps/evolution/shell/view_defaults/window";
+ gconf_bridge_bind_window (
+ bridge, key, GTK_WINDOW (shell_window), TRUE, FALSE);
+
+ object = G_OBJECT (shell_window);
+ key = "/apps/evolution/shell/view_defaults/component_id";
+ gconf_bridge_bind_property (bridge, key, object, "active-view");
+
+ object = G_OBJECT (priv->content_pane);
+ key = "/apps/evolution/shell/view_defaults/folder_bar/width";
+ gconf_bridge_bind_property_delayed (bridge, key, object, "position");
+
+ object = G_OBJECT (ACTION (SHOW_SIDEBAR));
+ key = "/apps/evolution/shell/view_defaults/sidebar_visible";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ object = G_OBJECT (ACTION (SHOW_STATUSBAR));
+ key = "/apps/evolution/shell/view_defaults/statusbar_visible";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ object = G_OBJECT (ACTION (SHOW_SWITCHER));
+ key = "/apps/evolution/shell/view_defaults/buttons_visible";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ object = G_OBJECT (ACTION (SHOW_TOOLBAR));
+ key = "/apps/evolution/shell/view_defaults/toolbar_visible";
+ gconf_bridge_bind_property (bridge, key, object, "active");
+
+ shell_window_init_switcher_style (shell_window);
+}
+
+void
+e_shell_window_private_dispose (EShellWindow *shell_window)
+{
+ EShellWindowPrivate *priv = shell_window->priv;
+
+ /* Need to disconnect handlers before we unref the shell. */
+ if (priv->signal_handler_ids != NULL) {
+ GArray *array = priv->signal_handler_ids;
+ gulong handler_id;
+ guint ii;
+
+ for (ii = 0; ii < array->len; ii++) {
+ handler_id = g_array_index (array, gulong, ii);
+ g_signal_handler_disconnect (priv->shell, handler_id);
+ }
+
+ g_array_free (array, TRUE);
+ priv->signal_handler_ids = NULL;
+ }
+
+ DISPOSE (priv->ui_manager);
+
+ g_hash_table_remove_all (priv->loaded_views);
+
+ DISPOSE (priv->main_menu);
+ DISPOSE (priv->main_toolbar);
+ DISPOSE (priv->menu_tool_button);
+ DISPOSE (priv->content_pane);
+ DISPOSE (priv->content_notebook);
+ DISPOSE (priv->sidebar_notebook);
+ DISPOSE (priv->switcher);
+ DISPOSE (priv->status_area);
+ DISPOSE (priv->online_button);
+ DISPOSE (priv->tooltip_label);
+ DISPOSE (priv->status_notebook);
+
+ priv->destroyed = TRUE;
+}
+
+void
+e_shell_window_private_finalize (EShellWindow *shell_window)
+{
+ EShellWindowPrivate *priv = shell_window->priv;
+
+ g_hash_table_destroy (priv->loaded_views);
+}
+
+void
+e_shell_window_switch_to_view (EShellWindow *shell_window,
+ const gchar *view_name)
+{
+ GtkNotebook *notebook;
+ EShellView *shell_view;
+ gint page_num;
+
+ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+ g_return_if_fail (view_name != NULL);
+
+ 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);
+
+ notebook = GTK_NOTEBOOK (shell_window->priv->content_notebook);
+ gtk_notebook_set_current_page (notebook, page_num);
+
+ notebook = GTK_NOTEBOOK (shell_window->priv->sidebar_notebook);
+ gtk_notebook_set_current_page (notebook, page_num);
+
+ notebook = GTK_NOTEBOOK (shell_window->priv->status_notebook);
+ gtk_notebook_set_current_page (notebook, page_num);
+
+ shell_window->priv->active_view = view_name;
+ g_object_notify (G_OBJECT (shell_window), "active-view");
+
+ e_shell_window_update_icon (shell_window);
+ e_shell_window_update_title (shell_window);
+ e_shell_window_update_new_menu (shell_window);
+ e_shell_window_update_view_menu (shell_window);
+ e_shell_window_update_search_menu (shell_window);
+
+ e_shell_view_update_actions (shell_view);
+}
+
+void
+e_shell_window_update_icon (EShellWindow *shell_window)
+{
+ EShellView *shell_view;
+ GtkAction *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);
+}
+
+void
+e_shell_window_update_title (EShellWindow *shell_window)
+{
+ EShellView *shell_view;
+ const gchar *view_title;
+ const gchar *view_name;
+ gchar *window_title;
+
+ 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);
+ view_title = e_shell_view_get_title (shell_view);
+
+ /* Translators: This is used for the main window title. */
+ window_title = g_strdup_printf (_("%s - Evolution"), view_title);
+ gtk_window_set_title (GTK_WINDOW (shell_window), window_title);
+ g_free (window_title);
+}
+
+void
+e_shell_window_update_new_menu (EShellWindow *shell_window)
+{
+ GtkWidget *menu;
+ GtkWidget *widget;
+ const gchar *path;
+
+ g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));
+
+ /* 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);
+
+ /* Update the "New" menu tool button submenu. */
+ menu = e_shell_window_create_new_menu (shell_window);
+ widget = shell_window->priv->menu_tool_button;
+ gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (widget), menu);
+}
diff --cc shell/e-shell-window-private.h
index 3ac0388,0000000..b0bfe7c
mode 100644,000000..100644
--- a/shell/e-shell-window-private.h
+++ b/shell/e-shell-window-private.h
@@@ -1,127 -1,0 +1,127 @@@
+/*
+ * e-shell-window-private.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_SHELL_WINDOW_PRIVATE_H
+#define E_SHELL_WINDOW_PRIVATE_H
+
+#include "e-shell-window.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include <e-util/e-util.h>
+#include <e-util/e-binding.h>
+#include <e-util/gconf-bridge.h>
+#include <widgets/misc/e-menu-tool-button.h>
+#include <widgets/misc/e-online-button.h>
+
+#include <e-shell.h>
+#include <e-shell-content.h>
+#include <e-shell-view.h>
+#include <e-shell-switcher.h>
+#include <e-shell-window-actions.h>
+
+#define E_SHELL_WINDOW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SHELL_WINDOW, EShellWindowPrivate))
+
+/* Shorthand, requires a variable named "shell_window". */
+#define ACTION(name) \
+ (E_SHELL_WINDOW_ACTION_##name (shell_window))
+#define ACTION_GROUP(name) \
+ (E_SHELL_WINDOW_ACTION_GROUP_##name (shell_window))
+
+/* For use in dispose() methods. */
+#define DISPOSE(obj) \
+ G_STMT_START { \
+ if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
+ } G_STMT_END
+
+/* Format for switcher action names.
+ * The last part is the shell view name.
+ * (e.g. switch-to-mail, switch-to-calendar) */
+#define SWITCHER_FORMAT "switch-to-%s"
+
+G_BEGIN_DECLS
+
+struct _EShellWindowPrivate {
+
+ gpointer shell; /* weak pointer */
+
+ /*** UI Management ***/
+
+ GtkUIManager *ui_manager;
+ guint custom_rule_merge_id;
+ guint gal_view_merge_id;
+
+ /*** Shell Views ***/
+
+ GHashTable *loaded_views;
+ const gchar *active_view;
+
+ /*** Widgetry ***/
+
+ GtkWidget *main_menu;
+ GtkWidget *main_toolbar;
+ GtkWidget *menu_tool_button;
+ GtkWidget *content_pane;
+ GtkWidget *content_notebook;
+ GtkWidget *sidebar_notebook;
+ GtkWidget *switcher;
+ GtkWidget *status_area;
+ GtkWidget *online_button;
+ GtkWidget *tooltip_label;
+ GtkWidget *status_notebook;
+
+ /* Miscellaneous */
+
+ /* Shell signal handlers. */
+ GArray *signal_handler_ids;
+
+ guint destroyed : 1; /* XXX Do we still need this? */
+ guint safe_mode : 1;
+};
+
+void e_shell_window_private_init (EShellWindow *shell_window);
+void e_shell_window_private_constructed
+ (EShellWindow *shell_window);
+void e_shell_window_private_dispose (EShellWindow *shell_window);
+void e_shell_window_private_finalize (EShellWindow *shell_window);
+
+/* Private Utilities */
+
+void e_shell_window_actions_init (EShellWindow *shell_window);
+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);
+
+G_END_DECLS
+
+#endif /* E_SHELL_WINDOW_PRIVATE_H */
diff --cc shell/e-shell-window.c
index c39d856,83e537c..bb913f7
--- a/shell/e-shell-window.c
+++ b/shell/e-shell-window.c
@@@ -12,9 -10,12 +12,9 @@@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Ettore Perazzoli <ettore ximian com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
diff --cc shell/e-shell-window.h
index d78fb19,869352b..b867490
--- a/shell/e-shell-window.h
+++ b/shell/e-shell-window.h
@@@ -12,9 -11,12 +12,9 @@@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Ettore Perazzoli <ettore ximian com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
diff --cc shell/e-shell.c
index d95853d,9b4e6bc..7854853
--- a/shell/e-shell.c
+++ b/shell/e-shell.c
@@@ -12,9 -10,12 +12,9 @@@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Ettore Perazzoli <ettore ximian com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
diff --cc shell/e-shell.h
index c76b649,e8451e3..1d0b9ab
--- a/shell/e-shell.h
+++ b/shell/e-shell.h
@@@ -12,9 -10,12 +12,9 @@@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
- * Authors:
- * Ettore Perazzoli <ettore ximian com>
- *
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
diff --cc shell/main.c
index c71d686,c6959d7..928a321
--- a/shell/main.c
+++ b/shell/main.c
@@@ -465,174 -562,6 +466,174 @@@ set_paths (void
}
#endif
+static void
+shell_window_destroyed_cb (EShell *shell)
+{
+ if (e_shell_get_watched_windows (shell) == NULL)
+ gtk_main_quit ();
+}
+
+static gint
+master_client_save_yourself_cb (GnomeClient *client,
+ GnomeSaveStyle save_style,
+ gint shutdown,
+ GnomeInteractStyle interact_style,
+ gint fast,
+ gpointer user_data)
+{
+ EShell *shell = user_data;
+
+ return !e_shell_is_busy (shell);
+}
+
+static void
+master_client_die_cb (GnomeClient *client,
+ gpointer user_data)
+{
+ EShell *shell = user_data;
+
+ e_shell_do_quit (shell);
+}
+
+/* taken from nautilus */
+static guint32
+slowly_and_stupidly_obtain_timestamp (GdkDisplay *display)
+{
+ Display *xdisplay;
+ Window xwindow;
+ XEvent event;
+ XSetWindowAttributes attrs;
+ Atom atom_name;
+ Atom atom_type;
- char *name;
++ const gchar *name;
+
+ xdisplay = GDK_DISPLAY_XDISPLAY (display);
+
+ attrs.override_redirect = True;
+ attrs.event_mask = PropertyChangeMask | StructureNotifyMask;
+
+ xwindow = XCreateWindow (
+ xdisplay, RootWindow (xdisplay, 0),
+ -100, -100, 1, 1,
+ 0,
+ CopyFromParent,
+ CopyFromParent,
+ CopyFromParent,
+ CWOverrideRedirect | CWEventMask,
+ &attrs);
+
+ atom_name = XInternAtom (xdisplay, "WM_NAME", TRUE);
+ g_assert (atom_name != None);
+
+ atom_type = XInternAtom (xdisplay, "STRING", TRUE);
+ g_assert (atom_type != None);
+
+ name = "Fake Window";
+ XChangeProperty (
+ xdisplay, xwindow, atom_name, atom_type,
+ 8, PropModeReplace, (unsigned char *) name,
+ strlen (name));
+
+ XWindowEvent (
+ xdisplay, xwindow, PropertyChangeMask, &event);
+
+ XDestroyWindow (xdisplay, xwindow);
+
+ return event.xproperty.time;
+}
+
+static gchar *
+pick_startup_id (void)
+{
+ GdkDisplay *display;
+ const gchar *startup_id;
+ gchar *id;
+
+ /* XXX This copies logic from unique_app_new(), which we can't use
+ * because we're subclassing UniqueApp. I already sent ebassi
+ * a patch to fix this. */
+
+ display = gdk_display_get_default ();
+
+ /* Try and get the startup notification ID from GDK, the
+ * environment or, if everything else failed, fake one. */
+ startup_id = gdk_x11_display_get_startup_notification_id (display);
+
+ if (!startup_id || startup_id[0] == '\0')
+ startup_id = g_getenv ("DESKTOP_STARTUP_ID");
+
+ if (!startup_id || startup_id[0] == '\0') {
+ guint32 timestamp;
+
+ timestamp = slowly_and_stupidly_obtain_timestamp (display);
+ id = g_strdup_printf ("_TIME%lu", (gulong) timestamp);
+ } else
+ id = g_strdup (startup_id);
+
+ return id;
+}
+
+static void
+create_default_shell (void)
+{
+ EShell *shell;
+ GConfClient *conf_client;
+ GnomeClient *master_client;
+ gboolean online = TRUE;
+ gchar *startup_id;
+ GError *error = NULL;
+
+ conf_client = gconf_client_get_default ();
+ master_client = gnome_master_client ();
+
+ if (start_online)
+ online = TRUE;
+ else if (start_offline)
+ online = FALSE;
+ else {
+ const gchar *key;
+ gboolean value;
+
+ key = "/apps/evolution/shell/start_offline";
+ value = gconf_client_get_bool (conf_client, key, &error);
+ if (error == NULL)
+ online = !value;
+ else {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+ }
+
+ startup_id = pick_startup_id ();
+
+ shell = g_object_new (
+ E_TYPE_SHELL,
+ "name", "org.gnome.evolution",
+ "online", online,
+ "startup-id", startup_id,
+ NULL);
+
+ g_free (startup_id);
+
+ g_signal_connect (
+ shell, "window-destroyed",
+ G_CALLBACK (shell_window_destroyed_cb), NULL);
+
+ if (master_client != NULL) {
+ g_signal_connect (
+ master_client, "save_yourself",
+ G_CALLBACK (master_client_save_yourself_cb), shell);
+
+ g_signal_connect (
+ master_client, "die",
+ G_CALLBACK (master_client_die_cb), shell);
+ }
+
+ g_object_unref (conf_client);
+
+ default_shell = shell;
+}
+
int
main (int argc, char **argv)
{
diff --cc shell/test/e-test-shell-backend.c
index 0fc6c20,0000000..e5fd3c6
mode 100644,000000..100644
--- a/shell/test/e-test-shell-backend.c
+++ b/shell/test/e-test-shell-backend.c
@@@ -1,240 -1,0 +1,240 @@@
+/*
+ * e-test-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-test-shell-backend.h"
+
+#include <glib/gi18n.h>
+
+#include "shell/e-shell.h"
+#include "shell/e-shell-window.h"
+
+#include "e-test-shell-view.h"
+
+#define E_TEST_SHELL_BACKEND_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TEST_SHELL_BACKEND, ETestShellBackendPrivate))
+
+struct _ETestShellBackendPrivate {
+ gint placeholder;
+};
+
+static gpointer parent_class;
+static GType test_shell_backend_type;
+
+static void
+action_test_item_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ g_debug ("%s", G_STRFUNC);
+}
+
+static void
+action_test_source_new_cb (GtkAction *action,
+ EShellWindow *shell_window)
+{
+ g_debug ("%s", G_STRFUNC);
+}
+
+static GtkActionEntry item_entries[] = {
+
+ { "test-item-new",
+ "document-new",
+ NC_("New", "_Test Item"),
+ NULL,
+ N_("Create a new test item"),
+ G_CALLBACK (action_test_item_new_cb) }
+};
+
+static GtkActionEntry source_entries[] = {
+
+ { "test-source-new",
+ "folder-new",
+ NC_("New", "Test _Source"),
+ NULL,
+ N_("Create a new test source"),
+ G_CALLBACK (action_test_source_new_cb) }
+};
+
+static void
+test_shell_backend_start (EShellBackend *shell_backend)
+{
+ g_debug ("%s", G_STRFUNC);
+}
+
+static gboolean
+test_shell_backend_is_busy (EShellBackend *shell_backend)
+{
+ g_debug ("%s", G_STRFUNC);
+
+ return FALSE;
+}
+
+static gboolean
+test_shell_backend_shutdown (EShellBackend *shell_backend)
+{
+ g_debug ("%s", G_STRFUNC);
+
+ return TRUE;
+}
+
+static gboolean
+test_shell_backend_migrate (EShellBackend *shell_backend,
+ gint major,
+ gint minor,
+ gint micro,
+ GError **error)
+{
+ g_debug ("%s (from %d.%d.%d)", G_STRFUNC, major, minor, micro);
+
+ return TRUE;
+}
+
+static gboolean
+test_shell_backend_handle_uri_cb (EShellBackend *shell_backend,
+ const gchar *uri)
+{
+ g_debug ("%s (uri=%s)", G_STRFUNC, uri);
+
+ return FALSE;
+}
+
+static void
+test_shell_backend_send_receive_cb (EShellBackend *shell_backend,
+ GtkWindow *parent_window)
+{
+ g_debug ("%s (window=%p)", G_STRFUNC, parent_window);
+}
+
+static void
+test_shell_backend_window_created_cb (EShellBackend *shell_backend,
+ GtkWindow *window)
+{
+ const gchar *backend_name;
+
+ g_debug ("%s (%s)", G_STRFUNC, G_OBJECT_TYPE_NAME (window));
+
+ if (!E_IS_SHELL_WINDOW (window))
+ return;
+
+ backend_name = E_SHELL_BACKEND_GET_CLASS (shell_backend)->name;
+
+ e_shell_window_register_new_item_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ item_entries, G_N_ELEMENTS (item_entries));
+
+ e_shell_window_register_new_source_actions (
+ E_SHELL_WINDOW (window), backend_name,
+ source_entries, G_N_ELEMENTS (source_entries));
+}
+
+static void
+test_shell_backend_window_destroyed_cb (EShellBackend *shell_backend)
+{
+ g_debug ("%s", G_STRFUNC);
+}
+
+void
+test_shell_backend_constructed (GObject *object)
+{
+ EShell *shell;
+ EShellBackend *shell_backend;
+
+ shell_backend = E_SHELL_BACKEND (object);
+ shell = e_shell_backend_get_shell (shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "handle-uri",
+ G_CALLBACK (test_shell_backend_handle_uri_cb),
+ shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "send-receive",
+ G_CALLBACK (test_shell_backend_send_receive_cb),
+ shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-created",
+ G_CALLBACK (test_shell_backend_window_created_cb),
+ shell_backend);
+
+ g_signal_connect_swapped (
+ shell, "window-destroyed",
+ G_CALLBACK (test_shell_backend_window_destroyed_cb),
+ shell_backend);
+}
+
+static void
+test_shell_backend_class_init (ETestShellBackendClass *class)
+{
+ GObjectClass *object_class;
+ EShellBackendClass *shell_backend_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETestShellBackendPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructed = test_shell_backend_constructed;
+
+ shell_backend_class = E_SHELL_BACKEND_CLASS (class);
+ shell_backend_class->shell_view_type = E_TYPE_TEST_SHELL_VIEW;
+ shell_backend_class->name = "test";
+ shell_backend_class->aliases = "monkey";
+ shell_backend_class->schemes = "";
+ shell_backend_class->sort_order = 100;
+ shell_backend_class->start = test_shell_backend_start;
+ shell_backend_class->is_busy = test_shell_backend_is_busy;
+ shell_backend_class->shutdown = test_shell_backend_shutdown;
+ shell_backend_class->migrate = test_shell_backend_migrate;
+}
+
+static void
+test_shell_backend_init (ETestShellBackend *test_shell_backend)
+{
+ test_shell_backend->priv =
+ E_TEST_SHELL_BACKEND_GET_PRIVATE (test_shell_backend);
+}
+
+GType
+e_test_shell_backend_get_type (void)
+{
+ return test_shell_backend_type;
+}
+
+void
+e_test_shell_backend_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (ETestShellBackendClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) test_shell_backend_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ETestShellBackend),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) test_shell_backend_init,
+ NULL /* value_table */
+ };
+
+ test_shell_backend_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_BACKEND,
+ "ETestShellBackend", &type_info, 0);
+}
diff --cc shell/test/e-test-shell-backend.h
index 0768e48,0000000..0d342bf
mode 100644,000000..100644
--- a/shell/test/e-test-shell-backend.h
+++ b/shell/test/e-test-shell-backend.h
@@@ -1,67 -1,0 +1,67 @@@
+/*
+ * e-test-shell-backend.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TEST_SHELL_BACKEND_H
+#define E_TEST_SHELL_BACKEND_H
+
+#include <shell/e-shell-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TEST_SHELL_BACKEND \
+ (e_test_shell_backend_get_type ())
+#define E_TEST_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TEST_SHELL_BACKEND, ETestShellBackend))
+#define E_TEST_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TEST_SHELL_BACKEND, ETestShellBackendClass))
+#define E_IS_TEST_SHELL_BACKEND(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TEST_SHELL_BACKEND))
+#define E_IS_TEST_SHELL_BACKEND_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TEST_SHELL_BACKEND))
+#define E_TEST_SHELL_BACKEND_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TEST_SHELL_BACKEND, ETestShellBackendClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETestShellBackend ETestShellBackend;
+typedef struct _ETestShellBackendClass ETestShellBackendClass;
+typedef struct _ETestShellBackendPrivate ETestShellBackendPrivate;
+
+struct _ETestShellBackend {
+ EShellBackend parent;
+ ETestShellBackendPrivate *priv;
+};
+
+struct _ETestShellBackendClass {
+ EShellBackendClass parent_class;
+};
+
+GType e_test_shell_backend_get_type (void);
+void e_test_shell_backend_register_type
+ (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_TEST_SHELL_BACKEND_H */
diff --cc shell/test/e-test-shell-view.c
index f05abff,0000000..b4464cc
mode 100644,000000..100644
--- a/shell/test/e-test-shell-view.c
+++ b/shell/test/e-test-shell-view.c
@@@ -1,155 -1,0 +1,155 @@@
+/*
+ * e-test-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-test-shell-view.h"
+
+#include "shell/e-shell-content.h"
+#include "shell/e-shell-sidebar.h"
+
+#define E_TEST_SHELL_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TEST_SHELL_VIEW, ETestShellViewPrivate))
+
+struct _ETestShellViewPrivate {
+ EActivity *activity;
+};
+
+static gpointer parent_class;
+static GType test_shell_view_type;
+
+static void
+test_shell_view_toggled (EShellView *shell_view)
+{
+#if 0
+ gboolean is_active;
+ const gchar *active;
+
+ is_active = e_shell_view_is_active (shell_view);
+ active = is_active ? "active" : "inactive";
+ g_debug ("%s (now %s)", G_STRFUNC, active);
+#endif
+}
+
+static void
+test_shell_view_dispose (GObject *object)
+{
+ ETestShellViewPrivate *priv;
+
+ priv = E_TEST_SHELL_VIEW_GET_PRIVATE (object);
+
+ if (priv->activity != NULL) {
+ e_activity_complete (priv->activity);
+ g_object_unref (priv->activity);
+ priv->activity = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+test_shell_view_constructed (GObject *object)
+{
+ ETestShellViewPrivate *priv;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ EActivity *activity;
+ GtkWidget *widget;
+
+ /* Chain up to parent's constructed() method. */
+ G_OBJECT_CLASS (parent_class)->constructed (object);
+
+ priv = E_TEST_SHELL_VIEW_GET_PRIVATE (object);
+
+ shell_view = E_SHELL_VIEW (object);
+ 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);
+
+ widget = gtk_label_new ("Content Widget");
+ gtk_container_add (GTK_CONTAINER (shell_content), widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new ("Sidebar Widget");
+ gtk_container_add (GTK_CONTAINER (shell_sidebar), widget);
+ gtk_widget_show (widget);
+
+ activity = e_activity_new ("Test Activity");
+ e_activity_set_allow_cancel (activity, TRUE);
+ e_shell_backend_add_activity (shell_backend, activity);
+ priv->activity = activity;
+}
+
+static void
+test_shell_view_class_init (ETestShellViewClass *class,
+ GTypeModule *type_module)
+{
+ GObjectClass *object_class;
+ EShellViewClass *shell_view_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETestShellViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = test_shell_view_dispose;
+ object_class->constructed = test_shell_view_constructed;
+
+ shell_view_class = E_SHELL_VIEW_CLASS (class);
+ shell_view_class->label = "Test";
+ shell_view_class->icon_name = "face-monkey";
+ shell_view_class->toggled = test_shell_view_toggled;
+}
+
+static void
+test_shell_view_init (ETestShellView *test_shell_view)
+{
+ test_shell_view->priv =
+ E_TEST_SHELL_VIEW_GET_PRIVATE (test_shell_view);
+}
+
+GType
+e_test_shell_view_get_type (void)
+{
+ return test_shell_view_type;
+}
+
+void
+e_test_shell_view_register_type (GTypeModule *type_module)
+{
+ const GTypeInfo type_info = {
+ sizeof (ETestShellViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) test_shell_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ type_module,
+ sizeof (ETestShellView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) test_shell_view_init,
+ NULL /* value_table */
+ };
+
+ test_shell_view_type = g_type_module_register_type (
+ type_module, E_TYPE_SHELL_VIEW,
+ "ETestShellView", &type_info, 0);
+}
diff --cc shell/test/e-test-shell-view.h
index b84fba9,0000000..85c33bf
mode 100644,000000..100644
--- a/shell/test/e-test-shell-view.h
+++ b/shell/test/e-test-shell-view.h
@@@ -1,66 -1,0 +1,66 @@@
+/*
+ * e-test-shell-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TEST_SHELL_VIEW_H
+#define E_TEST_SHELL_VIEW_H
+
+#include <shell/e-shell-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TEST_SHELL_VIEW \
+ (e_test_shell_view_get_type ())
+#define E_TEST_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TEST_SHELL_VIEW, ETestShellView))
+#define E_TEST_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TEST_SHELL_VIEW, ETestShellViewClass))
+#define E_IS_TEST_SHELL_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TEST_SHELL_VIEW))
+#define E_IS_TEST_SHELL_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TEST_SHELL_VIEW))
+#define E_TEST_SHELL_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TEST_SHELL_VIEW, ETestShellViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETestShellView ETestShellView;
+typedef struct _ETestShellViewClass ETestShellViewClass;
+typedef struct _ETestShellViewPrivate ETestShellViewPrivate;
+
+struct _ETestShellView {
+ EShellView parent;
+ ETestShellViewPrivate *priv;
+};
+
+struct _ETestShellViewClass {
+ EShellViewClass parent_class;
+};
+
+GType e_test_shell_view_get_type (void);
+void e_test_shell_view_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_TEST_SHELL_VIEW_H */
diff --cc shell/test/evolution-module-test.c
index ceae63c,0000000..1fe3c7c
mode 100644,000000..100644
--- a/shell/test/evolution-module-test.c
+++ b/shell/test/evolution-module-test.c
@@@ -1,41 -1,0 +1,41 @@@
+/*
+ * evolution-module-test.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-test-shell-backend.h"
+#include "e-test-shell-view.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ /* Register dynamically loaded types. */
+
+ e_test_shell_backend_register_type (type_module);
+ e_test_shell_view_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --cc widgets/misc/a11y/ea-calendar-cell.c
index 8173d6d,0000000..2d2a92d
mode 100644,000000..100644
--- a/widgets/misc/a11y/ea-calendar-cell.c
+++ b/widgets/misc/a11y/ea-calendar-cell.c
@@@ -1,387 -1,0 +1,387 @@@
+/*
+ *
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Bolian Yin <bolian yin sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <gtk/gtk.h>
+#include <e-util/e-util.h>
+#include "ea-calendar-cell.h"
+#include "ea-calendar-item.h"
+#include "a11y/ea-factory.h"
+
+/* ECalendarCell */
+
+static void e_calendar_cell_class_init (ECalendarCellClass *class);
+
+EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_CELL, ea_calendar_cell, ea_calendar_cell_new)
+
+GType
+e_calendar_cell_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (ECalendarCellClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) e_calendar_cell_class_init, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (ECalendarCell), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "ECalendarCell", &tinfo, 0);
+ }
+
+ return type;
+}
+
+static void
+e_calendar_cell_class_init (ECalendarCellClass *class)
+{
+ EA_SET_FACTORY (e_calendar_cell_get_type (), ea_calendar_cell);
+}
+
+ECalendarCell *
+e_calendar_cell_new (ECalendarItem *calitem, gint row, gint column)
+{
+ GObject *object;
+ ECalendarCell *cell;
+
+ g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), NULL);
+
+ object = g_object_new (E_TYPE_CALENDAR_CELL, NULL);
+ cell = E_CALENDAR_CELL (object);
+ cell->calitem = calitem;
+ cell->row = row;
+ cell->column = column;
+
+#ifdef ACC_DEBUG
+ g_print ("EvoAcc: e_calendar_cell created %p\n", (void *)cell);
+#endif
+
+ return cell;
+}
+
+/* EaCalendarCell */
+
+static void ea_calendar_cell_class_init (EaCalendarCellClass *klass);
+static void ea_calendar_cell_init (EaCalendarCell *a11y);
+
+static G_CONST_RETURN gchar* ea_calendar_cell_get_name (AtkObject *accessible);
+static G_CONST_RETURN gchar* ea_calendar_cell_get_description (AtkObject *accessible);
+static AtkObject * ea_calendar_cell_get_parent (AtkObject *accessible);
+static gint ea_calendar_cell_get_index_in_parent (AtkObject *accessible);
+static AtkStateSet *ea_calendar_cell_ref_state_set (AtkObject *accessible);
+
+/* component interface */
+static void atk_component_interface_init (AtkComponentIface *iface);
+static void component_interface_get_extents (AtkComponent *component,
+ gint *x, gint *y,
+ gint *width, gint *height,
+ AtkCoordType coord_type);
+static gboolean component_interface_grab_focus (AtkComponent *component);
+
+static gpointer parent_class = NULL;
+
+#ifdef ACC_DEBUG
+static gint n_ea_calendar_cell_created = 0, n_ea_calendar_cell_destroyed = 0;
+static void ea_calendar_cell_finalize (GObject *object);
+#endif
+
+GType
+ea_calendar_cell_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (EaCalendarCellClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) ea_calendar_cell_class_init, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (EaCalendarCell), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) ea_calendar_cell_init, /* instance init */
+ NULL /* value table */
+ };
+
+ static const GInterfaceInfo atk_component_info = {
+ (GInterfaceInitFunc) atk_component_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ type = g_type_register_static (ATK_TYPE_GOBJECT_ACCESSIBLE,
+ "EaCalendarCell", &tinfo, 0);
+ g_type_add_interface_static (type, ATK_TYPE_COMPONENT,
+ &atk_component_info);
+ }
+
+ return type;
+}
+
+static void
+ea_calendar_cell_class_init (EaCalendarCellClass *klass)
+{
+ AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+#ifdef ACC_DEBUG
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = ea_calendar_cell_finalize;
+#endif
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ class->get_name = ea_calendar_cell_get_name;
+ class->get_description = ea_calendar_cell_get_description;
+
+ class->get_parent = ea_calendar_cell_get_parent;
+ class->get_index_in_parent = ea_calendar_cell_get_index_in_parent;
+ class->ref_state_set = ea_calendar_cell_ref_state_set;
+}
+
+static void
+ea_calendar_cell_init (EaCalendarCell *a11y)
+{
+ a11y->state_set = atk_state_set_new ();
+ atk_state_set_add_state (a11y->state_set, ATK_STATE_TRANSIENT);
+ atk_state_set_add_state (a11y->state_set, ATK_STATE_ENABLED);
+ atk_state_set_add_state (a11y->state_set, ATK_STATE_SENSITIVE);
+ atk_state_set_add_state (a11y->state_set, ATK_STATE_SELECTABLE);
+ atk_state_set_add_state (a11y->state_set, ATK_STATE_SHOWING);
+ atk_state_set_add_state (a11y->state_set, ATK_STATE_FOCUSABLE);
+}
+
+AtkObject*
+ea_calendar_cell_new (GObject *obj)
+{
+ gpointer object;
+ AtkObject *atk_object;
+
+ g_return_val_if_fail (E_IS_CALENDAR_CELL (obj), NULL);
+ object = g_object_new (EA_TYPE_CALENDAR_CELL, NULL);
+ atk_object = ATK_OBJECT (object);
+ atk_object_initialize (atk_object, obj);
+ atk_object->role = ATK_ROLE_TABLE_CELL;
+
+#ifdef ACC_DEBUG
+ ++n_ea_calendar_cell_created;
+ g_print ("ACC_DEBUG: n_ea_calendar_cell_created = %d\n",
+ n_ea_calendar_cell_created);
+#endif
+ return atk_object;
+}
+
+#ifdef ACC_DEBUG
+static void ea_calendar_cell_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+
+ ++n_ea_calendar_cell_destroyed;
+ g_print ("ACC_DEBUG: n_ea_calendar_cell_destroyed = %d\n",
+ n_ea_calendar_cell_destroyed);
+}
+#endif
+
+static G_CONST_RETURN gchar*
+ea_calendar_cell_get_name (AtkObject *accessible)
+{
+ GObject *g_obj;
+
+ g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), NULL);
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
+ if (!g_obj)
+ /* defunct object*/
+ return NULL;
+
+ if (!accessible->name) {
+ AtkObject *atk_obj;
+ EaCalendarItem *ea_calitem;
+ ECalendarCell *cell;
+ gint day_index;
+ gint year, month, day;
+ gchar buffer[128];
+
+ cell = E_CALENDAR_CELL (g_obj);
+ atk_obj = ea_calendar_cell_get_parent (accessible);
+ ea_calitem = EA_CALENDAR_ITEM (atk_obj);
+ day_index = atk_table_get_index_at (ATK_TABLE (ea_calitem),
+ cell->row, cell->column);
+ e_calendar_item_get_date_for_offset (cell->calitem, day_index,
+ &year, &month, &day);
+
+ g_snprintf (buffer, 128, "%d-%d-%d", year, month + 1, day);
+ ATK_OBJECT_CLASS (parent_class)->set_name (accessible, buffer);
+ }
+ return accessible->name;
+}
+
+static G_CONST_RETURN gchar*
+ea_calendar_cell_get_description (AtkObject *accessible)
+{
+ return ea_calendar_cell_get_name (accessible);
+}
+
+static AtkObject *
+ea_calendar_cell_get_parent (AtkObject *accessible)
+{
+ GObject *g_obj;
+ ECalendarCell *cell;
+ ECalendarItem *calitem;
+
+ g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), NULL);
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
+ if (!g_obj)
+ /* defunct object*/
+ return NULL;
+
+ cell = E_CALENDAR_CELL (g_obj);
+ calitem = cell->calitem;
+ return atk_gobject_accessible_for_object (G_OBJECT (calitem));
+}
+
+static gint
+ea_calendar_cell_get_index_in_parent (AtkObject *accessible)
+{
+ GObject *g_obj;
+ ECalendarCell *cell;
+ AtkObject *parent;
+
+ g_return_val_if_fail (EA_IS_CALENDAR_CELL (accessible), -1);
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
+ if (!g_obj)
+ return -1;
+ cell = E_CALENDAR_CELL (g_obj);
+ parent = atk_object_get_parent (accessible);
+ return atk_table_get_index_at (ATK_TABLE (parent),
+ cell->row, cell->column);
+}
+
+static AtkStateSet *
+ea_calendar_cell_ref_state_set (AtkObject *accessible)
+{
+ EaCalendarCell *atk_cell = EA_CALENDAR_CELL (accessible);
+
+ g_return_val_if_fail (atk_cell->state_set, NULL);
+
+ g_object_ref(atk_cell->state_set);
+
+ return atk_cell->state_set;
+
+}
+
+/* Atk Component Interface */
+
+static void
+atk_component_interface_init (AtkComponentIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->get_extents = component_interface_get_extents;
+ iface->grab_focus = component_interface_grab_focus;
+}
+
+static void
+component_interface_get_extents (AtkComponent *component,
+ gint *x, gint *y, gint *width, gint *height,
+ AtkCoordType coord_type)
+{
+ GObject *g_obj;
+ AtkObject *atk_obj, *atk_canvas;
+ ECalendarCell *cell;
+ ECalendarItem *calitem;
+ EaCalendarItem *ea_calitem;
+ gint day_index;
+ gint year, month, day;
+ gint canvas_x, canvas_y, canvas_width, canvas_height;
+
+ *x = *y = *width = *height = 0;
+
+ g_return_if_fail (EA_IS_CALENDAR_CELL (component));
+
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(component));
+ if (!g_obj)
+ /* defunct object*/
+ return;
+
+ cell = E_CALENDAR_CELL (g_obj);
+ calitem = cell->calitem;
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem));
+ ea_calitem = EA_CALENDAR_ITEM (atk_obj);
+ day_index = atk_table_get_index_at (ATK_TABLE (ea_calitem),
+ cell->row, cell->column);
+ e_calendar_item_get_date_for_offset (calitem, day_index,
+ &year, &month, &day);
+
+ if (!e_calendar_item_get_day_extents (calitem,
+ year, month, day,
+ x, y, width, height))
+ return;
+ atk_canvas = atk_object_get_parent (ATK_OBJECT (ea_calitem));
+ atk_component_get_extents (ATK_COMPONENT (atk_canvas),
+ &canvas_x, &canvas_y,
+ &canvas_width, &canvas_height,
+ coord_type);
+ *x += canvas_x;
+ *y += canvas_y;
+}
+
+static gboolean
+component_interface_grab_focus (AtkComponent *component)
+{
+ GObject *g_obj;
+ GtkWidget *toplevel;
+ AtkObject *ea_calitem;
+ ECalendarItem *calitem;
+ EaCalendarCell *a11y;
+ gint index;
+
+ a11y = EA_CALENDAR_CELL (component);
+ ea_calitem = ea_calendar_cell_get_parent (ATK_OBJECT (a11y));
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(ea_calitem));
+ calitem = E_CALENDAR_ITEM (g_obj);
+
+ index = atk_object_get_index_in_parent (ATK_OBJECT (a11y));
+
+ atk_selection_clear_selection (ATK_SELECTION (ea_calitem));
+ atk_selection_add_selection (ATK_SELECTION (ea_calitem), index);
+
+ gtk_widget_grab_focus (GTK_WIDGET (GNOME_CANVAS_ITEM (calitem)->canvas));
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (GNOME_CANVAS_ITEM (calitem)->canvas));
+ if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
+ gtk_window_present (GTK_WINDOW (toplevel));
+
+ return TRUE;
+
+}
diff --cc widgets/misc/a11y/ea-calendar-item.c
index 66f40a9,0000000..34db081
mode 100644,000000..100644
--- a/widgets/misc/a11y/ea-calendar-item.c
+++ b/widgets/misc/a11y/ea-calendar-item.c
@@@ -1,1314 -1,0 +1,1314 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
- * Bolian Yin <bolian yin sun com>
++ * Bolian Yin <bolian yin sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <libgnomecanvas/gnome-canvas.h>
+#include <glib.h>
+#include <e-util/e-util.h>
+#include <glib/gi18n.h>
+#include <libedataserver/e-data-server-util.h>
+#include "ea-calendar-item.h"
+#include "ea-calendar-cell.h"
+#include "a11y/ea-cell-table.h"
+
+#define EA_CALENDAR_COLUMN_NUM E_CALENDAR_COLS_PER_MONTH
+
+/* EaCalendarItem */
+static void ea_calendar_item_class_init (EaCalendarItemClass *klass);
+static void ea_calendar_item_finalize (GObject *object);
+
+static G_CONST_RETURN gchar* ea_calendar_item_get_name (AtkObject *accessible);
+static G_CONST_RETURN gchar* ea_calendar_item_get_description (AtkObject *accessible);
+static gint ea_calendar_item_get_n_children (AtkObject *accessible);
+static AtkObject *ea_calendar_item_ref_child (AtkObject *accessible, gint index);
+static AtkStateSet* ea_calendar_item_ref_state_set (AtkObject *accessible);
+
+/* atk table interface */
+static void atk_table_interface_init (AtkTableIface *iface);
+static gint table_interface_get_index_at (AtkTable *table,
+ gint row,
+ gint column);
+static gint table_interface_get_column_at_index (AtkTable *table,
+ gint index);
+static gint table_interface_get_row_at_index (AtkTable *table,
+ gint index);
+static AtkObject* table_interface_ref_at (AtkTable *table,
+ gint row,
+ gint column);
+static gint table_interface_get_n_rows (AtkTable *table);
+static gint table_interface_get_n_columns (AtkTable *table);
+static gint table_interface_get_column_extent_at (AtkTable *table,
+ gint row,
+ gint column);
+static gint table_interface_get_row_extent_at (AtkTable *table,
+ gint row,
+ gint column);
+
+static gboolean table_interface_is_row_selected (AtkTable *table,
+ gint row);
+static gboolean table_interface_is_column_selected (AtkTable *table,
+ gint row);
+static gboolean table_interface_is_selected (AtkTable *table,
+ gint row,
+ gint column);
+static gint table_interface_get_selected_rows (AtkTable *table,
+ gint **rows_selected);
+static gint table_interface_get_selected_columns (AtkTable *table,
+ gint **columns_selected);
+static gboolean table_interface_add_row_selection (AtkTable *table, gint row);
+static gboolean table_interface_remove_row_selection (AtkTable *table,
+ gint row);
+static gboolean table_interface_add_column_selection (AtkTable *table,
+ gint column);
+static gboolean table_interface_remove_column_selection (AtkTable *table,
+ gint column);
+static AtkObject* table_interface_get_row_header (AtkTable *table, gint row);
+static AtkObject* table_interface_get_column_header (AtkTable *table,
+ gint in_col);
+static AtkObject* table_interface_get_caption (AtkTable *table);
+
+static G_CONST_RETURN gchar*
+table_interface_get_column_description (AtkTable *table, gint in_col);
+
+static G_CONST_RETURN gchar*
+table_interface_get_row_description (AtkTable *table, gint row);
+
+static AtkObject* table_interface_get_summary (AtkTable *table);
+
+/* atk selection interface */
+static void atk_selection_interface_init (AtkSelectionIface *iface);
+static gboolean selection_interface_add_selection (AtkSelection *selection,
+ gint i);
+static gboolean selection_interface_clear_selection (AtkSelection *selection);
+static AtkObject* selection_interface_ref_selection (AtkSelection *selection,
+ gint i);
+static gint selection_interface_get_selection_count (AtkSelection *selection);
+static gboolean selection_interface_is_child_selected (AtkSelection *selection,
+ gint i);
+
+/* callbacks */
+static void selection_preview_change_cb (ECalendarItem *calitem);
+static void date_range_changed_cb (ECalendarItem *calitem);
+
+/* helpers */
+static EaCellTable *ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem);
+static void ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem);
+static gboolean ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem,
+ gint column,
+ gchar *buffer,
+ gint buffer_size);
+static gboolean ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem,
+ gint row,
+ gchar *buffer,
+ gint buffer_size);
+static gboolean e_calendar_item_get_offset_for_date (ECalendarItem *calitem,
+ gint year, gint month, gint day,
+ gint *offset);
+static void ea_calendar_set_focus_object (EaCalendarItem *ea_calitem,
+ AtkObject *item_cell);
+
+#ifdef ACC_DEBUG
+static gint n_ea_calendar_item_created = 0;
+static gint n_ea_calendar_item_destroyed = 0;
+#endif
+
+static gpointer parent_class = NULL;
+
+GType
+ea_calendar_item_get_type (void)
+{
+ static GType type = 0;
+ AtkObjectFactory *factory;
+ GTypeQuery query;
+ GType derived_atk_type;
+
+ if (!type) {
+ static GTypeInfo tinfo = {
+ sizeof (EaCalendarItemClass),
+ (GBaseInitFunc) NULL, /* base init */
+ (GBaseFinalizeFunc) NULL, /* base finalize */
+ (GClassInitFunc) ea_calendar_item_class_init, /* class init */
+ (GClassFinalizeFunc) NULL, /* class finalize */
+ NULL, /* class data */
+ sizeof (EaCalendarItem), /* instance size */
+ 0, /* nb preallocs */
+ (GInstanceInitFunc) NULL, /* instance init */
+ NULL /* value table */
+ };
+
+ static const GInterfaceInfo atk_table_info = {
+ (GInterfaceInitFunc) atk_table_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+ static const GInterfaceInfo atk_selection_info = {
+ (GInterfaceInitFunc) atk_selection_interface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ /*
+ * Figure out the size of the class and instance
+ * we are run-time deriving from (GailCanvasItem, in this case)
+ */
+
+ factory = atk_registry_get_factory (atk_get_default_registry (),
+ GNOME_TYPE_CANVAS_ITEM);
+ derived_atk_type = atk_object_factory_get_accessible_type (factory);
+ g_type_query (derived_atk_type, &query);
+
+ tinfo.class_size = query.class_size;
+ tinfo.instance_size = query.instance_size;
+
+ type = g_type_register_static (derived_atk_type,
+ "EaCalendarItem", &tinfo, 0);
+ g_type_add_interface_static (type, ATK_TYPE_TABLE,
+ &atk_table_info);
+ g_type_add_interface_static (type, ATK_TYPE_SELECTION,
+ &atk_selection_info);
+ }
+
+ return type;
+}
+
+static void
+ea_calendar_item_class_init (EaCalendarItemClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = ea_calendar_item_finalize;
+ parent_class = g_type_class_peek_parent (klass);
+
+ class->get_name = ea_calendar_item_get_name;
+ class->get_description = ea_calendar_item_get_description;
+ class->ref_state_set = ea_calendar_item_ref_state_set;
+
+ class->get_n_children = ea_calendar_item_get_n_children;
+ class->ref_child = ea_calendar_item_ref_child;
+}
+
+AtkObject*
+ea_calendar_item_new (GObject *obj)
+{
+ gpointer object;
+ AtkObject *atk_object;
+ AtkObject *item_cell;
+
+ g_return_val_if_fail (E_IS_CALENDAR_ITEM (obj), NULL);
+ object = g_object_new (EA_TYPE_CALENDAR_ITEM, NULL);
+ atk_object = ATK_OBJECT (object);
+ atk_object_initialize (atk_object, obj);
+ atk_object->role = ATK_ROLE_CALENDAR;
+
+ item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_object),
+ 0);
+ if (item_cell)
+ ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_object), item_cell);
+
+#ifdef ACC_DEBUG
+ ++n_ea_calendar_item_created;
+ g_print ("ACC_DEBUG: n_ea_calendar_item_created = %d\n",
+ n_ea_calendar_item_created);
+#endif
+ /* connect signal handlers */
+ g_signal_connect (obj, "selection_preview_changed",
+ G_CALLBACK (selection_preview_change_cb),
+ atk_object);
+ g_signal_connect (obj, "date_range_changed",
+ G_CALLBACK (date_range_changed_cb),
+ atk_object);
+
+ return atk_object;
+}
+
+static void
+ea_calendar_item_finalize (GObject *object)
+{
+ EaCalendarItem *ea_calitem;
+
+ g_return_if_fail (EA_IS_CALENDAR_ITEM (object));
+
+ ea_calitem = EA_CALENDAR_ITEM (object);
+
+ /* Free the allocated cell data */
+ ea_calendar_item_destory_cell_data (ea_calitem);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+#ifdef ACC_DEBUG
+ ++n_ea_calendar_item_destroyed;
+ printf ("ACC_DEBUG: n_ea_calendar_item_destroyed = %d\n",
+ n_ea_calendar_item_destroyed);
+#endif
+}
+
+static G_CONST_RETURN gchar*
+ea_calendar_item_get_name (AtkObject *accessible)
+{
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ gint start_year, start_month, start_day;
+ gint end_year, end_month, end_day;
+ gchar *name_str = NULL;
+ gchar buffer_start[128] = "";
+ gchar buffer_end[128] = "";
+ struct tm day_start = { 0 };
+ struct tm day_end = { 0 };
+
+ g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL);
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
+ if (!g_obj)
+ return NULL;
+ g_return_val_if_fail (E_IS_CALENDAR_ITEM (g_obj), NULL);
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ if (e_calendar_item_get_date_range (calitem,
+ &start_year, &start_month, &start_day,
+ &end_year, &end_month, &end_day)) {
+
+ day_start.tm_year = start_year - 1900;
+ day_start.tm_mon = start_month;
+ day_start.tm_mday = start_day;
+ day_start.tm_isdst = -1;
+ e_utf8_strftime (buffer_start, sizeof (buffer_start), _("%d %B %Y"), &day_start);
+
+ day_end.tm_year = end_year - 1900;
+ day_end.tm_mon = end_month;
+ day_end.tm_mday = end_day;
+ day_end.tm_isdst = -1;
+ e_utf8_strftime (buffer_end, sizeof (buffer_end), _("%d %B %Y"), &day_end);
+
+ name_str = g_strdup_printf (_("Calendar: from %s to %s"), buffer_start, buffer_end);
+ }
+
+#if 0
+ if (e_calendar_item_get_selection (calitem, &select_start, &select_end)) {
+ GDate select_start, select_end;
+ gint year1, year2, month1, month2, day1, day2;
+
+ year1 = g_date_get_year (&select_start);
+ month1 = g_date_get_month (&select_start);
+ day1 = g_date_get_day (&select_start);
+
+ year2 = g_date_get_year (&select_end);
+ month2 = g_date_get_month (&select_end);
+ day2 = g_date_get_day (&select_end);
+
+ sprintf (new_name + strlen (new_name),
+ " : current selection: from %d-%d-%d to %d-%d-%d.",
+ year1, month1, day1,
+ year2, month2, day2);
+ }
+#endif
+
+ ATK_OBJECT_CLASS (parent_class)->set_name (accessible, name_str);
+ g_free (name_str);
+
+ return accessible->name;
+}
+
+static G_CONST_RETURN gchar*
+ea_calendar_item_get_description (AtkObject *accessible)
+{
+ if (accessible->description)
+ return accessible->description;
+
+ return _("evolution calendar item");
+}
+
+static AtkStateSet*
+ea_calendar_item_ref_state_set (AtkObject *accessible)
+{
+ AtkStateSet *state_set;
+ GObject *g_obj;
+
+ state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE(accessible));
+ if (!g_obj)
+ return state_set;
+
+ atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
+ atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
+
+ return state_set;
+}
+
+static gint
+ea_calendar_item_get_n_children (AtkObject *accessible)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ gint n_children = 0;
+ gint start_year, start_month, start_day;
+ gint end_year, end_month, end_day;
+ GDate *start_date, *end_date;
+
+ g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), -1);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return -1;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ if (!e_calendar_item_get_date_range (calitem, &start_year,
+ &start_month, &start_day,
+ &end_year, &end_month,
+ &end_day))
+ return 0;
+
+ start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
+ end_date = g_date_new_dmy (end_day, end_month + 1, end_year);
+
+ n_children = g_date_days_between (start_date, end_date) + 1;
+ g_free (start_date);
+ g_free (end_date);
+ return n_children;
+}
+
+static AtkObject *
+ea_calendar_item_ref_child (AtkObject *accessible, gint index)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ gint n_children;
+ ECalendarCell *cell;
+ EaCellTable *cell_data;
+ EaCalendarItem *ea_calitem;
+
+ g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return NULL;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+
+ n_children = ea_calendar_item_get_n_children (accessible);
+ if (index < 0 || index >= n_children)
+ return NULL;
+
+ ea_calitem = EA_CALENDAR_ITEM (accessible);
+ cell_data = ea_calendar_item_get_cell_data (ea_calitem);
+ if (!cell_data)
+ return NULL;
+
+ cell = ea_cell_table_get_cell_at_index (cell_data, index);
+ if (!cell) {
+ cell = e_calendar_cell_new (calitem,
+ index / EA_CALENDAR_COLUMN_NUM,
+ index % EA_CALENDAR_COLUMN_NUM);
+ ea_cell_table_set_cell_at_index (cell_data, index, cell);
+ g_object_unref (cell);
+ }
+
+#ifdef ACC_DEBUG
+ g_print ("AccDebug: ea_calendar_item children[%d]=%p\n", index,
+ (gpointer)cell);
+#endif
+ return g_object_ref (atk_gobject_accessible_for_object (G_OBJECT(cell)));
+}
+
+/* atk table interface */
+
+static void
+atk_table_interface_init (AtkTableIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->ref_at = table_interface_ref_at;
+
+ iface->get_n_rows = table_interface_get_n_rows;
+ iface->get_n_columns = table_interface_get_n_columns;
+ iface->get_index_at = table_interface_get_index_at;
+ iface->get_column_at_index = table_interface_get_column_at_index;
+ iface->get_row_at_index = table_interface_get_row_at_index;
+ iface->get_column_extent_at = table_interface_get_column_extent_at;
+ iface->get_row_extent_at = table_interface_get_row_extent_at;
+
+ iface->is_selected = table_interface_is_selected;
+ iface->get_selected_rows = table_interface_get_selected_rows;
+ iface->get_selected_columns = table_interface_get_selected_columns;
+ iface->is_row_selected = table_interface_is_row_selected;
+ iface->is_column_selected = table_interface_is_column_selected;
+ iface->add_row_selection = table_interface_add_row_selection;
+ iface->remove_row_selection = table_interface_remove_row_selection;
+ iface->add_column_selection = table_interface_add_column_selection;
+ iface->remove_column_selection = table_interface_remove_column_selection;
+
+ iface->get_row_header = table_interface_get_row_header;
+ iface->get_column_header = table_interface_get_column_header;
+ iface->get_caption = table_interface_get_caption;
+ iface->get_summary = table_interface_get_summary;
+ iface->get_row_description = table_interface_get_row_description;
+ iface->get_column_description = table_interface_get_column_description;
+}
+
+static AtkObject*
+table_interface_ref_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ gint index;
+
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+ index = EA_CALENDAR_COLUMN_NUM * row + column;
+ return ea_calendar_item_ref_child (ATK_OBJECT (ea_calitem), index);
+}
+
+static gint
+table_interface_get_n_rows (AtkTable *table)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+ gint n_children;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return -1;
+
+ n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
+ return (n_children - 1) / EA_CALENDAR_COLUMN_NUM + 1;
+}
+
+static gint
+table_interface_get_n_columns (AtkTable *table)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return -1;
+
+ return EA_CALENDAR_COLUMN_NUM;
+}
+
+static gint
+table_interface_get_index_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return -1;
+
+ return row * EA_CALENDAR_COLUMN_NUM + column;
+}
+
+static gint
+table_interface_get_column_at_index (AtkTable *table,
+ gint index)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+ gint n_children;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return -1;
+
+ n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
+ if (index >= 0 && index < n_children)
+ return index % EA_CALENDAR_COLUMN_NUM;
+ return -1;
+}
+
+static gint
+table_interface_get_row_at_index (AtkTable *table,
+ gint index)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+ gint n_children;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return -1;
+
+ n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
+ if (index >= 0 && index < n_children)
+ return index / EA_CALENDAR_COLUMN_NUM;
+ return -1;
+}
+
+static gint
+table_interface_get_column_extent_at (AtkTable *table,
+ gint row,
+ gint column)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ return calitem->cell_width;
+}
+
+static gint
+table_interface_get_row_extent_at (AtkTable *table,
+ gint row, gint column)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ return calitem->cell_height;
+}
+
+/* any day in the row is selected, the row is selected */
+static gboolean
+table_interface_is_row_selected (AtkTable *table,
+ gint row)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ gint n_rows;
+ ECalendarItem *calitem;
+ gint row_index_start, row_index_end;
+ gint sel_index_start, sel_index_end;
+
+ GDate start_date, end_date;
+
+ g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (table);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ n_rows = table_interface_get_n_rows (table);
+ if (row < 0 || row >= n_rows)
+ return FALSE;
+
+ row_index_start = row * EA_CALENDAR_COLUMN_NUM;
+ row_index_end = row_index_start + EA_CALENDAR_COLUMN_NUM - 1;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
+ return FALSE;
+
+ e_calendar_item_get_offset_for_date (calitem,
+ g_date_get_year (&start_date),
+ g_date_get_month (&start_date),
+ g_date_get_day (&start_date),
+ &sel_index_start);
+ e_calendar_item_get_offset_for_date (calitem,
+ g_date_get_year (&end_date),
+ g_date_get_month (&end_date),
+ g_date_get_day (&end_date),
+ &sel_index_end);
+
+ if ((sel_index_start < row_index_start &&
+ sel_index_end >= row_index_start) ||
+ (sel_index_start >= row_index_start &&
+ sel_index_start <= row_index_end))
+ return TRUE;
+ return FALSE;
+}
+
+static gboolean
+table_interface_is_selected (AtkTable *table,
+ gint row,
+ gint column)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ gint n_rows, n_columns;
+ ECalendarItem *calitem;
+ gint index;
+ gint sel_index_start, sel_index_end;
+
+ GDate start_date, end_date;
+
+ g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (table);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ n_rows = table_interface_get_n_rows (table);
+ if (row < 0 || row >= n_rows)
+ return FALSE;
+ n_columns = table_interface_get_n_columns (table);
+ if (column < 0 || column >= n_columns)
+ return FALSE;
+
+ index = table_interface_get_index_at (table, row, column);
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
+ return FALSE;
+
+ e_calendar_item_get_offset_for_date (calitem,
+ g_date_get_year (&start_date),
+ g_date_get_month (&start_date),
+ g_date_get_day (&start_date),
+ &sel_index_start);
+ e_calendar_item_get_offset_for_date (calitem,
+ g_date_get_year (&end_date),
+ g_date_get_month (&end_date),
+ g_date_get_day (&end_date), &sel_index_end);
+
+ if (sel_index_start <= index && sel_index_end >= index)
+ return TRUE;
+ return FALSE;
+}
+
+static gboolean
+table_interface_is_column_selected (AtkTable *table,
+ gint column)
+{
+ return FALSE;
+}
+
+static gint
+table_interface_get_selected_rows (AtkTable *table,
+ gint **rows_selected)
+{
+ *rows_selected = NULL;
+ return -1;
+}
+
+static gint
+table_interface_get_selected_columns (AtkTable *table,
+ gint **columns_selected)
+{
+ *columns_selected = NULL;
+ return -1;
+}
+
+static gboolean
+table_interface_add_row_selection (AtkTable *table,
+ gint row)
+{
+ return FALSE;
+}
+
+static gboolean
+table_interface_remove_row_selection (AtkTable *table,
+ gint row)
+{
+ return FALSE;
+}
+
+static gboolean
+table_interface_add_column_selection (AtkTable *table,
+ gint column)
+{
+ return FALSE;
+}
+
+static gboolean
+table_interface_remove_column_selection (AtkTable *table,
+ gint column)
+{
+ /* FIXME: NOT IMPLEMENTED */
+ return FALSE;
+}
+
+static AtkObject*
+table_interface_get_row_header (AtkTable *table,
+ gint row)
+{
+ /* FIXME: NOT IMPLEMENTED */
+ return NULL;
+}
+
+static AtkObject*
+table_interface_get_column_header (AtkTable *table,
+ gint in_col)
+{
+ /* FIXME: NOT IMPLEMENTED */
+ return NULL;
+}
+
+static AtkObject*
+table_interface_get_caption (AtkTable *table)
+{
+ /* FIXME: NOT IMPLEMENTED */
+ return NULL;
+}
+
+static G_CONST_RETURN gchar*
+table_interface_get_column_description (AtkTable *table, gint in_col)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+ const gchar *description = NULL;
+ EaCellTable *cell_data;
+ gint n_columns;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return NULL;
+
+ n_columns = table_interface_get_n_columns (table);
+ if (in_col < 0 || in_col >= n_columns)
+ return NULL;
+ cell_data = ea_calendar_item_get_cell_data (ea_calitem);
+ if (!cell_data)
+ return NULL;
+
+ description = ea_cell_table_get_column_label (cell_data, in_col);
+ if (!description) {
+ gchar buffer[128] = "column description";
+ ea_calendar_item_get_column_label (ea_calitem, in_col,
+ buffer, sizeof (buffer));
+ ea_cell_table_set_column_label (cell_data, in_col, buffer);
+ description = ea_cell_table_get_column_label (cell_data,
+ in_col);
+ }
+ return description;
+}
+
+static G_CONST_RETURN gchar*
+table_interface_get_row_description (AtkTable *table, gint row)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (table);
+ const gchar *description = NULL;
+ EaCellTable *cell_data;
+ gint n_rows;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return NULL;
+
+ n_rows = table_interface_get_n_rows (table);
+ if (row < 0 || row >= n_rows)
+ return NULL;
+ cell_data = ea_calendar_item_get_cell_data (ea_calitem);
+ if (!cell_data)
+ return NULL;
+
+ description = ea_cell_table_get_row_label (cell_data, row);
+ if (!description) {
+ gchar buffer[128] = "row description";
+ ea_calendar_item_get_row_label (ea_calitem, row,
+ buffer, sizeof (buffer));
+ ea_cell_table_set_row_label (cell_data, row, buffer);
+ description = ea_cell_table_get_row_label (cell_data,
+ row);
+ }
+ return description;
+}
+
+static AtkObject*
+table_interface_get_summary (AtkTable *table)
+{
+ /* FIXME: NOT IMPLEMENTED */
+ return NULL;
+}
+
+/* atkselection interface */
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+ g_return_if_fail (iface != NULL);
+
+ iface->add_selection = selection_interface_add_selection;
+ iface->clear_selection = selection_interface_clear_selection;
+ iface->ref_selection = selection_interface_ref_selection;
+ iface->get_selection_count = selection_interface_get_selection_count;
+ iface->is_child_selected = selection_interface_is_child_selected;
+}
+
+static gboolean
+selection_interface_add_selection (AtkSelection *selection, gint index)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
+ gint year, month, day;
+ GDate start_date, end_date;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ if (!e_calendar_item_get_date_for_offset (calitem, index,
+ &year, &month, &day))
+ return FALSE;
+
+ /* FIXME: not support mulit-selection */
+ g_date_set_dmy (&start_date, day, month + 1, year);
+ end_date = start_date;
+ e_calendar_item_set_selection (calitem, &start_date, &end_date);
+ return TRUE;
+}
+
+static gboolean
+selection_interface_clear_selection (AtkSelection *selection)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ e_calendar_item_set_selection (calitem, NULL, NULL);
+
+ return TRUE;
+}
+
+static AtkObject*
+selection_interface_ref_selection (AtkSelection *selection, gint i)
+{
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
+ gint count, sel_offset;
+ GDate start_date, end_date;
+
+ count = selection_interface_get_selection_count (selection);
+ if (i < 0 || i >= count)
+ return NULL;
+
+ g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (ea_calitem));
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
+ return NULL;
+ if (!e_calendar_item_get_offset_for_date (calitem,
+ g_date_get_year (&start_date),
+ g_date_get_month (&start_date) - 1,
+ g_date_get_day (&start_date),
+ &sel_offset))
+ return NULL;
+
+ return ea_calendar_item_ref_child (ATK_OBJECT (selection), sel_offset + i);
+}
+
+static gint
+selection_interface_get_selection_count (AtkSelection *selection)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
+ GDate start_date, end_date;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return 0;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+ if (e_calendar_item_get_selection (calitem, &start_date, &end_date))
+ return g_date_days_between (&start_date, &end_date) + 1;
+ else
+ return 0;
+}
+
+static gboolean
+selection_interface_is_child_selected (AtkSelection *selection, gint index)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCalendarItem* ea_calitem = EA_CALENDAR_ITEM (selection);
+ gint row, column, n_children;
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ n_children = atk_object_get_n_accessible_children (ATK_OBJECT (selection));
+ if (index < 0 || index >= n_children)
+ return FALSE;
+
+ row = index / EA_CALENDAR_COLUMN_NUM;
+ column = index % EA_CALENDAR_COLUMN_NUM;
+
+ return table_interface_is_selected (ATK_TABLE (selection), row, column);
+}
+
+/* callbacks */
+
+static void
+selection_preview_change_cb (ECalendarItem *calitem)
+{
+ AtkObject *atk_obj;
+ AtkObject *item_cell;
+
+ g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem));
+ ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj));
+
+ /* only deal with the first selected child, for now */
+ item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_obj),
+ 0);
+
+ if (item_cell)
+ ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell);
+
+ g_signal_emit_by_name (atk_obj,
+ "active-descendant-changed",
+ item_cell);
+ g_signal_emit_by_name (atk_obj, "selection_changed");
+}
+
+static void
+date_range_changed_cb (ECalendarItem *calitem)
+{
+ AtkObject *atk_obj;
+ AtkObject *item_cell;
+
+ g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem));
+ ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj));
+
+ item_cell = atk_selection_ref_selection (ATK_SELECTION (atk_obj),
+ 0);
+ if (item_cell)
+ ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell);
+
+ g_signal_emit_by_name (atk_obj, "model_changed");
+}
+
+/* helpers */
+
+static EaCellTable *
+ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ EaCellTable *cell_data;
+
+ g_return_val_if_fail (ea_calitem, NULL);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return NULL;
+
+ cell_data = g_object_get_data (G_OBJECT(ea_calitem),
+ "ea-calendar-cell-table");
+
+ if (!cell_data) {
+ gint n_cells = ea_calendar_item_get_n_children (ATK_OBJECT(ea_calitem));
+ cell_data = ea_cell_table_create (n_cells/EA_CALENDAR_COLUMN_NUM,
+ EA_CALENDAR_COLUMN_NUM,
+ FALSE);
+ g_object_set_data (G_OBJECT(ea_calitem),
+ "ea-calendar-cell-table", cell_data);
+ }
+ return cell_data;
+}
+
+static void
+ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem)
+{
+ EaCellTable *cell_data;
+
+ g_return_if_fail (ea_calitem);
+
+ cell_data = g_object_get_data (G_OBJECT(ea_calitem),
+ "ea-calendar-cell-table");
+ if (cell_data) {
+ g_object_set_data (G_OBJECT(ea_calitem),
+ "ea-calendar-cell-table", NULL);
+ ea_cell_table_destroy (cell_data);
+ }
+}
+
+static gboolean
+ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem, gint row,
+ gchar *buffer, gint buffer_size)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ gint index, week_num;
+ gint year, month, day;
+
+ g_return_val_if_fail (ea_calitem, FALSE);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ calitem = E_CALENDAR_ITEM (g_obj);
+
+ index = atk_table_get_index_at (ATK_TABLE (ea_calitem), row, 0);
+ if (!e_calendar_item_get_date_for_offset (calitem, index,
+ &year, &month, &day))
+ return FALSE;
+
+ week_num = e_calendar_item_get_week_number (calitem,
+ day, month, year);
+
+ g_snprintf (buffer, buffer_size, "week number : %d", week_num);
+ return TRUE;
+}
+
+static gboolean
+ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem, gint column,
+ gchar *buffer, gint buffer_size)
+{
+ AtkGObjectAccessible *atk_gobj;
+ GObject *g_obj;
+ ECalendarItem *calitem;
+ const gchar *abbr_name;
+
+ g_return_val_if_fail (ea_calitem, FALSE);
+
+ atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
+ g_obj = atk_gobject_accessible_get_object (atk_gobj);
+ if (!g_obj)
+ return FALSE;
+
+ /* Columns are 0 = Monday ... 6 = Sunday */
+ calitem = E_CALENDAR_ITEM (g_obj);
+ abbr_name = e_get_weekday_name (column + 1, TRUE);
+ g_strlcpy (buffer, abbr_name, buffer_size);
+
+ return TRUE;
+}
+
+/* the coordinate the e-calendar canvas coord */
+gboolean
+e_calendar_item_get_day_extents (ECalendarItem *calitem,
+ gint year, gint month, gint date,
+ gint *x, gint *y,
+ gint *width, gint *height)
+{
+ GnomeCanvasItem *item;
+ GtkWidget *widget;
+ GtkStyle *style;
+ PangoFontDescription *font_desc;
+ PangoContext *pango_context;
+ PangoFontMetrics *font_metrics;
+ gint char_height, xthickness, ythickness, text_y;
+ gint new_year, new_month, num_months, months_offset;
+ gint month_x, month_y, month_cell_x, month_cell_y;
+ gint month_row, month_col;
+ gint day_row, day_col;
+ gint days_from_week_start;
+
+ g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
+
+ item = GNOME_CANVAS_ITEM (calitem);
+ widget = GTK_WIDGET (item->canvas);
+ style = widget->style;
+
+ /* Set up Pango prerequisites */
+ font_desc = calitem->font_desc;
+ if (!font_desc)
+ font_desc = style->font_desc;
+ pango_context = gtk_widget_get_pango_context (widget);
+ font_metrics = pango_context_get_metrics (pango_context, font_desc,
+ pango_context_get_language (pango_context));
+
+ char_height =
+ PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) +
+ PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics));
+
+ xthickness = style->xthickness;
+ ythickness = style->ythickness;
+
+ new_year = year;
+ new_month = month;
+ e_calendar_item_normalize_date (calitem, &new_year, &new_month);
+ num_months = calitem->rows * calitem->cols;
+ months_offset = (new_year - calitem->year) * 12
+ + new_month - calitem->month;
+
+ if (months_offset > num_months || months_offset < 0)
+ return FALSE;
+
+ month_row = months_offset / calitem->cols;
+ month_col = months_offset % calitem->cols;
+
+ month_x = item->x1 + xthickness + calitem->x_offset
+ + month_col * calitem->month_width;
+ month_y = item->y1 + ythickness + month_row * calitem->month_height;
+
+ month_cell_x = month_x + E_CALENDAR_ITEM_XPAD_BEFORE_WEEK_NUMBERS
+ + calitem->month_lpad + E_CALENDAR_ITEM_XPAD_BEFORE_CELLS;
+ text_y = month_y + ythickness * 2
+ + E_CALENDAR_ITEM_YPAD_ABOVE_MONTH_NAME
+ + char_height + E_CALENDAR_ITEM_YPAD_BELOW_MONTH_NAME
+ + E_CALENDAR_ITEM_YPAD_ABOVE_DAY_LETTERS + calitem->month_tpad;
+
+ month_cell_y = text_y + char_height
+ + E_CALENDAR_ITEM_YPAD_BELOW_DAY_LETTERS + 1
+ + E_CALENDAR_ITEM_YPAD_ABOVE_CELLS;
+
+ days_from_week_start =
+ e_calendar_item_get_n_days_from_week_start (calitem, new_year,
+ new_month);
+ day_row = (date + days_from_week_start - 1) / EA_CALENDAR_COLUMN_NUM;
+ day_col = (date + days_from_week_start - 1) % EA_CALENDAR_COLUMN_NUM;
+
+ *x = month_cell_x + day_col * calitem->cell_width;
+ *y = month_cell_y + day_row * calitem->cell_height;
+ *width = calitem->cell_width;
+ *height = calitem->cell_height;
+
+ return TRUE;
+}
+
+/* month is from 0 to 11 */
+gboolean
+e_calendar_item_get_date_for_offset (ECalendarItem *calitem, gint day_offset,
+ gint *year, gint *month, gint *day)
+{
+ gint start_year, start_month, start_day;
+ gint end_year, end_month, end_day;
+ GDate *start_date;
+
+ g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
+
+ if (!e_calendar_item_get_date_range (calitem, &start_year,
+ &start_month, &start_day,
+ &end_year, &end_month,
+ &end_day))
+ return FALSE;
+
+ start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
+
+ g_date_add_days (start_date, day_offset);
+
+ *year = g_date_get_year (start_date);
+ *month = g_date_get_month (start_date) - 1;
+ *day = g_date_get_day (start_date);
+
+ return TRUE;
+}
+
+/* the arg month is from 0 to 11 */
+static gboolean
+e_calendar_item_get_offset_for_date (ECalendarItem *calitem,
+ gint year, gint month, gint day,
+ gint *offset)
+{
+ gint start_year, start_month, start_day;
+ gint end_year, end_month, end_day;
+ GDate *start_date, *end_date;
+
+ *offset = 0;
+ g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
+
+ if (!e_calendar_item_get_date_range (calitem, &start_year,
+ &start_month, &start_day,
+ &end_year, &end_month,
+ &end_day))
+ return FALSE;
+
+ start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
+ end_date = g_date_new_dmy (day, month + 1, year);
+
+ *offset = g_date_days_between (start_date, end_date);
+ g_free (start_date);
+ g_free (end_date);
+
+ return TRUE;
+}
+
+gint
+e_calendar_item_get_n_days_from_week_start (ECalendarItem *calitem,
+ gint year, gint month)
+{
+ struct tm tmp_tm;
+ gint start_weekday, days_from_week_start;
+
+ memset (&tmp_tm, 0, sizeof (tmp_tm));
+ tmp_tm.tm_year = year - 1900;
+ tmp_tm.tm_mon = month;
+ tmp_tm.tm_mday = 1;
+ tmp_tm.tm_isdst = -1;
+ mktime (&tmp_tm);
+ start_weekday = (tmp_tm.tm_wday + 6) % 7; /* 0 to 6 */
+ days_from_week_start = (start_weekday + 7 - calitem->week_start_day)
+ % 7;
+ return days_from_week_start;
+}
+
+static void
+ea_calendar_set_focus_object (EaCalendarItem *ea_calitem, AtkObject *item_cell)
+{
+ AtkStateSet *state_set, *old_state_set;
+ AtkObject *old_cell;
+
+ old_cell = (AtkObject *)g_object_get_data (G_OBJECT(ea_calitem), "gail-focus-object");
+ if (old_cell && EA_IS_CALENDAR_CELL (old_cell)) {
+ old_state_set = atk_object_ref_state_set (old_cell);
+ atk_state_set_remove_state (old_state_set, ATK_STATE_FOCUSED);
+ g_object_unref (old_state_set);
+ }
+ if (old_cell)
+ g_object_unref (old_cell);
+
+ state_set = atk_object_ref_state_set (item_cell);
+ atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
+ g_object_set_data (G_OBJECT(ea_calitem), "gail-focus-object", item_cell);
+ g_object_unref (state_set);
+}
diff --cc widgets/misc/a11y/ea-widgets.c
index 239299d,0000000..9deede2
mode 100644,000000..100644
--- a/widgets/misc/a11y/ea-widgets.c
+++ b/widgets/misc/a11y/ea-widgets.c
@@@ -1,32 -1,0 +1,32 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Bolian Yin <bolian yin sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "a11y/ea-factory.h"
+#include "ea-calendar-item.h"
+#include "ea-widgets.h"
+
+EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_ITEM, ea_calendar_item, ea_calendar_item_new)
+
+void e_calendar_item_a11y_init (void)
+{
+ EA_SET_FACTORY (e_calendar_item_get_type (), ea_calendar_item);
+}
diff --cc widgets/misc/a11y/ea-widgets.h
index d19c908,0000000..495222a
mode 100644,000000..100644
--- a/widgets/misc/a11y/ea-widgets.h
+++ b/widgets/misc/a11y/ea-widgets.h
@@@ -1,32 -1,0 +1,32 @@@
+/*
+ *
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Bolian Yin <bolian yin sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* Evolution Accessibility
+*/
+
+#ifndef _EA_WIDGETS_H__
+#define _EA_WIDGETS_H__
+
+void e_calendar_item_a11y_init (void);
+
+#endif /* _EA_WIDGETS_H__ */
diff --cc widgets/misc/e-account-manager.c
index 04e050b,0000000..24b579d
mode 100644,000000..100644
--- a/widgets/misc/e-account-manager.c
+++ b/widgets/misc/e-account-manager.c
@@@ -1,461 -1,0 +1,461 @@@
+/*
+ * e-account-manager.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-account-manager.h"
+
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include "e-util/e-binding.h"
+#include "e-account-tree-view.h"
+
+#define E_ACCOUNT_MANAGER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManagerPrivate))
+
+struct _EAccountManagerPrivate {
+ EAccountList *account_list;
+
+ GtkWidget *tree_view;
+ GtkWidget *add_button;
+ GtkWidget *edit_button;
+ GtkWidget *delete_button;
+ GtkWidget *default_button;
+};
+
+enum {
+ PROP_0,
+ PROP_ACCOUNT_LIST
+};
+
+enum {
+ ADD_ACCOUNT,
+ EDIT_ACCOUNT,
+ DELETE_ACCOUNT,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+account_manager_default_clicked_cb (EAccountManager *manager)
+{
+ EAccountTreeView *tree_view;
+ EAccountList *account_list;
+ EAccount *account;
+
+ tree_view = e_account_manager_get_tree_view (manager);
+ account_list = e_account_manager_get_account_list (manager);
+ account = e_account_tree_view_get_selected (tree_view);
+ g_return_if_fail (account != NULL);
+
+ e_account_list_set_default (account_list, account);
+
+ /* This signals the tree view to refresh. */
+ e_account_list_change (account_list, account);
+}
+
+static gboolean
+account_manager_key_press_event_cb (EAccountManager *manager,
+ GdkEventKey *event)
+{
+ if (event->keyval == GDK_Delete) {
+ e_account_manager_delete_account (manager);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+account_manager_selection_changed_cb (EAccountManager *manager,
+ GtkTreeSelection *selection)
+{
+ EAccountTreeView *tree_view;
+ EAccountList *account_list;
+ EAccount *default_account;
+ EAccount *account;
+ GtkWidget *add_button;
+ GtkWidget *edit_button;
+ GtkWidget *delete_button;
+ GtkWidget *default_button;
+ const gchar *url = NULL;
+ gboolean has_proxies;
+ gboolean sensitive;
+
+ add_button = manager->priv->add_button;
+ edit_button = manager->priv->edit_button;
+ delete_button = manager->priv->delete_button;
+ default_button = manager->priv->default_button;
+
+ tree_view = e_account_manager_get_tree_view (manager);
+ account = e_account_tree_view_get_selected (tree_view);
+ account_list = e_account_tree_view_get_account_list (tree_view);
+
+ if (account != NULL)
+ url = e_account_get_string (account, E_ACCOUNT_SOURCE_URL);
+ else
+ gtk_widget_grab_focus (add_button);
+
+ has_proxies = (url != NULL) &&
+ e_account_list_account_has_proxies (account_list, account);
+
+ /* XXX EAccountList misuses const */
+ default_account = (EAccount *)
+ e_account_list_get_default (account_list);
+
+ sensitive = (account != NULL) && !has_proxies;
+ gtk_widget_set_sensitive (edit_button, sensitive);
+
+ sensitive = (account != NULL);
+ gtk_widget_set_sensitive (delete_button, sensitive);
+
+ sensitive = (account != NULL && account != default_account);
+ gtk_widget_set_sensitive (default_button, sensitive);
+}
+
+static void
+account_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACCOUNT_LIST:
+ e_account_manager_set_account_list (
+ E_ACCOUNT_MANAGER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+account_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACCOUNT_LIST:
+ g_value_set_object (
+ value,
+ e_account_manager_get_account_list (
+ E_ACCOUNT_MANAGER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+account_manager_dispose (GObject *object)
+{
+ EAccountManagerPrivate *priv;
+
+ priv = E_ACCOUNT_MANAGER_GET_PRIVATE (object);
+
+ if (priv->account_list != NULL) {
+ g_object_unref (priv->account_list);
+ priv->account_list = NULL;
+ }
+
+ if (priv->tree_view != NULL) {
+ g_object_unref (priv->tree_view);
+ priv->tree_view = NULL;
+ }
+
+ if (priv->add_button != NULL) {
+ g_object_unref (priv->add_button);
+ priv->add_button = NULL;
+ }
+
+ if (priv->edit_button != NULL) {
+ g_object_unref (priv->edit_button);
+ priv->edit_button = NULL;
+ }
+
+ if (priv->delete_button != NULL) {
+ g_object_unref (priv->delete_button);
+ priv->delete_button = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+account_manager_class_init (EAccountManagerClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAccountManagerPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = account_manager_set_property;
+ object_class->get_property = account_manager_get_property;
+ object_class->dispose = account_manager_dispose;
+
+ /* XXX If we moved the account editor to /widgets/misc we
+ * could handle adding and editing accounts directly. */
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ACCOUNT_LIST,
+ g_param_spec_object (
+ "account-list",
+ "Account List",
+ NULL,
+ E_TYPE_ACCOUNT_LIST,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ signals[ADD_ACCOUNT] = g_signal_new (
+ "add-account",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EAccountManagerClass, add_account),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[EDIT_ACCOUNT] = g_signal_new (
+ "edit-account",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EAccountManagerClass, edit_account),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[DELETE_ACCOUNT] = g_signal_new (
+ "delete-account",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EAccountManagerClass, delete_account),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+account_manager_init (EAccountManager *manager)
+{
+ GtkTreeSelection *selection;
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ manager->priv = E_ACCOUNT_MANAGER_GET_PRIVATE (manager);
+
+ gtk_table_resize (GTK_TABLE (manager), 1, 2);
+ gtk_table_set_col_spacings (GTK_TABLE (manager), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (manager), 12);
+
+ container = GTK_WIDGET (manager);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_table_attach (
+ GTK_TABLE (container), widget, 0, 1, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_account_tree_view_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ manager->priv->tree_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ e_mutual_binding_new (
+ G_OBJECT (manager), "account-list",
+ G_OBJECT (widget), "account-list");
+
+ g_signal_connect_swapped (
+ widget, "key-press-event",
+ G_CALLBACK (account_manager_key_press_event_cb),
+ manager);
+
+ g_signal_connect_swapped (
+ widget, "row-activated",
+ G_CALLBACK (e_account_manager_edit_account),
+ manager);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (account_manager_selection_changed_cb),
+ manager);
+
+ container = GTK_WIDGET (manager);
+
+ widget = gtk_vbutton_box_new ();
+ gtk_button_box_set_layout (
+ GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
+ gtk_box_set_spacing (GTK_BOX (widget), 6);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 0, 2, 0, GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_ADD);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->add_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_account_manager_add_account), manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_EDIT);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->edit_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_account_manager_edit_account), manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_DELETE);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->delete_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_account_manager_delete_account), manager);
+
+ widget = gtk_button_new_with_mnemonic (_("De_fault"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget), gtk_image_new_from_icon_name (
+ "emblem-default", GTK_ICON_SIZE_BUTTON));
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->default_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (account_manager_default_clicked_cb), manager);
+}
+
+GType
+e_account_manager_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAccountManagerClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) account_manager_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_init */
+ sizeof (EAccountManager),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) account_manager_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_TABLE, "EAccountManager", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_account_manager_new (EAccountList *account_list)
+{
+ g_return_val_if_fail (E_IS_ACCOUNT_LIST (account_list), NULL);
+
+ return g_object_new (
+ E_TYPE_ACCOUNT_MANAGER,
+ "account-list", account_list, NULL);
+}
+
+void
+e_account_manager_add_account (EAccountManager *manager)
+{
+ g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager));
+
+ g_signal_emit (manager, signals[ADD_ACCOUNT], 0);
+}
+
+void
+e_account_manager_edit_account (EAccountManager *manager)
+{
+ g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager));
+
+ g_signal_emit (manager, signals[EDIT_ACCOUNT], 0);
+}
+
+void
+e_account_manager_delete_account (EAccountManager *manager)
+{
+ g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager));
+
+ g_signal_emit (manager, signals[DELETE_ACCOUNT], 0);
+}
+
+EAccountList *
+e_account_manager_get_account_list (EAccountManager *manager)
+{
+ g_return_val_if_fail (E_IS_ACCOUNT_MANAGER (manager), NULL);
+
+ return manager->priv->account_list;
+}
+
+void
+e_account_manager_set_account_list (EAccountManager *manager,
+ EAccountList *account_list)
+{
+ g_return_if_fail (E_IS_ACCOUNT_MANAGER (manager));
+
+ if (account_list != NULL) {
+ g_return_if_fail (E_IS_ACCOUNT_LIST (account_list));
+ g_object_ref (account_list);
+ }
+
+ if (manager->priv->account_list != NULL)
+ g_object_unref (manager->priv->account_list);
+
+ manager->priv->account_list = account_list;
+
+ g_object_notify (G_OBJECT (manager), "account-list");
+}
+
+EAccountTreeView *
+e_account_manager_get_tree_view (EAccountManager *manager)
+{
+ g_return_val_if_fail (E_IS_ACCOUNT_MANAGER (manager), NULL);
+
+ return E_ACCOUNT_TREE_VIEW (manager->priv->tree_view);
+}
diff --cc widgets/misc/e-account-manager.h
index c714576,0000000..dab8b28
mode 100644,000000..100644
--- a/widgets/misc/e-account-manager.h
+++ b/widgets/misc/e-account-manager.h
@@@ -1,82 -1,0 +1,82 @@@
+/*
+ * e-account-manager.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ACCOUNT_MANAGER_H
+#define E_ACCOUNT_MANAGER_H
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-account-list.h>
+#include <misc/e-account-tree-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ACCOUNT_MANAGER \
+ (e_account_manager_get_type ())
+#define E_ACCOUNT_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManager))
+#define E_ACCOUNT_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ACCOUNT_MANAGER, EAccountManagerClass))
+#define E_IS_ACCOUNT_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ACCOUNT_MANAGER))
+#define E_IS_ACCOUNT_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ACCOUNT_MANAGER))
+#define E_ACCOUNT_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ACCOUNT_MANAGER, EAccountManagerClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAccountManager EAccountManager;
+typedef struct _EAccountManagerClass EAccountManagerClass;
+typedef struct _EAccountManagerPrivate EAccountManagerPrivate;
+
+struct _EAccountManager {
+ GtkTable parent;
+ EAccountManagerPrivate *priv;
+};
+
+struct _EAccountManagerClass {
+ GtkTableClass parent_class;
+
+ void (*add_account) (EAccountManager *manager);
+ void (*edit_account) (EAccountManager *manager);
+ void (*delete_account) (EAccountManager *manager);
+};
+
+GType e_account_manager_get_type (void);
+GtkWidget * e_account_manager_new (EAccountList *account_list);
+void e_account_manager_add_account (EAccountManager *manager);
+void e_account_manager_edit_account (EAccountManager *manager);
+void e_account_manager_delete_account(EAccountManager *manager);
+EAccountList * e_account_manager_get_account_list
+ (EAccountManager *manager);
+void e_account_manager_set_account_list
+ (EAccountManager *manager,
+ EAccountList *account_list);
+EAccountTreeView *
+ e_account_manager_get_tree_view (EAccountManager *manager);
+
+G_END_DECLS
+
+#endif /* E_ACCOUNT_MANAGER_H */
diff --cc widgets/misc/e-account-tree-view.c
index 78f92d5,0000000..8e57dfc
mode 100644,000000..100644
--- a/widgets/misc/e-account-tree-view.c
+++ b/widgets/misc/e-account-tree-view.c
@@@ -1,632 -1,0 +1,632 @@@
+/*
+ * e-account-tree-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-account-tree-view.h"
+
+#include <glib/gi18n.h>
+#include <camel/camel-url.h>
+
+#define E_ACCOUNT_TREE_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewPrivate))
+
+enum {
+ COLUMN_ACCOUNT,
+ COLUMN_DEFAULT,
+ COLUMN_ENABLED,
+ COLUMN_NAME,
+ COLUMN_PROTOCOL
+};
+
+enum {
+ PROP_0,
+ PROP_ACCOUNT_LIST,
+ PROP_SELECTED
+};
+
+enum {
+ ENABLE_ACCOUNT,
+ DISABLE_ACCOUNT,
+ REFRESHED,
+ LAST_SIGNAL
+};
+
+struct _EAccountTreeViewPrivate {
+ EAccountList *account_list;
+ GHashTable *index;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+account_tree_view_refresh_cb (EAccountList *account_list,
+ EAccount *account,
+ EAccountTreeView *tree_view)
+{
+ GtkListStore *store;
+ GtkTreeModel *model;
+ GtkTreeIter tree_iter;
+ EIterator *account_iter;
+ EAccount *default_account;
+ GHashTable *index;
+ GList *list = NULL;
+ GList *iter;
+
+ store = gtk_list_store_new (
+ 5, E_TYPE_ACCOUNT, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+ G_TYPE_STRING, G_TYPE_STRING);
+ model = GTK_TREE_MODEL (store);
+ index = tree_view->priv->index;
+
+ g_hash_table_remove_all (index);
+
+ if (account_list == NULL)
+ goto skip;
+
+ /* XXX EAccountList misuses const. */
+ default_account = (EAccount *)
+ e_account_list_get_default (account_list);
+
+ /* Build a list of EAccounts to display. */
+ account_iter = e_list_get_iterator (E_LIST (account_list));
+ while (e_iterator_is_valid (account_iter)) {
+
+ /* XXX EIterator misuses const. */
+ account = (EAccount *) e_iterator_get (account_iter);
+ list = g_list_prepend (list, account);
+ e_iterator_next (account_iter);
+ }
+ g_object_unref (account_iter);
+
+ list = g_list_reverse (list);
+
+ /* Populate the list store and index. */
+ for (iter = list; iter != NULL; iter = iter->next) {
+ GtkTreeRowReference *reference;
+ GtkTreePath *path;
+ CamelURL *url = NULL;
+ gboolean is_default;
+ const gchar *protocol;
+
+ account = iter->data;
+
+ /* Skip proxy accounts. */
+ if (account->parent_uid != NULL)
+ continue;
+
+ is_default = (account == default_account);
+
+ if (account->source != NULL && account->source->url != NULL)
+ url = camel_url_new (account->source->url, NULL);
+
+ if (url != NULL && url->protocol != NULL)
+ protocol = url->protocol;
+ else
+ protocol = _("None");
+
+ gtk_list_store_append (store, &tree_iter);
+ gtk_list_store_set (
+ store, &tree_iter,
+ COLUMN_ACCOUNT, account,
+ COLUMN_DEFAULT, is_default,
+ COLUMN_ENABLED, account->enabled,
+ COLUMN_NAME, account->name,
+ COLUMN_PROTOCOL, protocol, -1);
+
+ path = gtk_tree_model_get_path (model, &tree_iter);
+ reference = gtk_tree_row_reference_new (model, path);
+ g_hash_table_insert (index, account, reference);
+ gtk_tree_path_free (path);
+
+ if (url != NULL)
+ camel_url_free (url);
+ }
+
+skip:
+ /* Restore the previously selected account. */
+ account = e_account_tree_view_get_selected (tree_view);
+ if (account != NULL)
+ g_object_ref (account);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
+ e_account_tree_view_set_selected (tree_view, account);
+ if (account != NULL)
+ g_object_unref (account);
+
+ g_signal_emit (tree_view, signals[REFRESHED], 0);
+}
+
+static void
+account_tree_view_enabled_toggled_cb (EAccountTreeView *tree_view,
+ gchar *path_string,
+ GtkCellRendererToggle *renderer)
+{
+ GtkTreeSelection *selection;
+ GtkTreePath *path;
+
+ /* Change the selection first so we enable or disable the
+ * correct account. */
+ path = gtk_tree_path_new_from_string (path_string);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+
+ if (gtk_cell_renderer_toggle_get_active (renderer))
+ e_account_tree_view_disable_account (tree_view);
+ else
+ e_account_tree_view_enable_account (tree_view);
+}
+
+static void
+account_tree_view_selection_changed_cb (EAccountTreeView *tree_view)
+{
+ g_object_notify (G_OBJECT (tree_view), "selected");
+}
+
+static GObject *
+account_tree_view_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ GtkTreeView *tree_view;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ /* Chain up to parent's constructor() method. */
+ object = G_OBJECT_CLASS (parent_class)->constructor (
+ type, n_construct_properties, construct_properties);
+
+ tree_view = GTK_TREE_VIEW (object);
+ gtk_tree_view_set_headers_visible (tree_view, TRUE);
+
+ /* Column: Enabled */
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_expand (column, FALSE);
+ gtk_tree_view_column_set_title (column, _("Enabled"));
+
+ renderer = gtk_cell_renderer_toggle_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+ g_signal_connect_swapped (
+ renderer, "toggled",
+ G_CALLBACK (account_tree_view_enabled_toggled_cb),
+ tree_view);
+
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "active", COLUMN_ENABLED);
+
+ gtk_tree_view_append_column (tree_view, column);
+
+ /* Column: Account Name */
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_expand (column, TRUE);
+ gtk_tree_view_column_set_title (column, _("Account Name"));
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "text", COLUMN_NAME);
+
+ renderer = gtk_cell_renderer_text_new ();
+ g_object_set (renderer, "text", _("Default"), NULL);
+ gtk_tree_view_column_pack_end (column, renderer, FALSE);
+
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "visible", COLUMN_DEFAULT);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ g_object_set (
+ renderer, "icon-name", "emblem-default",
+ "stock-size", GTK_ICON_SIZE_MENU, NULL);
+ gtk_tree_view_column_pack_end (column, renderer, FALSE);
+
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "visible", COLUMN_DEFAULT);
+
+ gtk_tree_view_append_column (tree_view, column);
+
+ /* Column: Protocol */
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_expand (column, FALSE);
+ gtk_tree_view_column_set_title (column, _("Protocol"));
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "text", COLUMN_PROTOCOL);
+
+ gtk_tree_view_append_column (tree_view, column);
+
+ return object;
+}
+
+static void
+account_tree_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACCOUNT_LIST:
+ e_account_tree_view_set_account_list (
+ E_ACCOUNT_TREE_VIEW (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SELECTED:
+ e_account_tree_view_set_selected (
+ E_ACCOUNT_TREE_VIEW (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+account_tree_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACCOUNT_LIST:
+ g_value_set_object (
+ value,
+ e_account_tree_view_get_account_list (
+ E_ACCOUNT_TREE_VIEW (object)));
+ return;
+
+ case PROP_SELECTED:
+ g_value_set_object (
+ value,
+ e_account_tree_view_get_selected (
+ E_ACCOUNT_TREE_VIEW (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+account_tree_view_dispose (GObject *object)
+{
+ EAccountTreeViewPrivate *priv;
+
+ priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (object);
+
+ if (priv->account_list != NULL) {
+ g_signal_handlers_disconnect_by_func (
+ priv->account_list,
+ account_tree_view_refresh_cb, object);
+ g_object_unref (priv->account_list);
+ priv->account_list = NULL;
+ }
+
+ g_hash_table_remove_all (priv->index);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+account_tree_view_finalize (GObject *object)
+{
+ EAccountTreeViewPrivate *priv;
+
+ priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->index);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+account_tree_view_enable_account (EAccountTreeView *tree_view)
+{
+ EAccountList *account_list;
+ EAccount *account;
+
+ account = e_account_tree_view_get_selected (tree_view);
+ if (account == NULL || account->enabled)
+ return;
+
+ account_list = e_account_tree_view_get_account_list (tree_view);
+ g_return_if_fail (account_list != NULL);
+
+ account->enabled = TRUE;
+ e_account_list_change (account_list, account);
+
+ e_account_list_save (account_list);
+}
+
+static void
+account_tree_view_disable_account (EAccountTreeView *tree_view)
+{
+ EAccountList *account_list;
+ EAccount *account;
+
+ account = e_account_tree_view_get_selected (tree_view);
+ if (account == NULL || !account->enabled)
+ return;
+
+ account_list = e_account_tree_view_get_account_list (tree_view);
+ g_return_if_fail (account_list != NULL);
+
+ account->enabled = FALSE;
+ e_account_list_change (account_list, account);
+
+ e_account_list_save (account_list);
+}
+
+static void
+account_tree_view_class_init (EAccountTreeViewClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAccountTreeViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = account_tree_view_constructor;
+ object_class->set_property = account_tree_view_set_property;
+ object_class->get_property = account_tree_view_get_property;
+ object_class->dispose = account_tree_view_dispose;
+ object_class->finalize = account_tree_view_finalize;
+
+ class->enable_account = account_tree_view_enable_account;
+ class->disable_account = account_tree_view_disable_account;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTED,
+ g_param_spec_object (
+ "selected",
+ "Selected Account",
+ NULL,
+ E_TYPE_ACCOUNT,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ACCOUNT_LIST,
+ g_param_spec_object (
+ "account-list",
+ "Account List",
+ NULL,
+ E_TYPE_ACCOUNT_LIST,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ signals[ENABLE_ACCOUNT] = g_signal_new (
+ "enable-account",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAccountTreeViewClass, enable_account),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[DISABLE_ACCOUNT] = g_signal_new (
+ "disable-account",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAccountTreeViewClass, disable_account),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[REFRESHED] = g_signal_new (
+ "refreshed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EAccountTreeViewClass, refreshed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+account_tree_view_init (EAccountTreeView *tree_view)
+{
+ GHashTable *index;
+ GtkTreeSelection *selection;
+
+ /* Reverse-lookup index */
+ index = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) gtk_tree_row_reference_free);
+
+ tree_view->priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (tree_view);
+ tree_view->priv->index = index;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (account_tree_view_selection_changed_cb),
+ tree_view);
+}
+
+GType
+e_account_tree_view_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAccountTreeViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) account_tree_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAccountTreeView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) account_tree_view_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_TREE_VIEW, "EAccountTreeView",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_account_tree_view_new (void)
+{
+ return g_object_new (E_TYPE_ACCOUNT_TREE_VIEW, NULL);
+}
+
+void
+e_account_tree_view_enable_account (EAccountTreeView *tree_view)
+{
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ g_signal_emit (tree_view, signals[ENABLE_ACCOUNT], 0);
+}
+
+void
+e_account_tree_view_disable_account (EAccountTreeView *tree_view)
+{
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ g_signal_emit (tree_view, signals[DISABLE_ACCOUNT], 0);
+}
+
+EAccountList *
+e_account_tree_view_get_account_list (EAccountTreeView *tree_view)
+{
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), NULL);
+
+ return tree_view->priv->account_list;
+}
+
+void
+e_account_tree_view_set_account_list (EAccountTreeView *tree_view,
+ EAccountList *account_list)
+{
+ EAccountTreeViewPrivate *priv;
+
+ g_return_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view));
+
+ if (account_list != NULL)
+ g_return_if_fail (E_IS_ACCOUNT_LIST (account_list));
+
+ priv = E_ACCOUNT_TREE_VIEW_GET_PRIVATE (tree_view);
+
+ if (priv->account_list != NULL) {
+ g_signal_handlers_disconnect_by_func (
+ priv->account_list,
+ account_tree_view_refresh_cb, tree_view);
+ g_object_unref (priv->account_list);
+ priv->account_list = NULL;
+ }
+
+ if (account_list != NULL) {
+ priv->account_list = g_object_ref (account_list);
+
+ /* Listen for changes to the account list. */
+ g_signal_connect (
+ priv->account_list, "account-added",
+ G_CALLBACK (account_tree_view_refresh_cb),
+ tree_view);
+ g_signal_connect (
+ priv->account_list, "account-changed",
+ G_CALLBACK (account_tree_view_refresh_cb),
+ tree_view);
+ g_signal_connect (
+ priv->account_list, "account-removed",
+ G_CALLBACK (account_tree_view_refresh_cb),
+ tree_view);
+ }
+
+ account_tree_view_refresh_cb (account_list, NULL, tree_view);
+
+ g_object_notify (G_OBJECT (tree_view), "account-list");
+}
+
+EAccount *
+e_account_tree_view_get_selected (EAccountTreeView *tree_view)
+{
+ EAccount *account;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return NULL;
+
+ gtk_tree_model_get (model, &iter, COLUMN_ACCOUNT, &account, -1);
+
+ return account;
+}
+
+gboolean
+e_account_tree_view_set_selected (EAccountTreeView *tree_view,
+ EAccount *account)
+{
+ GtkTreeRowReference *reference;
+ GtkTreeSelection *selection;
+ GtkTreePath *path;
+
+ g_return_val_if_fail (E_IS_ACCOUNT_TREE_VIEW (tree_view), FALSE);
+
+ if (account != NULL)
+ g_return_val_if_fail (E_IS_ACCOUNT (account), FALSE);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ /* NULL means clear the selection. */
+ if (account == NULL) {
+ gtk_tree_selection_unselect_all (selection);
+ return TRUE;
+ }
+
+ /* Lookup the tree row reference for the account. */
+ reference = g_hash_table_lookup (tree_view->priv->index, account);
+ if (reference == NULL)
+ return FALSE;
+
+ /* Select the referenced path. */
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+
+ g_object_notify (G_OBJECT (tree_view), "selected");
+
+ return TRUE;
+}
diff --cc widgets/misc/e-account-tree-view.h
index 9d86a8f,0000000..ea13dc3
mode 100644,000000..100644
--- a/widgets/misc/e-account-tree-view.h
+++ b/widgets/misc/e-account-tree-view.h
@@@ -1,84 -1,0 +1,84 @@@
+/*
+ * e-account-tree-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ACCOUNT_TREE_VIEW_H
+#define E_ACCOUNT_TREE_VIEW_H
+
+#include <gtk/gtk.h>
+#include <libedataserver/e-account.h>
+#include <libedataserver/e-account-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ACCOUNT_TREE_VIEW \
+ (e_account_tree_view_get_type ())
+#define E_ACCOUNT_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeView))
+#define E_ACCOUNT_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewClass))
+#define E_IS_ACCOUNT_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ACCOUNT_TREE_VIEW))
+#define E_IS_ACCOUNT_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ACCOUNT_TREE_VIEW))
+#define E_ACCOUNT_TREE_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ACCOUNT_TREE_VIEW, EAccountTreeViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAccountTreeView EAccountTreeView;
+typedef struct _EAccountTreeViewClass EAccountTreeViewClass;
+typedef struct _EAccountTreeViewPrivate EAccountTreeViewPrivate;
+
+struct _EAccountTreeView {
+ GtkTreeView parent;
+ EAccountTreeViewPrivate *priv;
+};
+
+struct _EAccountTreeViewClass {
+ GtkTreeViewClass parent_class;
+
+ void (*enable_account) (EAccountTreeView *tree_view);
+ void (*disable_account) (EAccountTreeView *tree_view);
+ void (*refreshed) (EAccountTreeView *tree_view);
+};
+
+GType e_account_tree_view_get_type (void);
+GtkWidget * e_account_tree_view_new (void);
+void e_account_tree_view_enable_account
+ (EAccountTreeView *tree_view);
+void e_account_tree_view_disable_account
+ (EAccountTreeView *tree_view);
+EAccountList * e_account_tree_view_get_account_list
+ (EAccountTreeView *tree_view);
+void e_account_tree_view_set_account_list
+ (EAccountTreeView *tree_view,
+ EAccountList *account_list);
+EAccount * e_account_tree_view_get_selected(EAccountTreeView *tree_view);
+gboolean e_account_tree_view_set_selected(EAccountTreeView *tree_view,
+ EAccount *account);
+
+G_END_DECLS
+
+#endif /* E_ACCOUNT_TREE_VIEW_H */
diff --cc widgets/misc/e-activity-proxy.c
index bddcc12,0000000..b045394
mode 100644,000000..100644
--- a/widgets/misc/e-activity-proxy.c
+++ b/widgets/misc/e-activity-proxy.c
@@@ -1,345 -1,0 +1,345 @@@
+/*
+ * e-activity-proxy.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-activity-proxy.h"
+
+#include <glib/gi18n.h>
+#include <e-spinner.h>
+
+#define E_ACTIVITY_PROXY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyPrivate))
+
+struct _EActivityProxyPrivate {
+ EActivity *activity;
+ GtkWidget *button;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *cancel;
+ GtkWidget *spinner;
+};
+
+enum {
+ PROP_0,
+ PROP_ACTIVITY
+};
+
+static gpointer parent_class;
+
+static void
+activity_proxy_update (EActivityProxy *proxy)
+{
+ EActivity *activity = proxy->priv->activity;
+ const gchar *icon_name;
+ gboolean allow_cancel;
+ gboolean cancelled;
+ gboolean clickable;
+ gboolean completed;
+ gboolean sensitive;
+ gchar *description;
+
+ allow_cancel = e_activity_get_allow_cancel (activity);
+ cancelled = e_activity_is_cancelled (activity);
+ clickable = e_activity_get_clickable (activity);
+ completed = e_activity_is_completed (activity);
+ icon_name = e_activity_get_icon_name (activity);
+
+ description = e_activity_describe (activity);
+ gtk_widget_set_tooltip_text (GTK_WIDGET (proxy), description);
+ gtk_label_set_text (GTK_LABEL (proxy->priv->label), description);
+ g_free (description);
+
+ /* Note, an activity requires an icon name in order to
+ * be clickable. We don't support spinner buttons. */
+ if (icon_name != NULL) {
+ gtk_image_set_from_icon_name (
+ GTK_IMAGE (proxy->priv->image),
+ icon_name, GTK_ICON_SIZE_MENU);
+ gtk_button_set_image (
+ GTK_BUTTON (proxy->priv->button),
+ gtk_image_new_from_icon_name (
+ icon_name, GTK_ICON_SIZE_MENU));
+ gtk_widget_hide (proxy->priv->spinner);
+ if (clickable) {
+ gtk_widget_show (proxy->priv->button);
+ gtk_widget_hide (proxy->priv->image);
+ } else {
+ gtk_widget_hide (proxy->priv->button);
+ gtk_widget_show (proxy->priv->image);
+ }
+ } else {
+ gtk_widget_show (proxy->priv->spinner);
+ gtk_widget_hide (proxy->priv->button);
+ gtk_widget_hide (proxy->priv->image);
+ }
+
+ if (allow_cancel)
+ gtk_widget_show (proxy->priv->cancel);
+ else
+ gtk_widget_hide (proxy->priv->cancel);
+
+ sensitive = !(cancelled || completed);
+ gtk_widget_set_sensitive (proxy->priv->cancel, sensitive);
+}
+
+static void
+activity_proxy_set_activity (EActivityProxy *proxy,
+ EActivity *activity)
+{
+ g_return_if_fail (proxy->priv->activity == NULL);
+
+ proxy->priv->activity = g_object_ref (activity);
+}
+
+static void
+activity_proxy_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACTIVITY:
+ activity_proxy_set_activity (
+ E_ACTIVITY_PROXY (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+activity_proxy_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACTIVITY:
+ g_value_set_object (
+ value, e_activity_proxy_get_activity (
+ E_ACTIVITY_PROXY (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+activity_proxy_dispose (GObject *object)
+{
+ EActivityProxyPrivate *priv;
+
+ priv = E_ACTIVITY_PROXY_GET_PRIVATE (object);
+
+ if (priv->activity != NULL) {
+ g_signal_handlers_disconnect_matched (
+ priv->activity, G_SIGNAL_MATCH_FUNC, 0, 0,
+ NULL, activity_proxy_update, NULL);
+ g_object_unref (priv->activity);
+ priv->activity = NULL;
+ }
+
+ if (priv->button != NULL) {
+ g_object_unref (priv->button);
+ priv->button = NULL;
+ }
+
+ if (priv->image != NULL) {
+ g_object_unref (priv->image);
+ priv->image = NULL;
+ }
+
+ if (priv->label != NULL) {
+ g_object_unref (priv->label);
+ priv->label = NULL;
+ }
+
+ if (priv->cancel != NULL) {
+ g_object_unref (priv->cancel);
+ priv->cancel = NULL;
+ }
+
+ if (priv->spinner != NULL) {
+ g_object_unref (priv->spinner);
+ priv->spinner = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+activity_proxy_constructed (GObject *object)
+{
+ EActivityProxy *proxy;
+
+ proxy = E_ACTIVITY_PROXY (object);
+
+ g_signal_connect_swapped (
+ proxy->priv->button, "clicked",
+ G_CALLBACK (e_activity_clicked), proxy->priv->activity);
+
+ g_signal_connect_swapped (
+ proxy->priv->cancel, "clicked",
+ G_CALLBACK (e_activity_cancel), proxy->priv->activity);
+
+ g_signal_connect_swapped (
+ proxy->priv->activity, "cancelled",
+ G_CALLBACK (activity_proxy_update), proxy);
+
+ g_signal_connect_swapped (
+ proxy->priv->activity, "completed",
+ G_CALLBACK (activity_proxy_update), proxy);
+
+ g_signal_connect_swapped (
+ proxy->priv->activity, "notify",
+ G_CALLBACK (activity_proxy_update), proxy);
+
+ activity_proxy_update (proxy);
+}
+
+static void
+activity_proxy_class_init (EActivityProxyClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EActivityProxyPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = activity_proxy_set_property;
+ object_class->get_property = activity_proxy_get_property;
+ object_class->dispose = activity_proxy_dispose;
+ object_class->constructed = activity_proxy_constructed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ACTIVITY,
+ g_param_spec_object (
+ "activity",
+ NULL,
+ NULL,
+ E_TYPE_ACTIVITY,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+activity_proxy_init (EActivityProxy *proxy)
+{
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ proxy->priv = E_ACTIVITY_PROXY_GET_PRIVATE (proxy);
+
+ container = GTK_WIDGET (proxy);
+
+ widget = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_hbox_new (FALSE, 3);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_image_new ();
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ proxy->priv->image = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ widget = gtk_button_new ();
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ proxy->priv->button = g_object_ref (widget);
+ gtk_widget_hide (widget);
+
+ /* XXX What's the rationale for killing the old spinner API? */
+ widget = e_spinner_new_spinning_small_shown ();
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ proxy->priv->spinner = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new (NULL);
+ gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ proxy->priv->label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_button_new ();
+ gtk_button_set_image (
+ GTK_BUTTON (widget), gtk_image_new_from_stock (
+ GTK_STOCK_STOP, GTK_ICON_SIZE_MENU));
+ gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_set_tooltip_text (widget, _("Cancel"));
+ proxy->priv->cancel = g_object_ref (widget);
+ gtk_widget_show (widget);
+}
+
+GType
+e_activity_proxy_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EActivityProxyClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) activity_proxy_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EActivityProxy),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) activity_proxy_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_EVENT_BOX, "EActivityProxy", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_activity_proxy_new (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
+
+ return g_object_new (
+ E_TYPE_ACTIVITY_PROXY,
+ "activity", activity, NULL);
+}
+
+EActivity *
+e_activity_proxy_get_activity (EActivityProxy *proxy)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY_PROXY (proxy), NULL);
+
+ return proxy->priv->activity;
+}
diff --cc widgets/misc/e-activity-proxy.h
index af305be,0000000..714dc63
mode 100644,000000..100644
--- a/widgets/misc/e-activity-proxy.h
+++ b/widgets/misc/e-activity-proxy.h
@@@ -1,68 -1,0 +1,68 @@@
+/*
+ * e-activity-proxy.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ACTIVITY_PROXY_H
+#define E_ACTIVITY_PROXY_H
+
+#include <gtk/gtk.h>
+#include <e-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ACTIVITY_PROXY \
+ (e_activity_proxy_get_type ())
+#define E_ACTIVITY_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxy))
+#define E_ACTIVITY_PROXY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ACTIVITY_PROXY, EActivityProxyClass))
+#define E_IS_ACTIVITY_PROXY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ACTIVITY_PROXY))
+#define E_IS_ACTIVITY_PROXY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ACTIVITY_PROXY))
+#define E_ACTIVITY_PROXY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ACTIVITY_PROXY, EActivityProxyClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EActivityProxy EActivityProxy;
+typedef struct _EActivityProxyClass EActivityProxyClass;
+typedef struct _EActivityProxyPrivate EActivityProxyPrivate;
+
+struct _EActivityProxy {
+ GtkEventBox parent;
+ EActivityProxyPrivate *priv;
+};
+
+struct _EActivityProxyClass {
+ GtkEventBoxClass parent_class;
+};
+
+GType e_activity_proxy_get_type (void);
+GtkWidget * e_activity_proxy_new (EActivity *activity);
+EActivity * e_activity_proxy_get_activity (EActivityProxy *proxy);
+
+G_END_DECLS
+
+#endif /* E_ACTIVITY_PROXY_H */
diff --cc widgets/misc/e-activity.c
index 7cd89a7,0000000..ac9a3d7
mode 100644,000000..100644
--- a/widgets/misc/e-activity.c
+++ b/widgets/misc/e-activity.c
@@@ -1,764 -1,0 +1,764 @@@
+/*
+ * e-activity.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-activity.h"
+
+#include <stdarg.h>
+#include <glib/gi18n.h>
+
+#include "e-util/e-util.h"
+
+#define E_ACTIVITY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ACTIVITY, EActivityPrivate))
+
+struct _EActivityPrivate {
+ gchar *icon_name;
+ gchar *primary_text;
+ gchar *secondary_text;
+ gdouble percent;
+ guint idle_id;
+ GError *error;
+
+ guint allow_cancel : 1;
+ guint blocking : 1;
+ guint cancelled : 1;
+ guint clickable : 1;
+ guint completed : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_ALLOW_CANCEL,
+ PROP_BLOCKING,
+ PROP_CLICKABLE,
+ PROP_ICON_NAME,
+ PROP_PERCENT,
+ PROP_PRIMARY_TEXT,
+ PROP_SECONDARY_TEXT
+};
+
+enum {
+ CANCELLED,
+ CLICKED,
+ COMPLETED,
+ DESCRIBE,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static gulong signals[LAST_SIGNAL];
+
+static gboolean
+activity_idle_cancel_cb (EActivity *activity)
+{
+ activity->priv->idle_id = 0;
+ e_activity_cancel (activity);
+ g_object_unref (activity);
+
+ return FALSE;
+}
+
+static gboolean
+activity_idle_complete_cb (EActivity *activity)
+{
+ activity->priv->idle_id = 0;
+ e_activity_complete (activity);
+ g_object_unref (activity);
+
+ return FALSE;
+}
+
+static gboolean
+activity_describe_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer accu_data)
+{
+ const gchar *string;
+
+ string = g_value_get_string (handler_return);
+ g_value_set_string (return_accu, string);
+
+ return (string == NULL);
+}
+
+static void
+activity_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ALLOW_CANCEL:
+ e_activity_set_allow_cancel (
+ E_ACTIVITY (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_BLOCKING:
+ e_activity_set_blocking (
+ E_ACTIVITY (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_CLICKABLE:
+ e_activity_set_clickable (
+ E_ACTIVITY (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_ICON_NAME:
+ e_activity_set_icon_name (
+ E_ACTIVITY (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_PERCENT:
+ e_activity_set_percent (
+ E_ACTIVITY (object),
+ g_value_get_double (value));
+ return;
+
+ case PROP_PRIMARY_TEXT:
+ e_activity_set_primary_text (
+ E_ACTIVITY (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_SECONDARY_TEXT:
+ e_activity_set_secondary_text (
+ E_ACTIVITY (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+activity_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ALLOW_CANCEL:
+ g_value_set_boolean (
+ value, e_activity_get_allow_cancel (
+ E_ACTIVITY (object)));
+ return;
+
+ case PROP_BLOCKING:
+ g_value_set_boolean (
+ value, e_activity_get_blocking (
+ E_ACTIVITY (object)));
+ return;
+
+ case PROP_CLICKABLE:
+ g_value_set_boolean (
+ value, e_activity_get_clickable (
+ E_ACTIVITY (object)));
+ return;
+
+ case PROP_ICON_NAME:
+ g_value_set_string (
+ value, e_activity_get_icon_name (
+ E_ACTIVITY (object)));
+ return;
+
+ case PROP_PERCENT:
+ g_value_set_double (
+ value, e_activity_get_percent (
+ E_ACTIVITY (object)));
+ return;
+
+ case PROP_PRIMARY_TEXT:
+ g_value_set_string (
+ value, e_activity_get_primary_text (
+ E_ACTIVITY (object)));
+ return;
+
+ case PROP_SECONDARY_TEXT:
+ g_value_set_string (
+ value, e_activity_get_secondary_text (
+ E_ACTIVITY (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+activity_finalize (GObject *object)
+{
+ EActivityPrivate *priv;
+
+ priv = E_ACTIVITY_GET_PRIVATE (object);
+
+ g_free (priv->icon_name);
+ g_free (priv->primary_text);
+ g_free (priv->secondary_text);
+
+ if (priv->idle_id > 0)
+ g_source_remove (priv->idle_id);
+
+ if (priv->error != NULL)
+ g_error_free (priv->error);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+activity_cancelled (EActivity *activity)
+{
+ activity->priv->cancelled = TRUE;
+
+ if (activity->priv->idle_id > 0) {
+ g_source_remove (activity->priv->idle_id);
+ activity->priv->idle_id = 0;
+ }
+}
+
+static void
+activity_completed (EActivity *activity)
+{
+ activity->priv->completed = TRUE;
+
+ if (activity->priv->idle_id > 0) {
+ g_source_remove (activity->priv->idle_id);
+ activity->priv->idle_id = 0;
+ }
+}
+
+static void
+activity_clicked (EActivity *activity)
+{
+ /* Allow subclasses to safely chain up. */
+}
+
+static gchar *
+activity_describe (EActivity *activity)
+{
+ GString *string;
+ const gchar *text;
+ gboolean cancelled;
+ gboolean completed;
+ gdouble percent;
+
+ string = g_string_sized_new (256);
+ text = e_activity_get_primary_text (activity);
+ cancelled = e_activity_is_cancelled (activity);
+ completed = e_activity_is_completed (activity);
+ percent = e_activity_get_percent (activity);
+
+ if (cancelled) {
+ /* Translators: This is a cancelled activity. */
+ g_string_printf (string, _("%s (cancelled)"), text);
+ } else if (completed) {
+ /* Translators: This is a completed activity. */
+ g_string_printf (string, _("%s (completed)"), text);
+ } else if (percent < 0.0) {
+ /* Translators: This is an activity whose percent
+ * complete is unknown. */
+ g_string_printf (string, _("%s..."), text);
+ } else {
+ /* Translators: This is an activity whose percent
+ * complete is known. */
+ g_string_printf (
+ string, _("%s (%d%% complete)"), text,
+ (gint) (percent * 100.0 + 0.5));
+ }
+
+ return g_string_free (string, FALSE);
+}
+
+static void
+activity_class_init (EActivityClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EActivityPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = activity_set_property;
+ object_class->get_property = activity_get_property;
+ object_class->finalize = activity_finalize;
+
+ class->cancelled = activity_cancelled;
+ class->completed = activity_completed;
+ class->clicked = activity_clicked;
+ class->describe = activity_describe;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ALLOW_CANCEL,
+ g_param_spec_boolean (
+ "allow-cancel",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BLOCKING,
+ g_param_spec_boolean (
+ "blocking",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CLICKABLE,
+ g_param_spec_boolean (
+ "clickable",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ICON_NAME,
+ g_param_spec_string (
+ "icon-name",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PERCENT,
+ g_param_spec_double (
+ "percent",
+ NULL,
+ NULL,
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE,
+ -1.0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PRIMARY_TEXT,
+ g_param_spec_string (
+ "primary-text",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SECONDARY_TEXT,
+ g_param_spec_string (
+ "secondary-text",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ signals[CANCELLED] = g_signal_new (
+ "cancelled",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EActivityClass, cancelled),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[CLICKED] = g_signal_new (
+ "clicked",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EActivityClass, clicked),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[COMPLETED] = g_signal_new (
+ "completed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EActivityClass, completed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[DESCRIBE] = g_signal_new (
+ "describe",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EActivityClass, describe),
+ activity_describe_accumulator, NULL,
+ e_marshal_STRING__VOID,
+ G_TYPE_STRING, 0);
+}
+
+static void
+activity_init (EActivity *activity)
+{
+ activity->priv = E_ACTIVITY_GET_PRIVATE (activity);
+}
+
+GType
+e_activity_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EActivityClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) activity_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EActivity),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) activity_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EActivity", &type_info, 0);
+ }
+
+ return type;
+}
+
+EActivity *
+e_activity_new (const gchar *primary_text)
+{
+ return g_object_new (
+ E_TYPE_ACTIVITY,
+ "primary-text", primary_text, NULL);
+}
+
+EActivity *
+e_activity_newv (const gchar *format, ...)
+{
+ EActivity *activity;
+ gchar *primary_text;
+ va_list args;
+
+ va_start (args, format);
+ primary_text = g_strdup_vprintf (format, args);
+ activity = e_activity_new (primary_text);
+ g_free (primary_text);
+ va_end (args);
+
+ return activity;
+}
+
+void
+e_activity_cancel (EActivity *activity)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
- if (!activity->priv->allow_cancel);
++ if (!activity->priv->allow_cancel)
+ return;
+
+ if (activity->priv->cancelled)
+ return;
+
+ if (activity->priv->completed)
+ return;
+
+ g_signal_emit (activity, signals[CANCELLED], 0);
+}
+
+void
+e_activity_cancel_in_idle (EActivity *activity)
+{
+ guint old_idle_id;
+
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ /* Be careful not to finalize the activity. Decrement the
+ * reference count only after incrementing it, in case this
+ * is the last reference. */
+
+ old_idle_id = activity->priv->idle_id;
+
+ activity->priv->idle_id = g_idle_add (
+ (GSourceFunc) activity_idle_cancel_cb,
+ g_object_ref (activity));
+
+ if (old_idle_id > 0) {
+ g_source_remove (old_idle_id);
+ g_object_unref (activity);
+ }
+}
+
+void
+e_activity_complete (EActivity *activity)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ if (activity->priv->cancelled)
+ return;
+
+ if (activity->priv->completed)
+ return;
+
+ g_signal_emit (activity, signals[COMPLETED], 0);
+}
+
+void
+e_activity_complete_in_idle (EActivity *activity)
+{
+ guint old_idle_id;
+
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ /* Be careful not to finalize the activity. Decrement the
+ * reference count only after incrementing it, in case this
+ * is the last reference. */
+
+ old_idle_id = activity->priv->idle_id;
+
+ activity->priv->idle_id = g_idle_add (
+ (GSourceFunc) activity_idle_complete_cb,
+ g_object_ref (activity));
+
+ if (old_idle_id > 0) {
+ g_source_remove (old_idle_id);
+ g_object_unref (activity);
+ }
+}
+
+void
+e_activity_clicked (EActivity *activity)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ g_signal_emit (activity, signals[CLICKED], 0);
+}
+
+gchar *
+e_activity_describe (EActivity *activity)
+{
+ EActivityClass *class;
+
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
+
+ class = E_ACTIVITY_GET_CLASS (activity);
+ g_return_val_if_fail (class->describe != NULL, NULL);
+
+ return class->describe (activity);
+}
+
+gboolean
+e_activity_is_cancelled (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
+
+ return activity->priv->cancelled;
+}
+
+gboolean
+e_activity_is_completed (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
+
+ return activity->priv->completed;
+}
+
+gboolean
+e_activity_get_allow_cancel (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
+
+ return activity->priv->allow_cancel;
+}
+
+void
+e_activity_set_allow_cancel (EActivity *activity,
+ gboolean allow_cancel)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ activity->priv->allow_cancel = allow_cancel;
+
+ g_object_notify (G_OBJECT (activity), "allow-cancel");
+}
+
+gboolean
+e_activity_get_blocking (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
+
+ return activity->priv->blocking;
+}
+
+void
+e_activity_set_blocking (EActivity *activity,
+ gboolean blocking)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ activity->priv->blocking = blocking;
+
+ g_object_notify (G_OBJECT (activity), "blocking");
+}
+
+gboolean
+e_activity_get_clickable (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
+
+ return activity->priv->clickable;
+}
+
+void
+e_activity_set_clickable (EActivity *activity,
+ gboolean clickable)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ activity->priv->clickable = clickable;
+
+ g_object_notify (G_OBJECT (activity), "clickable");
+}
+
+const gchar *
+e_activity_get_icon_name (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
+
+ return activity->priv->icon_name;
+}
+
+void
+e_activity_set_icon_name (EActivity *activity,
+ const gchar *icon_name)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ g_free (activity->priv->icon_name);
+ activity->priv->icon_name = g_strdup (icon_name);
+
+ g_object_notify (G_OBJECT (activity), "icon-name");
+}
+
+gdouble
+e_activity_get_percent (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), -1.0);
+
+ return activity->priv->percent;
+}
+
+void
+e_activity_set_percent (EActivity *activity,
+ gdouble percent)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ activity->priv->percent = percent;
+
+ g_object_notify (G_OBJECT (activity), "percent");
+}
+
+const gchar *
+e_activity_get_primary_text (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
+
+ return activity->priv->primary_text;
+}
+
+void
+e_activity_set_primary_text (EActivity *activity,
+ const gchar *primary_text)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ g_free (activity->priv->primary_text);
+ activity->priv->primary_text = g_strdup (primary_text);
+
+ g_object_notify (G_OBJECT (activity), "primary-text");
+}
+
+const gchar *
+e_activity_get_secondary_text (EActivity *activity)
+{
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), NULL);
+
+ return activity->priv->secondary_text;
+}
+
+void
+e_activity_set_secondary_text (EActivity *activity,
+ const gchar *secondary_text)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ g_free (activity->priv->secondary_text);
+ activity->priv->secondary_text = g_strdup (secondary_text);
+
+ g_object_notify (G_OBJECT (activity), "secondary-text");
+}
+
+void
+e_activity_set_error (EActivity *activity,
+ const GError *error)
+{
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ if (activity->priv->error != NULL) {
+ g_error_free (activity->priv->error);
+ activity->priv->error = NULL;
+ }
+
+ if (error != NULL)
+ activity->priv->error = g_error_copy (error);
+}
+
+gboolean
+e_activity_propagate_error (EActivity *activity,
+ GError **destination)
+{
+ gboolean propagated;
+
+ g_return_val_if_fail (E_IS_ACTIVITY (activity), FALSE);
+
+ if ((propagated = (activity->priv->error != NULL))) {
+ g_propagate_error (destination, activity->priv->error);
+ activity->priv->error = NULL;
+ }
+
+ return propagated;
+}
diff --cc widgets/misc/e-activity.h
index 34974dd,0000000..aca2621
mode 100644,000000..100644
--- a/widgets/misc/e-activity.h
+++ b/widgets/misc/e-activity.h
@@@ -1,107 -1,0 +1,107 @@@
+/*
+ * e-activity.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ACTIVITY_H
+#define E_ACTIVITY_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ACTIVITY \
+ (e_activity_get_type ())
+#define E_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ACTIVITY, EActivity))
+#define E_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ACTIVITY, EActivityClass))
+#define E_IS_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ACTIVITY))
+#define E_IS_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ACTIVITY))
+#define E_ACTIVITY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ACTIVITY, EActivityClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EActivity EActivity;
+typedef struct _EActivityClass EActivityClass;
+typedef struct _EActivityPrivate EActivityPrivate;
+
+struct _EActivity {
+ GObject parent;
+ EActivityPrivate *priv;
+};
+
+struct _EActivityClass {
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*cancelled) (EActivity *activity);
+ void (*completed) (EActivity *activity);
+ void (*clicked) (EActivity *activity);
+ gchar * (*describe) (EActivity *activity);
+};
+
+GType e_activity_get_type (void);
+EActivity * e_activity_new (const gchar *primary_text);
+EActivity * e_activity_newv (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
+void e_activity_cancel (EActivity *activity);
+void e_activity_cancel_in_idle (EActivity *activity);
+void e_activity_complete (EActivity *activity);
+void e_activity_complete_in_idle (EActivity *activity);
+void e_activity_clicked (EActivity *activity);
+gchar * e_activity_describe (EActivity *activity);
+gboolean e_activity_is_cancelled (EActivity *activity);
+gboolean e_activity_is_completed (EActivity *activity);
+gboolean e_activity_get_allow_cancel (EActivity *activity);
+void e_activity_set_allow_cancel (EActivity *activity,
+ gboolean allow_cancel);
+gboolean e_activity_get_blocking (EActivity *activity);
+void e_activity_set_blocking (EActivity *activity,
+ gboolean blocking);
+gboolean e_activity_get_clickable (EActivity *activity);
+void e_activity_set_clickable (EActivity *activity,
+ gboolean clickable);
+const gchar * e_activity_get_icon_name (EActivity *activity);
+void e_activity_set_icon_name (EActivity *activity,
+ const gchar *icon_name);
+gdouble e_activity_get_percent (EActivity *activity);
+void e_activity_set_percent (EActivity *activity,
+ gdouble percent);
+const gchar * e_activity_get_primary_text (EActivity *activity);
+void e_activity_set_primary_text (EActivity *activity,
+ const gchar *primary_text);
+const gchar * e_activity_get_secondary_text (EActivity *activity);
+void e_activity_set_secondary_text (EActivity *activity,
+ const gchar *secondary_text);
+void e_activity_set_error (EActivity *activity,
+ const GError *error);
+gboolean e_activity_propagate_error (EActivity *activity,
+ GError **destination);
+
+G_END_DECLS
+
+#endif /* E_ACTIVITY_H */
diff --cc widgets/misc/e-alert-activity.c
index d8b9d6f,0000000..860b129
mode 100644,000000..100644
--- a/widgets/misc/e-alert-activity.c
+++ b/widgets/misc/e-alert-activity.c
@@@ -1,254 -1,0 +1,254 @@@
+/*
+ * e-alert-activity.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-alert-activity.h"
+
+#define E_ALERT_ACTIVITY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityPrivate))
+
+struct _EAlertActivityPrivate {
+ GtkWidget *message_dialog;
+};
+
+enum {
+ PROP_0,
+ PROP_MESSAGE_DIALOG
+};
+
+static gpointer parent_class;
+
+static void
+alert_activity_set_message_dialog (EAlertActivity *alert_activity,
+ GtkWidget *message_dialog)
+{
+ g_return_if_fail (alert_activity->priv->message_dialog == NULL);
+
+ alert_activity->priv->message_dialog = g_object_ref (message_dialog);
+}
+
+static void
+alert_activity_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MESSAGE_DIALOG:
+ alert_activity_set_message_dialog (
+ E_ALERT_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+alert_activity_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_MESSAGE_DIALOG:
+ g_value_set_object (
+ value, e_alert_activity_get_message_dialog (
+ E_ALERT_ACTIVITY (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+alert_activity_dispose (GObject *object)
+{
+ EAlertActivityPrivate *priv;
+
+ priv = E_ALERT_ACTIVITY_GET_PRIVATE (object);
+
+ if (priv->message_dialog != NULL) {
+ g_object_unref (priv->message_dialog);
+ priv->message_dialog = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+alert_activity_constructed (GObject *object)
+{
+ EActivity *activity;
+ EAlertActivity *alert_activity;
+ GtkWidget *message_dialog;
+ const gchar *primary_text;
+ const gchar *secondary_text;
+
+ alert_activity = E_ALERT_ACTIVITY (object);
+ message_dialog = e_alert_activity_get_message_dialog (alert_activity);
+
+ object = G_OBJECT (message_dialog);
+ primary_text = g_object_get_data (object, "primary");
+ secondary_text = g_object_get_data (object, "secondary");
+
+ activity = E_ACTIVITY (alert_activity);
+ e_activity_set_primary_text (activity, primary_text);
+ e_activity_set_secondary_text (activity, secondary_text);
+}
+
+static void
+alert_activity_clicked (EActivity *activity)
+{
+ EAlertActivity *alert_activity;
+ GtkWidget *message_dialog;
+
+ e_activity_complete (activity);
+
+ alert_activity = E_ALERT_ACTIVITY (activity);
+ message_dialog = e_alert_activity_get_message_dialog (alert_activity);
+ gtk_dialog_run (GTK_DIALOG (message_dialog));
+ gtk_widget_hide (message_dialog);
+
+ /* Chain up to parent's clicked() method. */
+ E_ACTIVITY_CLASS (parent_class)->clicked (activity);
+}
+
+static void
+alert_activity_timeout (ETimeoutActivity *activity)
+{
+ e_activity_complete (E_ACTIVITY (activity));
+
+ /* Chain up to parent's timeout() method. */
+ E_TIMEOUT_ACTIVITY_CLASS (parent_class)->timeout (activity);
+}
+
+static void
+alert_activity_class_init (EAlertActivityClass *class)
+{
+ GObjectClass *object_class;
+ EActivityClass *activity_class;
+ ETimeoutActivityClass *timeout_activity_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAlertActivityPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = alert_activity_set_property;
+ object_class->get_property = alert_activity_get_property;
+ object_class->dispose = alert_activity_dispose;
+ object_class->constructed = alert_activity_constructed;
+
+ activity_class = E_ACTIVITY_CLASS (class);
+ activity_class->clicked = alert_activity_clicked;
+
+ timeout_activity_class = E_TIMEOUT_ACTIVITY_CLASS (class);
+ timeout_activity_class->timeout = alert_activity_timeout;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_MESSAGE_DIALOG,
+ g_param_spec_object (
+ "message-dialog",
+ NULL,
+ NULL,
+ GTK_TYPE_DIALOG,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+alert_activity_init (EAlertActivity *alert_activity)
+{
+ alert_activity->priv = E_ALERT_ACTIVITY_GET_PRIVATE (alert_activity);
+
+ e_activity_set_clickable (E_ACTIVITY (alert_activity), TRUE);
+ e_timeout_activity_set_timeout (E_TIMEOUT_ACTIVITY (alert_activity), 60);
+}
+
+GType
+e_alert_activity_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAlertActivityClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) alert_activity_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAlertActivity),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) alert_activity_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_TIMEOUT_ACTIVITY, "EAlertActivity",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+EActivity *
+e_alert_activity_new_info (GtkWidget *message_dialog)
+{
+ g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+ return g_object_new (
+ E_TYPE_ALERT_ACTIVITY,
+ "icon-name", "dialog-information",
+ "message-dialog", message_dialog, NULL);
+}
+
+EActivity *
+e_alert_activity_new_error (GtkWidget *message_dialog)
+{
+ g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+ return g_object_new (
+ E_TYPE_ALERT_ACTIVITY,
+ "icon-name", "dialog-error",
+ "message-dialog", message_dialog, NULL);
+}
+
+EActivity *
+e_alert_activity_new_warning (GtkWidget *message_dialog)
+{
+ g_return_val_if_fail (GTK_IS_DIALOG (message_dialog), NULL);
+
+ return g_object_new (
+ E_TYPE_ALERT_ACTIVITY,
+ "icon-name", "dialog-warning",
+ "message-dialog", message_dialog, NULL);
+}
+
+GtkWidget *
+e_alert_activity_get_message_dialog (EAlertActivity *alert_activity)
+{
+ g_return_val_if_fail (E_IS_ALERT_ACTIVITY (alert_activity), NULL);
+
+ return alert_activity->priv->message_dialog;
+}
diff --cc widgets/misc/e-alert-activity.h
index 4c5547d,0000000..5557094
mode 100644,000000..100644
--- a/widgets/misc/e-alert-activity.h
+++ b/widgets/misc/e-alert-activity.h
@@@ -1,70 -1,0 +1,70 @@@
+/*
+ * e-alert-activity.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_ALERT_ACTIVITY_H
+#define E_ALERT_ACTIVITY_H
+
+#include <e-timeout-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ALERT_ACTIVITY \
+ (e_alert_activity_get_type ())
+#define E_ALERT_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivity))
+#define E_ALERT_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass))
+#define E_IS_ALERT_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ALERT_ACTIVITY))
+#define E_IS_ALERT_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ALERT_ACTIVITY))
+#define E_ALERT_ACTIVITY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ALERT_ACTIVITY, EAlertActivityClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAlertActivity EAlertActivity;
+typedef struct _EAlertActivityClass EAlertActivityClass;
+typedef struct _EAlertActivityPrivate EAlertActivityPrivate;
+
+struct _EAlertActivity {
+ ETimeoutActivity parent;
+ EAlertActivityPrivate *priv;
+};
+
+struct _EAlertActivityClass {
+ ETimeoutActivityClass parent_class;
+};
+
+GType e_alert_activity_get_type (void);
+EActivity * e_alert_activity_new_info (GtkWidget *message_dialog);
+EActivity * e_alert_activity_new_error (GtkWidget *message_dialog);
+EActivity * e_alert_activity_new_warning (GtkWidget *message_dialog);
+GtkWidget * e_alert_activity_get_message_dialog
+ (EAlertActivity *alert_activity);
+
+G_END_DECLS
+
+#endif /* E_ALERT_ACTIVITY_H */
diff --cc widgets/misc/e-file-activity.c
index 1957c20,0000000..e35ab49
mode 100644,000000..100644
--- a/widgets/misc/e-file-activity.c
+++ b/widgets/misc/e-file-activity.c
@@@ -1,365 -1,0 +1,365 @@@
+/*
+ * e-file-activity.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-file-activity.h"
+
+#include <stdarg.h>
+
+#define E_FILE_ACTIVITY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_FILE_ACTIVITY, EFileActivityPrivate))
+
+struct _EFileActivityPrivate {
+ GCancellable *cancellable;
+ GAsyncResult *result;
+ GFile *file;
+
+ gulong handler_id;
+};
+
+enum {
+ PROP_0,
+ PROP_CANCELLABLE,
+ PROP_FILE,
+ PROP_RESULT
+};
+
+static gpointer parent_class;
+
+static void
+file_activity_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CANCELLABLE:
+ e_file_activity_set_cancellable (
+ E_FILE_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_FILE:
+ e_file_activity_set_file (
+ E_FILE_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_RESULT:
+ e_file_activity_set_result (
+ E_FILE_ACTIVITY (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+file_activity_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_CANCELLABLE:
+ g_value_set_object (
+ value, e_file_activity_get_cancellable (
+ E_FILE_ACTIVITY (object)));
+ return;
+
+ case PROP_FILE:
+ g_value_set_object (
+ value, e_file_activity_get_file (
+ E_FILE_ACTIVITY (object)));
+ return;
+
+ case PROP_RESULT:
+ g_value_set_object (
+ value, e_file_activity_get_result (
+ E_FILE_ACTIVITY (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+file_activity_dispose (GObject *object)
+{
+ EFileActivityPrivate *priv;
+
+ priv = E_FILE_ACTIVITY_GET_PRIVATE (object);
+
+ if (priv->cancellable != NULL) {
+ g_signal_handler_disconnect (
+ priv->cancellable, priv->handler_id);
+ g_object_unref (priv->cancellable);
+ priv->cancellable = NULL;
+ }
+
+ if (priv->result != NULL) {
+ g_object_unref (priv->result);
+ priv->result = NULL;
+ }
+
+ if (priv->file != NULL) {
+ g_object_unref (priv->file);
+ priv->file = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+file_activity_cancelled (EActivity *activity)
+{
+ EFileActivity *file_activity;
+ GCancellable *cancellable;
+
+ file_activity = E_FILE_ACTIVITY (activity);
+ cancellable = e_file_activity_get_cancellable (file_activity);
+ g_cancellable_cancel (cancellable);
+
+ /* Chain up to parent's cancelled() method. */
+ E_ACTIVITY_CLASS (parent_class)->cancelled (activity);
+}
+
+static void
+file_activity_class_init (EFileActivityClass *class)
+{
+ GObjectClass *object_class;
+ EActivityClass *activity_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EFileActivityPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = file_activity_set_property;
+ object_class->get_property = file_activity_get_property;
+ object_class->dispose = file_activity_dispose;
+
+ activity_class = E_ACTIVITY_CLASS (class);
+ activity_class->cancelled = file_activity_cancelled;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CANCELLABLE,
+ g_param_spec_object (
+ "cancellable",
+ "Cancellable",
+ NULL,
+ G_TYPE_CANCELLABLE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILE,
+ g_param_spec_object (
+ "file",
+ "File",
+ NULL,
+ G_TYPE_FILE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_RESULT,
+ g_param_spec_object (
+ "result",
+ "Result",
+ NULL,
+ G_TYPE_ASYNC_RESULT,
+ G_PARAM_READWRITE));
+}
+
+static void
+file_activity_init (EFileActivity *file_activity)
+{
+ GCancellable *cancellable;
+
+ file_activity->priv = E_FILE_ACTIVITY_GET_PRIVATE (file_activity);
+
+ e_activity_set_allow_cancel (E_ACTIVITY (file_activity), TRUE);
+
+ cancellable = g_cancellable_new ();
+ e_file_activity_set_cancellable (file_activity, cancellable);
+ g_object_unref (cancellable);
+}
+
+GType
+e_file_activity_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EFileActivityClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) file_activity_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EFileActivity),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) file_activity_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_ACTIVITY, "EFileActivity", &type_info, 0);
+ }
+
+ return type;
+}
+
+EActivity *
+e_file_activity_new (const gchar *primary_text)
+{
+ return g_object_new (
+ E_TYPE_FILE_ACTIVITY,
+ "primary-text", primary_text, NULL);
+}
+
+EActivity *
+e_file_activity_newv (const gchar *format, ...)
+{
+ EActivity *activity;
+ gchar *primary_text;
+ va_list args;
+
+ va_start (args, format);
+ primary_text = g_strdup_vprintf (format, args);
+ activity = e_file_activity_new (primary_text);
+ g_free (primary_text);
+ va_end (args);
+
+ return activity;
+}
+
+GCancellable *
+e_file_activity_get_cancellable (EFileActivity *file_activity)
+{
+ g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
+
+ return file_activity->priv->cancellable;
+}
+
+void
+e_file_activity_set_cancellable (EFileActivity *file_activity,
+ GCancellable *cancellable)
+{
+ g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
+
+ if (cancellable != NULL) {
+ g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+ g_object_ref (cancellable);
+ }
+
+ if (file_activity->priv->cancellable != NULL) {
+ g_signal_handler_disconnect (
+ file_activity->priv->cancellable,
+ file_activity->priv->handler_id);
+ g_object_unref (file_activity->priv->cancellable);
+ file_activity->priv->handler_id = 0;
+ }
+
+ file_activity->priv->cancellable = cancellable;
+
+ if (cancellable != NULL)
+ file_activity->priv->handler_id =
+ g_signal_connect_swapped (
+ cancellable, "cancelled",
+ G_CALLBACK (e_activity_cancel),
+ file_activity);
+
+ g_object_notify (G_OBJECT (file_activity), "cancellable");
+}
+
+GFile *
+e_file_activity_get_file (EFileActivity *file_activity)
+{
+ g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
+
+ return file_activity->priv->file;
+}
+
+void
+e_file_activity_set_file (EFileActivity *file_activity,
+ GFile *file)
+{
+ g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
+
+ if (file != NULL) {
+ g_return_if_fail (G_IS_FILE (file));
+ g_object_ref (file);
+ }
+
+ if (file_activity->priv->file != NULL)
+ g_object_unref (file_activity->priv->file);
+
+ file_activity->priv->file = file;
+
+ g_object_notify (G_OBJECT (file_activity), "file");
+}
+
+GAsyncResult *
+e_file_activity_get_result (EFileActivity *file_activity)
+{
+ g_return_val_if_fail (E_IS_FILE_ACTIVITY (file_activity), NULL);
+
+ return file_activity->priv->result;
+}
+
+void
+e_file_activity_set_result (EFileActivity *file_activity,
+ GAsyncResult *result)
+{
+ g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity));
+
+ if (result != NULL) {
+ g_return_if_fail (G_IS_ASYNC_RESULT (result));
+ g_object_ref (result);
+ }
+
+ if (file_activity->priv->result != NULL)
+ g_object_unref (file_activity->priv->result);
+
+ file_activity->priv->result = result;
+
+ g_object_notify (G_OBJECT (file_activity), "result");
+}
+
+void
+e_file_activity_progress (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer activity)
+{
+ gdouble percent = -1.0;
+
+ g_return_if_fail (E_IS_ACTIVITY (activity));
+
+ if (current_num_bytes > 0 && total_num_bytes > 0)
+ percent = (gdouble) current_num_bytes / total_num_bytes;
+
+ e_activity_set_percent (activity, percent);
+}
diff --cc widgets/misc/e-file-activity.h
index acd144d,0000000..b4a5433
mode 100644,000000..100644
--- a/widgets/misc/e-file-activity.h
+++ b/widgets/misc/e-file-activity.h
@@@ -1,83 -1,0 +1,83 @@@
+/*
+ * e-file-activity.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_FILE_ACTIVITY_H
+#define E_FILE_ACTIVITY_H
+
+#include <gio/gio.h>
+#include <widgets/misc/e-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_FILE_ACTIVITY \
+ (e_file_activity_get_type ())
+#define E_FILE_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_FILE_ACTIVITY, EFileActivity))
+#define E_FILE_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_FILE_ACTIVITY, EFileActivityClass))
+#define E_IS_FILE_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_FILE_ACTIVITY))
+#define E_IS_FILE_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_FILE_ACTIVITY))
+#define E_FILE_ACTIVITY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_FILE_ACTIVITY, EFileActivityClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EFileActivity EFileActivity;
+typedef struct _EFileActivityClass EFileActivityClass;
+typedef struct _EFileActivityPrivate EFileActivityPrivate;
+
+struct _EFileActivity {
+ EActivity parent;
+ EFileActivityPrivate *priv;
+};
+
+struct _EFileActivityClass {
+ EActivityClass parent_class;
+};
+
+GType e_file_activity_get_type (void);
+EActivity * e_file_activity_new (const gchar *primary_text);
+EActivity * e_file_activity_newv (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
+GCancellable * e_file_activity_get_cancellable (EFileActivity *file_activity);
+void e_file_activity_set_cancellable (EFileActivity *file_activity,
+ GCancellable *cancellable);
+GFile * e_file_activity_get_file (EFileActivity *file_activity);
+void e_file_activity_set_file (EFileActivity *file_activity,
+ GFile *file);
+GAsyncResult * e_file_activity_get_result (EFileActivity *file_activity);
+void e_file_activity_set_result (EFileActivity *file_activity,
+ GAsyncResult *result);
+
+/* This can be used as a GFileProgressCallback. */
+void e_file_activity_progress (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer activity);
+
+G_END_DECLS
+
+#endif /* E_FILE_ACTIVITY_H */
diff --cc widgets/misc/e-filter-bar.c
index 9f38ecc,9a67636..a113d1f
--- a/widgets/misc/e-filter-bar.c
+++ b/widgets/misc/e-filter-bar.c
@@@ -828,45 -937,34 +828,40 @@@ class_init (EFilterBarClass *class
}
static void
-init (EFilterBar *efb)
+filter_bar_init (EFilterBar *filter_bar)
{
- g_signal_connect (efb, "menu_activated", G_CALLBACK (menubar_activated), NULL);
- g_signal_connect (efb, "query_changed", G_CALLBACK (option_changed), NULL);
- g_signal_connect (efb, "search_activated", G_CALLBACK (option_changed), NULL);
+ g_signal_connect (filter_bar, "menu_activated", G_CALLBACK (menubar_activated), NULL);
+ g_signal_connect (filter_bar, "query_changed", G_CALLBACK (option_changed), NULL);
+ g_signal_connect (filter_bar, "search_activated", G_CALLBACK (option_changed), NULL);
- efb->menu_rules = g_ptr_array_new ();
- efb->option_rules = g_ptr_array_new ();
+ filter_bar->menu_rules = g_ptr_array_new ();
+ filter_bar->option_rules = g_ptr_array_new ();
}
-
-/* Object construction. */
-
-EFilterBar *
-e_filter_bar_new (RuleContext *context,
- const char *systemrules,
- const char *userrules,
- EFilterBarConfigRule config,
- void *data)
+GType
+e_filter_bar_get_type (void)
{
- EFilterBar *bar;
+ static GType type = 0;
- <<<<<<< HEAD:widgets/misc/e-filter-bar.c
- bar = g_object_new (e_filter_bar_get_type (), NULL);
- ((ESearchBar *)bar)->lite = FALSE;
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EFilterBarClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) filter_bar_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EFilterBar),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) filter_bar_init,
+ NULL /* value_table */
+ };
- =======
- bar = g_object_new (e_filter_bar_get_type (), NULL);
- ((ESearchBar *)bar)->lite = FALSE;
- >>>>>>> ff25805... Filter/Search bar changes for Anjal.:widgets/misc/e-filter-bar.c
- e_filter_bar_new_construct (context, systemrules, userrules, config, data, bar);
+ type = g_type_register_static (
+ E_TYPE_SEARCH_BAR, "EFilterBar", &type_info, 0);
+ }
- return bar;
+ return type;
}
EFilterBar *
diff --cc widgets/misc/e-icon-entry.h
index 65aff61,894cb16..e18b0fd
--- a/widgets/misc/e-icon-entry.h
+++ b/widgets/misc/e-icon-entry.h
@@@ -41,32 -41,30 +41,32 @@@
G_BEGIN_DECLS
-#define E_TYPE_ICON_ENTRY (e_icon_entry_get_type())
-#define E_ICON_ENTRY(object) (G_TYPE_CHECK_INSTANCE_CAST((object), E_TYPE_ICON_ENTRY, EIconEntry))
-#define E_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), E_TYPE_ICON_ENTRY, EIconEntryClass))
-#define E_IS_ICON_ENTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), E_TYPE_ICON_ENTRY))
-#define E_IS_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), E_TYPE_ICON_ENTRY))
-#define E_ICON_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), E_TYPE_ICON_ENTRY, EIconEntryClass))
-
+/* Standard GObject macros */
+#define E_TYPE_ICON_ENTRY \
+ (e_icon_entry_get_type())
+#define E_ICON_ENTRY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ICON_ENTRY, EIconEntry))
+#define E_ICON_ENTRY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ICON_ENTRY, EIconEntryClass))
+#define E_IS_ICON_ENTRY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ICON_ENTRY))
+#define E_IS_ICON_ENTRY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ICON_ENTRY))
+#define E_ICON_ENTRY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ICON_ENTRY, EIconEntryClass))
+
+typedef struct _EIconEntry EIconEntry;
typedef struct _EIconEntryClass EIconEntryClass;
-typedef struct _EIconEntry EIconEntry;
-typedef struct _EIconEntryPrivate EIconEntryPrivate;
-
-struct _EIconEntryClass
-{
- GtkBinClass parent_class;
-};
+typedef struct _EIconEntryPrivate EIconEntryPrivate;
-
+
struct _EIconEntry
{
- GtkBin parent_object;
-
- /*< public >*/
- GtkWidget *entry;
-
- /*< private >*/
+ GtkBin parent;
EIconEntryPrivate *priv;
};
diff --cc widgets/misc/e-menu-tool-button.c
index 5e87de8,0000000..53778e6
mode 100644,000000..100644
--- a/widgets/misc/e-menu-tool-button.c
+++ b/widgets/misc/e-menu-tool-button.c
@@@ -1,157 -1,0 +1,157 @@@
+/*
+ * e-menu-tool-button.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-menu-tool-button.h"
+
+static gpointer parent_class;
+
+static GtkWidget *
+menu_tool_button_clone_image (GtkWidget *source)
+{
+ 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_first_menu_item (GtkMenuToolButton *menu_tool_button)
+{
+ GtkWidget *menu;
+ GList *children;
+
+ menu = gtk_menu_tool_button_get_menu (menu_tool_button);
+ if (!GTK_IS_MENU (menu))
+ return NULL;
+
+ /* XXX GTK+ 2.12 provides no accessor function. */
+ children = GTK_MENU_SHELL (menu)->children;
+ if (children == NULL)
+ return NULL;
+
+ return GTK_MENU_ITEM (children->data);
+}
+
+static void
+menu_tool_button_update_button (GtkToolButton *tool_button)
+{
+ GtkMenuItem *menu_item;
+ GtkMenuToolButton *menu_tool_button;
+ GtkImageMenuItem *image_menu_item;
+ GtkAction *action;
+ GtkWidget *image;
+ gchar *tooltip = NULL;
+
+ menu_tool_button = GTK_MENU_TOOL_BUTTON (tool_button);
+ menu_item = menu_tool_button_get_first_menu_item (menu_tool_button);
+ if (!GTK_IS_IMAGE_MENU_ITEM (menu_item))
+ 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;
+
+ image = menu_tool_button_clone_image (image);
+ gtk_tool_button_set_icon_widget (tool_button, image);
+ gtk_widget_show (image);
+
+ /* If the menu item is a proxy for a GtkAction, extract
+ * the action's tooltip and use it as our own tooltip. */
+ action = gtk_widget_get_action (GTK_WIDGET (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);
+}
+
+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_first_menu_item (menu_tool_button);
+
+ if (GTK_IS_MENU_ITEM (menu_item))
+ gtk_menu_item_activate (menu_item);
+}
+
+static void
+menu_tool_button_class_init (EMenuToolButtonClass *class)
+{
+ GtkToolButtonClass *tool_button_class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ tool_button_class = GTK_TOOL_BUTTON_CLASS (class);
+ tool_button_class->clicked = menu_tool_button_clicked;
+}
+
+static void
+menu_tool_button_init (EMenuToolButton *button)
+{
+ g_signal_connect (
+ button, "notify::menu",
+ G_CALLBACK (menu_tool_button_update_button), NULL);
+}
+
+GType
+e_menu_tool_button_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (EMenuToolButtonClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) menu_tool_button_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EMenuToolButton),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) menu_tool_button_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_MENU_TOOL_BUTTON, "EMenuToolButton",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkToolItem *
+e_menu_tool_button_new (const gchar *label)
+{
+ return g_object_new (E_TYPE_MENU_TOOL_BUTTON, "label", label, NULL);
+}
diff --cc widgets/misc/e-menu-tool-button.h
index b10cf3a,0000000..214f5ab
mode 100644,000000..100644
--- a/widgets/misc/e-menu-tool-button.h
+++ b/widgets/misc/e-menu-tool-button.h
@@@ -1,68 -1,0 +1,68 @@@
+/*
+ * e-menu-tool-button.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* EMenuToolButton is a variation of GtkMenuToolButton where the
+ * button icon always reflects the first menu item, and clicking
+ * the button activates the first menu item. */
+
+#ifndef E_MENU_TOOL_BUTTON_H
+#define E_MENU_TOOL_BUTTON_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MENU_TOOL_BUTTON \
+ (e_menu_tool_button_get_type ())
+#define E_MENU_TOOL_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButton))
+#define E_MENU_TOOL_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButtonClass))
+#define E_IS_MENU_TOOL_BUTTON(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MENU_TOOL_BUTTON))
+#define E_IS_MENU_TOOL_BUTTON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MENU_TOOL_BUTTON))
+#define E_MENU_TOOL_BUTTON_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MENU_TOOL_BUTTON, EMenuToolButtonClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMenuToolButton EMenuToolButton;
+typedef struct _EMenuToolButtonClass EMenuToolButtonClass;
+
+struct _EMenuToolButton {
+ GtkMenuToolButton parent;
+};
+
+struct _EMenuToolButtonClass {
+ GtkMenuToolButtonClass parent_class;
+};
+
+GType e_menu_tool_button_get_type (void);
+GtkToolItem * e_menu_tool_button_new (const gchar *label);
+
+G_END_DECLS
+
+#endif /* E_MENU_TOOL_BUTTON_H */
diff --cc widgets/misc/e-popup-action.c
index 51abc01,0000000..e856a1f
mode 100644,000000..100644
--- a/widgets/misc/e-popup-action.c
+++ b/widgets/misc/e-popup-action.c
@@@ -1,285 -1,0 +1,285 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-popup-action.h"
+
+#include <glib/gi18n.h>
+#include "e-util/e-binding.h"
+
+#define E_POPUP_ACTION_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_POPUP_ACTION, EPopupActionPrivate))
+
+enum {
+ PROP_0,
+ PROP_SOURCE
+};
+
+struct _EPopupActionPrivate {
+ GtkAction *source;
+};
+
+static gpointer parent_class;
+
+static void
+popup_action_set_source (EPopupAction *popup_action,
+ GtkAction *source)
+{
+ g_return_if_fail (popup_action->priv->source == NULL);
+ g_return_if_fail (GTK_IS_ACTION (source));
+
+ popup_action->priv->source = g_object_ref (source);
+}
+
+static void
+popup_action_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE:
+ popup_action_set_source (
+ E_POPUP_ACTION (object),
+ g_value_get_object (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_SOURCE:
+ g_value_set_object (
+ value, e_popup_action_get_source (
+ E_POPUP_ACTION (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+popup_action_dispose (GObject *object)
+{
+ EPopupActionPrivate *priv;
+
+ priv = E_POPUP_ACTION_GET_PRIVATE (object);
+
+ if (priv->source != NULL) {
+ g_object_unref (priv->source);
+ priv->source = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+popup_action_constructed (GObject *object)
+{
+ EPopupActionPrivate *priv;
+ GObject *source;
+ gchar *icon_name;
+ gchar *label;
+ gchar *stock_id;
+ gchar *tooltip;
+
+ priv = E_POPUP_ACTION_GET_PRIVATE (object);
+
+ source = G_OBJECT (priv->source);
+
+ g_object_get (
+ object, "icon-name", &icon_name, "label", &label,
+ "stock-id", &stock_id, "tooltip", &tooltip, NULL);
+
+ if (label == NULL)
+ e_binding_new (source, "label", object, "label");
+
+ if (tooltip == NULL)
+ e_binding_new (source, "tooltip", object, "tooltip");
+
+ if (icon_name == NULL && stock_id == NULL) {
+ g_free (icon_name);
+ g_free (stock_id);
+
+ g_object_get (
+ source, "icon-name", &icon_name,
+ "stock-id", &stock_id, NULL);
+
+ if (icon_name == NULL) {
+ e_binding_new (
+ source, "icon-name", object, "icon-name");
+ e_binding_new (
+ source, "stock-id", object, "stock-id");
+ } else {
+ e_binding_new (
+ source, "stock-id", object, "stock-id");
+ e_binding_new (
+ source, "icon-name", object, "icon-name");
+ }
+ }
+
+ e_binding_new (source, "sensitive", object, "visible");
+
+ g_free (icon_name);
+ g_free (label);
+ g_free (stock_id);
+ g_free (tooltip);
+}
+
+static void
+popup_action_class_init (EPopupActionClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EPopupActionPrivate));
+
+ 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_install_property (
+ object_class,
+ PROP_SOURCE,
+ g_param_spec_object (
+ "source",
+ _("Source Action"),
+ _("The source action to proxy"),
+ GTK_TYPE_ACTION,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+popup_action_init (EPopupAction *popup_action)
+{
+ popup_action->priv = E_POPUP_ACTION_GET_PRIVATE (popup_action);
+}
+
+GType
+e_popup_action_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EPopupActionClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) popup_action_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EPopupAction),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) popup_action_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_ACTION, "EPopupAction", &type_info, 0);
+ }
+
+ return type;
+}
+
+EPopupAction *
+e_popup_action_new (const gchar *name,
+ const gchar *label,
+ GtkAction *source)
+{
+ EPopupAction *popup_action;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (GTK_IS_ACTION (source), NULL);
+
+ popup_action = g_object_new (
+ E_TYPE_POPUP_ACTION, "name", name,
+ "label", label, "source", source, NULL);
+
+ /* XXX This is a hack to work around the fact that GtkAction's
+ * "label" and "tooltip" properties are not constructor
+ * properties, even though they're supplied upfront.
+ *
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=568334 */
+ popup_action_constructed (G_OBJECT (popup_action));
+
+ return popup_action;
+}
+
+GtkAction *
+e_popup_action_get_source (EPopupAction *popup_action)
+{
+ g_return_val_if_fail (E_IS_POPUP_ACTION (popup_action), NULL);
+
+ return popup_action->priv->source;
+}
+
+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 *source;
+ const gchar *label;
+
+ label = gtk_action_group_translate_string (
+ action_group, entries[ii].label);
+
+ source = gtk_action_group_get_action (
+ action_group, entries[ii].source);
+
+ if (source == NULL) {
+ g_warning (
+ "Source action '%s' not found in "
+ "action group '%s'", entries[ii].source,
+ gtk_action_group_get_name (action_group));
+ continue;
+ }
+
+ popup_action = e_popup_action_new (
+ entries[ii].name, label, source);
+
+ g_signal_connect_swapped (
+ popup_action, "activate",
+ G_CALLBACK (gtk_action_activate),
+ popup_action->priv->source);
+
+ gtk_action_group_add_action (
+ action_group, GTK_ACTION (popup_action));
+
+ g_object_unref (popup_action);
+ }
+}
diff --cc widgets/misc/e-popup-action.h
index 6000b5a,0000000..d19971f
mode 100644,000000..100644
--- a/widgets/misc/e-popup-action.h
+++ b/widgets/misc/e-popup-action.h
@@@ -1,95 -1,0 +1,95 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * 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 "sources" 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.
+ */
+
+#ifndef E_POPUP_ACTION_H
+#define E_POPUP_ACTION_H
+
+#include <gtk/gtk.h>
+
+/* 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 source action */
+ const gchar *source; /* name of the source action */
+};
+
+GType e_popup_action_get_type (void);
+EPopupAction * e_popup_action_new (const gchar *name,
+ const gchar *label,
+ GtkAction *source);
+GtkAction * e_popup_action_get_source (EPopupAction *popup_action);
+
+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 --cc widgets/misc/e-preferences-window.c
index ecdbee1,0000000..af2d07d
mode 100644,000000..100644
--- a/widgets/misc/e-preferences-window.c
+++ b/widgets/misc/e-preferences-window.c
@@@ -1,393 -1,0 +1,393 @@@
+/*
+ * e-preferences-window.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-preferences-window.h"
+
+#include <glib/gi18n.h>
+#include <e-util/e-util.h>
+
+#define SWITCH_PAGE_INTERVAL 250
+
+#define E_PREFERENCES_WINDOW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowPrivate))
+
+struct _EPreferencesWindowPrivate {
+ GtkWidget *icon_view;
+ GtkWidget *notebook;
+ GHashTable *index;
+};
+
+enum {
+ COLUMN_TEXT, /* G_TYPE_STRING */
+ COLUMN_PIXBUF, /* GDK_TYPE_PIXBUF */
+ COLUMN_PAGE, /* G_TYPE_INT */
+ COLUMN_SORT /* G_TYPE_INT */
+};
+
+static gpointer parent_class;
+
+static GdkPixbuf *
+preferences_window_load_pixbuf (const gchar *icon_name)
+{
+ GtkIconTheme *icon_theme;
+ GtkIconInfo *icon_info;
+ GdkPixbuf *pixbuf;
+ const gchar *filename;
+ gint size;
+ GError *error = NULL;
+
+ icon_theme = gtk_icon_theme_get_default ();
+
+ if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &size, 0))
+ return NULL;
+
+ icon_info = gtk_icon_theme_lookup_icon (
+ icon_theme, icon_name, size, 0);
+
+ if (icon_info == NULL)
+ return NULL;
+
+ filename = gtk_icon_info_get_filename (icon_info);
+
+ pixbuf = gdk_pixbuf_new_from_file (filename, &error);
+
+ gtk_icon_info_free (icon_info);
+
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ return pixbuf;
+}
+
+static void
+preferences_window_help_clicked_cb (GtkWindow *window)
+{
+ e_display_help (window, "config-prefs");
+}
+
+static void
+preferences_window_selection_changed_cb (EPreferencesWindow *window)
+{
+ GtkIconView *icon_view;
+ GtkNotebook *notebook;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GList *list;
+ gint page;
+
+ icon_view = GTK_ICON_VIEW (window->priv->icon_view);
+ list = gtk_icon_view_get_selected_items (icon_view);
+ if (list == NULL)
+ return;
+
+ model = gtk_icon_view_get_model (icon_view);
+ gtk_tree_model_get_iter (model, &iter, list->data);
+ gtk_tree_model_get (model, &iter, COLUMN_PAGE, &page, -1);
+
+ notebook = GTK_NOTEBOOK (window->priv->notebook);
+ gtk_notebook_set_current_page (notebook, page);
+
+ g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (list);
+
+ gtk_widget_grab_focus (GTK_WIDGET (icon_view));
+}
+
+static void
+preferences_window_dispose (GObject *object)
+{
+ EPreferencesWindowPrivate *priv;
+
+ priv = E_PREFERENCES_WINDOW_GET_PRIVATE (object);
+
+ if (priv->icon_view != NULL) {
+ g_object_unref (priv->icon_view);
+ priv->icon_view = NULL;
+ }
+
+ if (priv->notebook != NULL) {
+ g_object_unref (priv->notebook);
+ priv->notebook = NULL;
+ }
+
+ g_hash_table_remove_all (priv->index);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+preferences_window_finalize (GObject *object)
+{
+ EPreferencesWindowPrivate *priv;
+
+ priv = E_PREFERENCES_WINDOW_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->index);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+preferences_window_show (GtkWidget *widget)
+{
+ EPreferencesWindowPrivate *priv;
+ GtkIconView *icon_view;
+ GtkTreePath *path;
+
+ priv = E_PREFERENCES_WINDOW_GET_PRIVATE (widget);
+
+ icon_view = GTK_ICON_VIEW (priv->icon_view);
+
+ path = gtk_tree_path_new_first ();
+ gtk_icon_view_select_path (icon_view, path);
+ gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
+ gtk_tree_path_free (path);
+
+ gtk_widget_grab_focus (priv->icon_view);
+
+ /* Chain up to parent's show() method. */
+ GTK_WIDGET_CLASS (parent_class)->show (widget);
+}
+
+static void
+preferences_window_class_init (EPreferencesWindowClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EPreferencesWindowPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = preferences_window_dispose;
+ object_class->finalize = preferences_window_finalize;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->show = preferences_window_show;
+}
+
+static void
+preferences_window_init (EPreferencesWindow *window)
+{
+ GtkListStore *store;
+ GtkWidget *container;
+ GtkWidget *hbox;
+ GtkWidget *vbox;
+ GtkWidget *widget;
+ GHashTable *index;
+ const gchar *title;
+
+ index = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) gtk_tree_row_reference_free);
+
+ window->priv = E_PREFERENCES_WINDOW_GET_PRIVATE (window);
+ window->priv->index = index;
+
+ store = gtk_list_store_new (
+ 4, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_INT, G_TYPE_INT);
+ gtk_tree_sortable_set_sort_column_id (
+ GTK_TREE_SORTABLE (store), COLUMN_SORT, GTK_SORT_ASCENDING);
+
+ title = _("Evolution Preferences");
+ gtk_window_set_title (GTK_WINDOW (window), title);
+ gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
+ gtk_container_set_border_width (GTK_CONTAINER (window), 12);
+
+ g_signal_connect (
+ window, "delete-event",
+ G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+
+ widget = gtk_vbox_new (FALSE, 12);
+ gtk_container_add (GTK_CONTAINER (window), widget);
+ gtk_widget_show (widget);
+
+ vbox = widget;
+
+ widget = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ hbox = widget;
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, TRUE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_icon_view_new_with_model (GTK_TREE_MODEL (store));
+ gtk_icon_view_set_columns (GTK_ICON_VIEW (widget), 1);
+ gtk_icon_view_set_text_column (GTK_ICON_VIEW (widget), COLUMN_TEXT);
+ gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (widget), COLUMN_PIXBUF);
+ g_signal_connect_swapped (
+ widget, "selection-changed",
+ G_CALLBACK (preferences_window_selection_changed_cb), window);
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ window->priv->icon_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+ g_object_unref (store);
+
+ 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 (hbox), widget, TRUE, TRUE, 0);
+ window->priv->notebook = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_hbutton_box_new ();
+ gtk_button_box_set_layout (
+ GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_END);
+ gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_HELP);
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (preferences_window_help_clicked_cb), window);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_button_box_set_child_secondary (
+ GTK_BUTTON_BOX (container), widget, TRUE);
+ gtk_widget_show (widget);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (gtk_widget_hide), window);
+ GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_grab_default (widget);
+ gtk_widget_show (widget);
+}
+
+GType
+e_preferences_window_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ const GTypeInfo type_info = {
+ sizeof (EPreferencesWindowClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) preferences_window_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EPreferencesWindow),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) preferences_window_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_WINDOW, "EPreferencesWindow", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_preferences_window_new (void)
+{
+ return g_object_new (E_TYPE_PREFERENCES_WINDOW, NULL);
+}
+
+void
+e_preferences_window_add_page (EPreferencesWindow *window,
+ const gchar *page_name,
+ const gchar *icon_name,
+ const gchar *caption,
+ GtkWidget *widget,
+ gint sort_order)
+{
+ GtkTreeRowReference *reference;
+ GtkIconView *icon_view;
+ GtkNotebook *notebook;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GHashTable *index;
+ GdkPixbuf *pixbuf;
+ GtkTreeIter iter;
+ gint page;
+
+ g_return_if_fail (E_IS_PREFERENCES_WINDOW (window));
+ g_return_if_fail (page_name != NULL);
+ g_return_if_fail (icon_name != NULL);
+ g_return_if_fail (caption != NULL);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ icon_view = GTK_ICON_VIEW (window->priv->icon_view);
+ notebook = GTK_NOTEBOOK (window->priv->notebook);
+
+ page = gtk_notebook_get_n_pages (notebook);
+ model = gtk_icon_view_get_model (icon_view);
+ pixbuf = preferences_window_load_pixbuf (icon_name);
+
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+
+ gtk_list_store_set (
+ GTK_LIST_STORE (model), &iter,
+ COLUMN_TEXT, caption, COLUMN_PIXBUF, pixbuf,
+ COLUMN_PAGE, page, COLUMN_SORT, sort_order, -1);
+
+ index = window->priv->index;
+ path = gtk_tree_model_get_path (model, &iter);
+ reference = gtk_tree_row_reference_new (model, path);
+ g_hash_table_insert (index, g_strdup (page_name), reference);
+ gtk_tree_path_free (path);
+
+ gtk_widget_show (widget);
+ gtk_notebook_append_page (notebook, widget, NULL);
+}
+
+void
+e_preferences_window_show_page (EPreferencesWindow *window,
+ const gchar *page_name)
+{
+ GtkTreeRowReference *reference;
+ GtkIconView *icon_view;
+ GtkTreePath *path;
+
+ g_return_if_fail (E_IS_PREFERENCES_WINDOW (window));
+ g_return_if_fail (page_name != NULL);
+
+ icon_view = GTK_ICON_VIEW (window->priv->icon_view);
+ reference = g_hash_table_lookup (window->priv->index, page_name);
+ g_return_if_fail (reference != NULL);
+
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_icon_view_select_path (icon_view, path);
+ gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.0, 0.0);
+ gtk_tree_path_free (path);
+}
diff --cc widgets/misc/e-preferences-window.h
index 39f2b82,0000000..4944a89
mode 100644,000000..100644
--- a/widgets/misc/e-preferences-window.h
+++ b/widgets/misc/e-preferences-window.h
@@@ -1,74 -1,0 +1,74 @@@
+/*
+ * e-preferences-window.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_PREFERENCES_WINDOW_H
+#define E_PREFERENCES_WINDOW_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_PREFERENCES_WINDOW \
+ (e_preferences_window_get_type ())
+#define E_PREFERENCES_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindow))
+#define E_PREFERENCES_WINDOW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowClass))
+#define E_IS_PREFERENCES_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_PREFERENCES_WINDOW))
+#define E_IS_PREFERENCES_WINDOW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((obj), E_TYPE_PREFERENCES_WINDOW))
+#define E_PREFERENCES_WINDOW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_TYPE \
+ ((obj), E_TYPE_PREFERENCES_WINDOW, EPreferencesWindowClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EPreferencesWindow EPreferencesWindow;
+typedef struct _EPreferencesWindowClass EPreferencesWindowClass;
+typedef struct _EPreferencesWindowPrivate EPreferencesWindowPrivate;
+
+struct _EPreferencesWindow {
+ GtkWindow parent;
+ EPreferencesWindowPrivate *priv;
+};
+
+struct _EPreferencesWindowClass {
+ GtkWindowClass parent_class;
+};
+
+GType e_preferences_window_get_type (void);
+GtkWidget * e_preferences_window_new (void);
+void e_preferences_window_add_page (EPreferencesWindow *window,
+ const gchar *page_name,
+ const gchar *icon_name,
+ const gchar *caption,
+ GtkWidget *widget,
+ gint sort_order);
+void e_preferences_window_show_page (EPreferencesWindow *window,
+ const gchar *page_name);
+
+G_END_DECLS
+
+#endif /* E_PREFERENCES_WINDOW_H */
diff --cc widgets/misc/e-search-bar.c
index 2d1fd5e,2bbbc91..9abc604
--- a/widgets/misc/e-search-bar.c
+++ b/widgets/misc/e-search-bar.c
@@@ -1260,15 -1329,14 +1276,18 @@@ e_search_bar_set_ui_component (ESearchB
}
void
-e_search_bar_set_menu_sensitive (ESearchBar *search_bar, int id, gboolean state)
+e_search_bar_set_search_text (ESearchBar *search_bar,
+ const gchar *text)
{
- char *verb_name;
- char *path;
+ EIconEntry *icon_entry;
+ GtkWidget *entry;
+
+ if (search_bar->lite)
+ return;
+ if (search_bar->lite)
+ return;
+
verb_name = verb_name_from_id (id);
path = g_strconcat ("/commands/", verb_name, NULL);
g_free (verb_name);
diff --cc widgets/misc/e-signature-editor.c
index cc1e9f6,0000000..53cb349
mode 100644,000000..100644
--- a/widgets/misc/e-signature-editor.c
+++ b/widgets/misc/e-signature-editor.c
@@@ -1,503 -1,0 +1,503 @@@
+/*
+ * e-signature-editor.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-signature-editor.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include <e-util/e-error.h>
+#include <e-util/e-signature-utils.h>
+
+#define E_SIGNATURE_EDITOR_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorPrivate))
+
+enum {
+ PROP_0,
+ PROP_SIGNATURE
+};
+
+struct _ESignatureEditorPrivate {
+ GtkActionGroup *action_group;
+ ESignature *signature;
+ GtkWidget *entry;
+ gchar *original_name;
+};
+
+static const gchar *ui =
+"<ui>\n"
+" <menubar name='main-menu'>\n"
+" <placeholder name='pre-edit-menu'>\n"
+" <menu action='file-menu'>\n"
+" <menuitem action='save-and-close'/>\n"
+" <separator/>"
+" <menuitem action='close'/>\n"
+" </menu>\n"
+" </placeholder>\n"
+" </menubar>\n"
+" <toolbar name='main-toolbar'>\n"
+" <placeholder name='pre-main-toolbar'>\n"
+" <toolitem action='save-and-close'/>\n"
+" </placeholder>\n"
+" </toolbar>\n"
+"</ui>";
+
+static gpointer parent_class = NULL;
+
+static void
+handle_error (GError **error)
+{
+ if (*error != NULL) {
+ g_warning ("%s", (*error)->message);
+ g_clear_error (error);
+ }
+}
+
+static void
+action_close_cb (GtkAction *action,
+ ESignatureEditor *editor)
+{
+ gboolean something_changed = FALSE;
+ const gchar *original_name;
+ const gchar *signature_name;
+
+ original_name = editor->priv->original_name;
+ signature_name = gtk_entry_get_text (GTK_ENTRY (editor->priv->entry));
+
+ something_changed |= gtkhtml_editor_has_undo (GTKHTML_EDITOR (editor));
+ something_changed |= (strcmp (signature_name, original_name) != 0);
+
+ if (something_changed) {
+ gint response;
+
+ response = e_error_run (
+ GTK_WINDOW (editor),
+ "mail:ask-signature-changed", NULL);
+ if (response == GTK_RESPONSE_YES) {
+ GtkActionGroup *action_group;
+
+ action_group = editor->priv->action_group;
+ action = gtk_action_group_get_action (
+ action_group, "save-and-close");
+ gtk_action_activate (action);
+ return;
+ } else if (response == GTK_RESPONSE_CANCEL)
+ return;
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (editor));
+}
+
+static void
+action_save_and_close_cb (GtkAction *action,
+ ESignatureEditor *editor)
+{
+ GtkWidget *entry;
+ ESignatureList *signature_list;
+ ESignature *signature;
+ ESignature *same_name;
+ const gchar *filename;
+ gchar *signature_name;
+ gboolean html;
+ GError *error = NULL;
+
+ entry = editor->priv->entry;
+ html = gtkhtml_editor_get_html_mode (GTKHTML_EDITOR (editor));
+
+ if (editor->priv->signature == NULL) {
+ signature = e_signature_new ();
+ signature->name = g_strdup (_("Unnamed"));
+ signature->script = FALSE;
+ signature->html = html;
+
+ /* FIXME Pass a GError and deal with it. */
+ signature->filename = e_create_signature_file (NULL);
+ } else {
+ signature = g_object_ref (editor->priv->signature);
+ signature->html = html;
+ }
+
+ filename = signature->filename;
+ gtkhtml_editor_save (GTKHTML_EDITOR (editor), filename, html, &error);
+
+ if (error != NULL) {
+ e_error_run (
+ GTK_WINDOW (editor),
+ "mail:no-save-signature",
+ error->message, NULL);
+ g_clear_error (&error);
+ return;
+ }
+
+ signature_list = e_get_signature_list ();
+
+ signature_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
+ g_strstrip (signature_name);
+
+ /* Make sure the signature name is not blank. */
+ if (*signature_name == '\0') {
+ e_error_run (
+ GTK_WINDOW (editor),
+ "mail:blank-signature", NULL);
+ gtk_widget_grab_focus (entry);
+ g_free (signature_name);
+ return;
+ }
+
+ /* Don't overwrite an existing signature of the same name.
+ * XXX ESignatureList misuses const. */
+ same_name = (ESignature *) e_signature_list_find (
+ signature_list, E_SIGNATURE_FIND_NAME, signature_name);
+ if (same_name != NULL && strcmp (signature->uid, same_name->uid) != 0) {
+ e_error_run (
+ GTK_WINDOW (editor),
+ "mail:signature-already-exists",
+ signature_name, NULL);
+ gtk_widget_grab_focus (entry);
+ g_free (signature_name);
+ return;
+ }
+
+ g_free (signature->name);
+ signature->name = signature_name;
+
+ if (editor->priv->signature != NULL)
+ e_signature_list_change (signature_list, signature);
+ else
+ e_signature_list_add (signature_list, signature);
+ e_signature_list_save (signature_list);
+
+ gtk_widget_destroy (GTK_WIDGET (editor));
+}
+
+static GtkActionEntry entries[] = {
+
+ { "close",
+ GTK_STOCK_CLOSE,
+ N_("_Close"),
+ "<Control>w",
+ NULL,
+ G_CALLBACK (action_close_cb) },
+
+ { "save-and-close",
+ GTK_STOCK_SAVE,
+ N_("_Save and Close"),
+ "<Control>Return",
+ NULL,
+ G_CALLBACK (action_save_and_close_cb) },
+
+ { "file-menu",
+ NULL,
+ N_("_File"),
+ NULL,
+ NULL,
+ NULL }
+};
+
+static gboolean
+signature_editor_delete_event_cb (ESignatureEditor *editor,
+ GdkEvent *event)
+{
+ GtkActionGroup *action_group;
+ GtkAction *action;
+
+ action_group = editor->priv->action_group;
+ action = gtk_action_group_get_action (action_group, "close");
+ gtk_action_activate (action);
+
+ return TRUE;
+}
+
+static void
+signature_editor_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SIGNATURE:
+ e_signature_editor_set_signature (
+ E_SIGNATURE_EDITOR (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_editor_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SIGNATURE:
+ g_value_set_object (
+ value, e_signature_editor_get_signature (
+ E_SIGNATURE_EDITOR (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_editor_dispose (GObject *object)
+{
+ ESignatureEditorPrivate *priv;
+
+ priv = E_SIGNATURE_EDITOR_GET_PRIVATE (object);
+
+ if (priv->action_group != NULL) {
+ g_object_unref (priv->action_group);
+ priv->action_group = NULL;
+ }
+
+ if (priv->signature != NULL) {
+ g_object_unref (priv->signature);
+ priv->signature = NULL;
+ }
+
+ if (priv->entry != NULL) {
+ g_object_unref (priv->entry);
+ priv->entry = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+signature_editor_finalize (GObject *object)
+{
+ ESignatureEditorPrivate *priv;
+
+ priv = E_SIGNATURE_EDITOR_GET_PRIVATE (object);
+
+ g_free (priv->original_name);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+signature_editor_class_init (ESignatureEditorClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ESignatureEditorPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = signature_editor_set_property;
+ object_class->get_property = signature_editor_get_property;
+ object_class->dispose = signature_editor_dispose;
+ object_class->finalize = signature_editor_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SIGNATURE,
+ g_param_spec_object (
+ "signature",
+ NULL,
+ NULL,
+ E_TYPE_SIGNATURE,
+ G_PARAM_READWRITE));
+}
+
+static void
+signature_editor_init (ESignatureEditor *editor)
+{
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
+ GtkWidget *container;
+ GtkWidget *widget;
+ GtkWidget *vbox;
+ GError *error = NULL;
+
+ editor->priv = E_SIGNATURE_EDITOR_GET_PRIVATE (editor);
+ vbox = GTKHTML_EDITOR (editor)->vbox;
+
+ ui_manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (editor));
+
+ gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
+ handle_error (&error);
+
+ 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), editor);
+ gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
+ editor->priv->action_group = g_object_ref (action_group);
+
+ gtk_ui_manager_ensure_update (ui_manager);
+
+ gtk_window_set_title (GTK_WINDOW (editor), _("Edit Signature"));
+
+ widget = gtk_hbox_new (FALSE, 6);
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
+ gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+ /* Position 2 should be between the main and style toolbars. */
+ gtk_box_reorder_child (GTK_BOX (vbox), widget, 2);
+ gtk_widget_show (widget);
+ container = widget;
+
+ widget = gtk_entry_new ();
+ gtk_box_pack_end (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ editor->priv->entry = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new_with_mnemonic (_("_Signature Name:"));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (widget), editor->priv->entry);
+ gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ g_signal_connect (
+ editor, "delete-event",
+ G_CALLBACK (signature_editor_delete_event_cb), NULL);
+
+ e_signature_editor_set_signature (editor, NULL);
+}
+
+GType
+e_signature_editor_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (ESignatureEditorClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) signature_editor_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ESignatureEditor),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) signature_editor_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTKHTML_TYPE_EDITOR, "ESignatureEditor",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_signature_editor_new (void)
+{
+ return g_object_new (E_TYPE_SIGNATURE_EDITOR, NULL);
+}
+
+ESignature *
+e_signature_editor_get_signature (ESignatureEditor *editor)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_EDITOR (editor), NULL);
+
+ return editor->priv->signature;
+}
+
+void
+e_signature_editor_set_signature (ESignatureEditor *editor,
+ ESignature *signature)
+{
+ const gchar *filename;
+ const gchar *signature_name;
+ gchar *contents;
+ gsize length;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_SIGNATURE_EDITOR (editor));
+
+ if (signature != NULL)
+ g_return_if_fail (E_SIGNATURE (signature));
+
+ if (editor->priv->signature != NULL) {
+ g_object_unref (editor->priv->signature);
+ editor->priv->signature = NULL;
+ }
+
+ if (signature == NULL)
+ goto exit;
+
+ editor->priv->signature = g_object_ref (signature);
+
+ /* Load signature content. */
+
+ filename = signature->filename;
+
+ if (signature->html)
+ g_file_get_contents (filename, &contents, &length, &error);
+ else {
+ gchar *data;
+
+ data = e_read_signature_file (signature, FALSE, &error);
+ if (data != NULL)
+ contents = g_strdup_printf ("<PRE>\n%s", data);
+ else
+ contents = NULL;
+ length = -1;
+ g_free (data);
+ }
+
+ if (error == NULL) {
+ gtkhtml_editor_set_html_mode (
+ GTKHTML_EDITOR (editor), signature->html);
+ gtkhtml_editor_set_text_html (
+ GTKHTML_EDITOR (editor), contents, length);
+ g_free (contents);
+ } else {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+exit:
+ if (signature != NULL)
+ signature_name = signature->name;
+ else
+ signature_name = _("Unnamed");
+
+ /* Set the entry text before we grab focus. */
+ g_free (editor->priv->original_name);
+ editor->priv->original_name = g_strdup (signature_name);
+ gtk_entry_set_text (GTK_ENTRY (editor->priv->entry), signature_name);
+
+ /* Set the focus appropriately. If this is a new signature, draw
+ * the user's attention to the signature name entry. Otherwise go
+ * straight to the editing area. */
+ if (signature == NULL)
+ gtk_widget_grab_focus (editor->priv->entry);
+ else {
+ GtkHTML *html;
+
+ html = gtkhtml_editor_get_html (GTKHTML_EDITOR (editor));
+ gtk_widget_grab_focus (GTK_WIDGET (html));
+ }
+
+ g_object_notify (G_OBJECT (editor), "signature");
+}
diff --cc widgets/misc/e-signature-editor.h
index 9d6c37a,0000000..1e8b88a
mode 100644,000000..100644
--- a/widgets/misc/e-signature-editor.h
+++ b/widgets/misc/e-signature-editor.h
@@@ -1,70 -1,0 +1,70 @@@
+/*
+ * e-signature-editor.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_SIGNATURE_EDITOR_H
+#define E_SIGNATURE_EDITOR_H
+
+#include <gtkhtml-editor.h>
+#include <e-util/e-signature.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SIGNATURE_EDITOR \
+ (e_signature_editor_get_type ())
+#define E_SIGNATURE_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditor))
+#define E_SIGNATURE_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorClass))
+#define E_IS_SIGNATURE_EDITOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SIGNATURE_EDITOR))
+#define E_IS_SIGNATURE_EDITOR_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SIGNATURE_EDITOR))
+#define E_SIGNATURE_EDITOR_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SIGNATURE_EDITOR, ESignatureEditorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESignatureEditor ESignatureEditor;
+typedef struct _ESignatureEditorClass ESignatureEditorClass;
+typedef struct _ESignatureEditorPrivate ESignatureEditorPrivate;
+
+struct _ESignatureEditor {
+ GtkhtmlEditor parent;
+ ESignatureEditorPrivate *priv;
+};
+
+struct _ESignatureEditorClass {
+ GtkhtmlEditorClass parent_class;
+};
+
+GType e_signature_editor_get_type (void);
+GtkWidget * e_signature_editor_new (void);
+ESignature * e_signature_editor_get_signature (ESignatureEditor *editor);
+void e_signature_editor_set_signature (ESignatureEditor *editor,
+ ESignature *signature);
+
+G_END_DECLS
+
+#endif /* E_SIGNATURE_EDITOR_H */
diff --cc widgets/misc/e-signature-manager.c
index a602710,0000000..a70bc1d
mode 100644,000000..100644
--- a/widgets/misc/e-signature-manager.c
+++ b/widgets/misc/e-signature-manager.c
@@@ -1,746 -1,0 +1,746 @@@
+/*
+ * e-signature-manager.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-signature-manager.h"
+
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gdk/gdkkeysyms.h>
+#include "e-util/e-binding.h"
+#include "e-signature-tree-view.h"
+#include "e-signature-script-dialog.h"
+
+#define E_SIGNATURE_MANAGER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerPrivate))
+
+struct _ESignatureManagerPrivate {
+ ESignatureList *signature_list;
+
+ GtkWidget *tree_view;
+ GtkWidget *add_button;
+ GtkWidget *add_script_button;
+ GtkWidget *edit_button;
+ GtkWidget *remove_button;
+
+ guint allow_scripts : 1;
+ guint prefer_html : 1;
+};
+
+enum {
+ PROP_0,
+ PROP_ALLOW_SCRIPTS,
+ PROP_PREFER_HTML,
+ PROP_SIGNATURE_LIST
+};
+
+enum {
+ ADD_SIGNATURE,
+ ADD_SIGNATURE_SCRIPT,
+ EDITOR_CREATED,
+ EDIT_SIGNATURE,
+ REMOVE_SIGNATURE,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+signature_manager_emit_editor_created (ESignatureManager *manager,
+ GtkWidget *editor)
+{
+ g_return_if_fail (E_IS_SIGNATURE_EDITOR (editor));
+
+ g_signal_emit (manager, signals[EDITOR_CREATED], 0, editor);
+}
+
+static gboolean
+signature_manager_key_press_event_cb (ESignatureManager *manager,
+ GdkEventKey *event)
+{
+ if (event->keyval == GDK_Delete) {
+ e_signature_manager_remove_signature (manager);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+signature_manager_run_script_dialog (ESignatureManager *manager,
+ ESignature *signature,
+ const gchar *title)
+{
+ GtkWidget *dialog;
+ GFile *script_file;
+ const gchar *script_name;
+ gboolean success = FALSE;
+ gpointer parent;
+
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ dialog = e_signature_script_dialog_new (parent);
+ gtk_window_set_title (GTK_WINDOW (dialog), title);
+
+ if (signature->filename != NULL && signature->name != NULL) {
+
+ script_file = g_file_new_for_path (signature->filename);
+ script_name = signature->name;
+
+ e_signature_script_dialog_set_script_file (
+ E_SIGNATURE_SCRIPT_DIALOG (dialog), script_file);
+ e_signature_script_dialog_set_script_name (
+ E_SIGNATURE_SCRIPT_DIALOG (dialog), script_name);
+
+ g_object_unref (script_file);
+ }
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
+ goto exit;
+
+ script_file = e_signature_script_dialog_get_script_file (
+ E_SIGNATURE_SCRIPT_DIALOG (dialog));
+ script_name = e_signature_script_dialog_get_script_name (
+ E_SIGNATURE_SCRIPT_DIALOG (dialog));
+
+ g_free (signature->filename);
+ signature->filename = g_file_get_path (script_file);
+
+ g_free (signature->name);
+ signature->name = g_strdup (script_name);
+
+ g_object_unref (script_file);
+
+ success = TRUE;
+
+exit:
+ gtk_widget_destroy (dialog);
+
+ return success;
+}
+
+static void
+signature_manager_selection_changed_cb (ESignatureManager *manager,
+ GtkTreeSelection *selection)
+{
+ ESignatureTreeView *tree_view;
+ ESignature *signature;
+ GtkWidget *edit_button;
+ GtkWidget *remove_button;
+ gboolean sensitive;
+
+ edit_button = manager->priv->edit_button;
+ remove_button = manager->priv->remove_button;
+
+ tree_view = e_signature_manager_get_tree_view (manager);
+ signature = e_signature_tree_view_get_selected (tree_view);
+ sensitive = (signature != NULL);
+
+ gtk_widget_set_sensitive (edit_button, sensitive);
+ gtk_widget_set_sensitive (remove_button, sensitive);
+}
+
+static void
+signature_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ALLOW_SCRIPTS:
+ e_signature_manager_set_allow_scripts (
+ E_SIGNATURE_MANAGER (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_PREFER_HTML:
+ e_signature_manager_set_prefer_html (
+ E_SIGNATURE_MANAGER (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SIGNATURE_LIST:
+ e_signature_manager_set_signature_list (
+ E_SIGNATURE_MANAGER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ALLOW_SCRIPTS:
+ g_value_set_boolean (
+ value,
+ e_signature_manager_get_allow_scripts (
+ E_SIGNATURE_MANAGER (object)));
+ return;
+
+ case PROP_PREFER_HTML:
+ g_value_set_boolean (
+ value,
+ e_signature_manager_get_prefer_html (
+ E_SIGNATURE_MANAGER (object)));
+ return;
+
+ case PROP_SIGNATURE_LIST:
+ g_value_set_object (
+ value,
+ e_signature_manager_get_signature_list (
+ E_SIGNATURE_MANAGER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_manager_dispose (GObject *object)
+{
+ ESignatureManagerPrivate *priv;
+
+ priv = E_SIGNATURE_MANAGER_GET_PRIVATE (object);
+
+ if (priv->signature_list != NULL) {
+ g_object_unref (priv->signature_list);
+ priv->signature_list = NULL;
+ }
+
+ if (priv->tree_view != NULL) {
+ g_object_unref (priv->tree_view);
+ priv->tree_view = NULL;
+ }
+
+ if (priv->add_button != NULL) {
+ g_object_unref (priv->add_button);
+ priv->add_button = NULL;
+ }
+
+ if (priv->add_script_button != NULL) {
+ g_object_unref (priv->add_script_button);
+ priv->add_script_button = NULL;
+ }
+
+ if (priv->edit_button != NULL) {
+ g_object_unref (priv->edit_button);
+ priv->edit_button = NULL;
+ }
+
+ if (priv->remove_button != NULL) {
+ g_object_unref (priv->remove_button);
+ priv->remove_button = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+signature_manager_add_signature (ESignatureManager *manager)
+{
+ ESignatureTreeView *tree_view;
+ GtkWidget *editor;
+
+ tree_view = e_signature_manager_get_tree_view (manager);
+
+ editor = e_signature_editor_new ();
+ gtkhtml_editor_set_html_mode (
+ GTKHTML_EDITOR (editor), manager->priv->prefer_html);
+ signature_manager_emit_editor_created (manager, editor);
+
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+}
+
+static void
+signature_manager_add_signature_script (ESignatureManager *manager)
+{
+ ESignatureTreeView *tree_view;
+ ESignatureList *signature_list;
+ ESignature *signature;
+ const gchar *title;
+
+ title = _("Add Signature Script");
+ tree_view = e_signature_manager_get_tree_view (manager);
+ signature_list = e_signature_manager_get_signature_list (manager);
+
+ signature = e_signature_new ();
+ signature->script = TRUE;
+ signature->html = TRUE;
+
+ if (signature_manager_run_script_dialog (manager, signature, title))
+ e_signature_list_add (signature_list, signature);
+
+ e_signature_list_save (signature_list);
+ g_object_unref (signature);
+
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+}
+
+static void
+signature_manager_editor_created (ESignatureManager *manager,
+ ESignatureEditor *editor)
+{
+ GtkWindowPosition position;
+ gpointer parent;
+
+ position = GTK_WIN_POS_CENTER_ON_PARENT;
+ parent = gtk_widget_get_toplevel (GTK_WIDGET (manager));
+ parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+ gtk_window_set_transient_for (GTK_WINDOW (editor), parent);
+ gtk_window_set_position (GTK_WINDOW (editor), position);
+ gtk_widget_show (GTK_WIDGET (editor));
+}
+
+static void
+signature_manager_edit_signature (ESignatureManager *manager)
+{
+ ESignatureTreeView *tree_view;
+ ESignatureList *signature_list;
+ ESignature *signature;
+ GtkWidget *editor;
+ const gchar *title;
+ gchar *filename;
+
+ tree_view = e_signature_manager_get_tree_view (manager);
+ signature = e_signature_tree_view_get_selected (tree_view);
+ signature_list = e_signature_manager_get_signature_list (manager);
+
+ if (signature == NULL)
+ return;
+
+ if (signature->script)
+ goto script;
+
+ filename = signature->filename;
+ if (filename == NULL || *filename == '\0') {
+ g_free (filename);
+ filename = g_strdup (_("Unnamed"));
+ signature->filename = filename;
+ }
+
+ editor = e_signature_editor_new ();
+ e_signature_editor_set_signature (
+ E_SIGNATURE_EDITOR (editor), signature);
+ signature_manager_emit_editor_created (manager, editor);
+
+ goto exit;
+
+script:
+ title = _("Edit Signature Script");
+
+ if (signature_manager_run_script_dialog (manager, signature, title))
+ e_signature_list_change (signature_list, signature);
+
+ e_signature_list_save (signature_list);
+
+exit:
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+
+ g_object_unref (signature);
+}
+
+static void
+signature_manager_remove_signature (ESignatureManager *manager)
+{
+ ESignatureTreeView *tree_view;
+ ESignatureList *signature_list;
+ ESignature *signature;
+
+ tree_view = e_signature_manager_get_tree_view (manager);
+ signature = e_signature_tree_view_get_selected (tree_view);
+ signature_list = e_signature_tree_view_get_signature_list (tree_view);
+
+ if (signature == NULL)
+ return;
+
+ if (signature->filename != NULL && !signature->script)
+ g_unlink (signature->filename);
+
+ e_signature_list_remove (signature_list, signature);
+ e_signature_list_save (signature_list);
+
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+}
+
+static void
+signature_manager_class_init (ESignatureManagerClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ESignatureManagerPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = signature_manager_set_property;
+ object_class->get_property = signature_manager_get_property;
+ object_class->dispose = signature_manager_dispose;
+
+ class->add_signature = signature_manager_add_signature;
+ class->add_signature_script = signature_manager_add_signature_script;
+ class->editor_created = signature_manager_editor_created;
+ class->edit_signature = signature_manager_edit_signature;
+ class->remove_signature = signature_manager_remove_signature;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ALLOW_SCRIPTS,
+ g_param_spec_boolean (
+ "allow-scripts",
+ "Allow Scripts",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_PREFER_HTML,
+ g_param_spec_boolean (
+ "prefer-html",
+ "Prefer HTML",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SIGNATURE_LIST,
+ g_param_spec_object (
+ "signature-list",
+ "Signature List",
+ NULL,
+ E_TYPE_SIGNATURE_LIST,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ signals[ADD_SIGNATURE] = g_signal_new (
+ "add-signature",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ESignatureManagerClass, add_signature),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[ADD_SIGNATURE_SCRIPT] = g_signal_new (
+ "add-signature-script",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ESignatureManagerClass, add_signature_script),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[EDITOR_CREATED] = g_signal_new (
+ "editor-created",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ESignatureManagerClass, editor_created),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ E_TYPE_SIGNATURE_EDITOR);
+
+ signals[EDIT_SIGNATURE] = g_signal_new (
+ "edit-signature",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ESignatureManagerClass, edit_signature),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[REMOVE_SIGNATURE] = g_signal_new (
+ "remove-signature",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ESignatureManagerClass, remove_signature),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+signature_manager_init (ESignatureManager *manager)
+{
+ GtkTreeSelection *selection;
+ GtkWidget *container;
+ GtkWidget *widget;
+
+ manager->priv = E_SIGNATURE_MANAGER_GET_PRIVATE (manager);
+
+ gtk_table_resize (GTK_TABLE (manager), 1, 2);
+ gtk_table_set_col_spacings (GTK_TABLE (manager), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (manager), 12);
+
+ container = GTK_WIDGET (manager);
+
+ widget = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (
+ GTK_SCROLLED_WINDOW (widget),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (
+ GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+ gtk_table_attach (
+ GTK_TABLE (container), widget, 0, 1, 0, 1,
+ GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = e_signature_tree_view_new ();
+ gtk_container_add (GTK_CONTAINER (container), widget);
+ manager->priv->tree_view = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ e_mutual_binding_new (
+ G_OBJECT (manager), "signature-list",
+ G_OBJECT (widget), "signature-list");
+
+ g_signal_connect_swapped (
+ widget, "key-press-event",
+ G_CALLBACK (signature_manager_key_press_event_cb),
+ manager);
+
+ g_signal_connect_swapped (
+ widget, "row-activated",
+ G_CALLBACK (e_signature_manager_edit_signature),
+ manager);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (signature_manager_selection_changed_cb),
+ manager);
+
+ container = GTK_WIDGET (manager);
+
+ widget = gtk_vbutton_box_new ();
+ gtk_button_box_set_layout (
+ GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
+ gtk_box_set_spacing (GTK_BOX (widget), 6);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 0, 2, 0, GTK_FILL, 0, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_ADD);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->add_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_signature_manager_add_signature),
+ manager);
+
+ widget = gtk_button_new_with_mnemonic (_("Add _Script"));
+ gtk_button_set_image (
+ GTK_BUTTON (widget), gtk_image_new_from_stock (
+ GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON));
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->add_script_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ e_binding_new (
+ G_OBJECT (manager), "allow-scripts",
+ G_OBJECT (widget), "sensitive");
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_signature_manager_add_signature_script),
+ manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_EDIT);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->edit_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_signature_manager_edit_signature),
+ manager);
+
+ widget = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+ gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+ manager->priv->remove_button = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ g_signal_connect_swapped (
+ widget, "clicked",
+ G_CALLBACK (e_signature_manager_remove_signature),
+ manager);
+}
+
+GType
+e_signature_manager_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (ESignatureManagerClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) signature_manager_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_init */
+ sizeof (ESignatureManager),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) signature_manager_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_TABLE, "ESignatureManager", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_signature_manager_new (ESignatureList *signature_list)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_LIST (signature_list), NULL);
+
+ return g_object_new (
+ E_TYPE_SIGNATURE_MANAGER,
+ "signature-list", signature_list, NULL);
+}
+
+void
+e_signature_manager_add_signature (ESignatureManager *manager)
+{
+ g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
+
+ g_signal_emit (manager, signals[ADD_SIGNATURE], 0);
+}
+
+void
+e_signature_manager_add_signature_script (ESignatureManager *manager)
+{
+ g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
+
+ g_signal_emit (manager, signals[ADD_SIGNATURE_SCRIPT], 0);
+}
+
+void
+e_signature_manager_edit_signature (ESignatureManager *manager)
+{
+ g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
+
+ g_signal_emit (manager, signals[EDIT_SIGNATURE], 0);
+}
+
+void
+e_signature_manager_remove_signature (ESignatureManager *manager)
+{
+ g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
+
+ g_signal_emit (manager, signals[REMOVE_SIGNATURE], 0);
+}
+
+gboolean
+e_signature_manager_get_allow_scripts (ESignatureManager *manager)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), FALSE);
+
+ return manager->priv->allow_scripts;
+}
+
+void
+e_signature_manager_set_allow_scripts (ESignatureManager *manager,
+ gboolean allow_scripts)
+{
+ g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
+
+ manager->priv->allow_scripts = allow_scripts;
+
+ g_object_notify (G_OBJECT (manager), "allow-scripts");
+}
+
+gboolean
+e_signature_manager_get_prefer_html (ESignatureManager *manager)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), FALSE);
+
+ return manager->priv->prefer_html;
+}
+
+void
+e_signature_manager_set_prefer_html (ESignatureManager *manager,
+ gboolean prefer_html)
+{
+ g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
+
+ manager->priv->prefer_html = prefer_html;
+
+ g_object_notify (G_OBJECT (manager), "prefer-html");
+}
+
+ESignatureList *
+e_signature_manager_get_signature_list (ESignatureManager *manager)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), NULL);
+
+ return manager->priv->signature_list;
+}
+
+void
+e_signature_manager_set_signature_list (ESignatureManager *manager,
+ ESignatureList *signature_list)
+{
+ g_return_if_fail (E_IS_SIGNATURE_MANAGER (manager));
+
+ if (signature_list != NULL) {
+ g_return_if_fail (E_IS_SIGNATURE_LIST (signature_list));
+ g_object_ref (signature_list);
+ }
+
+ if (manager->priv->signature_list != NULL)
+ g_object_unref (manager->priv->signature_list);
+
+ manager->priv->signature_list = signature_list;
+
+ g_object_notify (G_OBJECT (manager), "signature-list");
+}
+
+ESignatureTreeView *
+e_signature_manager_get_tree_view (ESignatureManager *manager)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_MANAGER (manager), NULL);
+
+ return E_SIGNATURE_TREE_VIEW (manager->priv->tree_view);
+}
diff --cc widgets/misc/e-signature-manager.h
index f00ad14,0000000..662836e
mode 100644,000000..100644
--- a/widgets/misc/e-signature-manager.h
+++ b/widgets/misc/e-signature-manager.h
@@@ -1,100 -1,0 +1,100 @@@
+/*
+ * e-signature-manager.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_SIGNATURE_MANAGER_H
+#define E_SIGNATURE_MANAGER_H
+
+#include <gtk/gtk.h>
+#include <e-util/e-signature-list.h>
+#include <misc/e-signature-editor.h>
+#include <misc/e-signature-tree-view.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SIGNATURE_MANAGER \
+ (e_signature_manager_get_type ())
+#define E_SIGNATURE_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManager))
+#define E_SIGNATURE_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerClass))
+#define E_IS_SIGNATURE_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SIGNATURE_MANAGER))
+#define E_IS_SIGNATURE_MANAGER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SIGNATURE_MANAGER))
+#define E_SIGNATURE_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SIGNATURE_MANAGER, ESignatureManagerClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESignatureManager ESignatureManager;
+typedef struct _ESignatureManagerClass ESignatureManagerClass;
+typedef struct _ESignatureManagerPrivate ESignatureManagerPrivate;
+
+struct _ESignatureManager {
+ GtkTable parent;
+ ESignatureManagerPrivate *priv;
+};
+
+struct _ESignatureManagerClass {
+ GtkTableClass parent_class;
+
+ void (*add_signature) (ESignatureManager *manager);
+ void (*add_signature_script) (ESignatureManager *manager);
+ void (*editor_created) (ESignatureManager *manager,
+ ESignatureEditor *editor);
+ void (*edit_signature) (ESignatureManager *manager);
+ void (*remove_signature) (ESignatureManager *manager);
+};
+
+GType e_signature_manager_get_type (void);
+GtkWidget * e_signature_manager_new (ESignatureList *signature_list);
+void e_signature_manager_add_signature
+ (ESignatureManager *manager);
+void e_signature_manager_add_signature_script
+ (ESignatureManager *manager);
+void e_signature_manager_edit_signature
+ (ESignatureManager *manager);
+void e_signature_manager_remove_signature
+ (ESignatureManager *manager);
+gboolean e_signature_manager_get_allow_scripts
+ (ESignatureManager *manager);
+void e_signature_manager_set_allow_scripts
+ (ESignatureManager *manager,
+ gboolean allow_scripts);
+gboolean e_signature_manager_get_prefer_html
+ (ESignatureManager *manager);
+void e_signature_manager_set_prefer_html
+ (ESignatureManager *manager,
+ gboolean prefer_html);
+ESignatureList *e_signature_manager_get_signature_list
+ (ESignatureManager *manager);
+void e_signature_manager_set_signature_list
+ (ESignatureManager *manager,
+ ESignatureList *signature_list);
+ESignatureTreeView *
+ e_signature_manager_get_tree_view
+ (ESignatureManager *manager);
+
+#endif /* E_SIGNATURE_MANAGER_H */
diff --cc widgets/misc/e-signature-preview.c
index d618e05,0000000..f8e168c
mode 100644,000000..100644
--- a/widgets/misc/e-signature-preview.c
+++ b/widgets/misc/e-signature-preview.c
@@@ -1,344 -1,0 +1,344 @@@
+/*
+ * e-signature-preview.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-signature-preview.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib/gstdio.h>
+#include "e-util/e-signature-utils.h"
+
+#define E_SIGNATURE_PREVIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreviewPrivate))
+
+enum {
+ PROP_0,
+ PROP_ALLOW_SCRIPTS,
+ PROP_SIGNATURE
+};
+
+enum {
+ REFRESH,
+ LAST_SIGNAL
+};
+
+struct _ESignaturePreviewPrivate {
+ ESignature *signature;
+ guint allow_scripts : 1;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+signature_preview_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ALLOW_SCRIPTS:
+ e_signature_preview_set_allow_scripts (
+ E_SIGNATURE_PREVIEW (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SIGNATURE:
+ e_signature_preview_set_signature (
+ E_SIGNATURE_PREVIEW (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_preview_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ALLOW_SCRIPTS:
+ g_value_set_boolean (
+ value, e_signature_preview_get_allow_scripts (
+ E_SIGNATURE_PREVIEW (object)));
+ return;
+
+ case PROP_SIGNATURE:
+ g_value_set_object (
+ value, e_signature_preview_get_signature (
+ E_SIGNATURE_PREVIEW (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_preview_dispose (GObject *object)
+{
+ ESignaturePreviewPrivate *priv;
+
+ priv = E_SIGNATURE_PREVIEW_GET_PRIVATE (object);
+
+ if (priv->signature != NULL) {
+ g_object_unref (priv->signature);
+ priv->signature = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+signature_preview_url_requested (GtkHTML *html,
+ const gchar *url,
+ GtkHTMLStream *handle)
+{
+ GtkHTMLStreamStatus status;
+ gchar buffer[128];
+ gchar *filename;
+ gssize size;
+ gint fd;
+
+ /* FIXME Use GInputStream for this. */
+
+ if (g_str_has_prefix (url, "file:"))
+ filename = g_filename_from_uri (url, NULL, NULL);
+ else
+ filename = g_strdup (url);
+ fd = g_open (filename, O_RDONLY, 0);
+ g_free (filename);
+
+ status = GTK_HTML_STREAM_OK;
+ if (fd != -1) {
+ while ((size = read (fd, buffer, sizeof (buffer)))) {
+ if (size == -1) {
+ status = GTK_HTML_STREAM_ERROR;
+ break;
+ } else
+ gtk_html_write (html, handle, buffer, size);
+ }
+ } else
+ status = GTK_HTML_STREAM_ERROR;
+
+ gtk_html_end (html, handle, status);
+
+ if (fd > 0)
+ close (fd);
+}
+
+static void
+signature_preview_refresh (ESignaturePreview *preview)
+{
+ GtkHTML *html;
+ ESignature *signature;
+ gchar *content = NULL;
+ gsize length;
+
+ /* XXX We should show error messages in the preview. */
+
+ html = GTK_HTML (preview);
+ signature = e_signature_preview_get_signature (preview);
+
+ if (signature == NULL)
+ goto clear;
+
+ if (signature->script && !preview->priv->allow_scripts)
+ goto clear;
+
+ if (signature->script)
+ content = e_run_signature_script (signature->filename);
+ else
+ content = e_read_signature_file (signature, FALSE, NULL);
+
+ if (content == NULL || *content == '\0')
+ goto clear;
+
+ length = strlen (content);
+
+ if (signature->html)
+ gtk_html_load_from_string (html, content, length);
+ else {
+ GtkHTMLStream *stream;
+
+ stream = gtk_html_begin_content (
+ html, "text/html; charset=utf-8");
+ gtk_html_write (html, stream, "<PRE>", 5);
+ if (length > 0)
+ gtk_html_write (html, stream, content, length);
+ gtk_html_write (html, stream, "</PRE>", 6);
+ gtk_html_end (html, stream, GTK_HTML_STREAM_OK);
+ }
+
+ g_free (content);
+ return;
+
+clear:
+ gtk_html_load_from_string (html, " ", 1);
+ g_free (content);
+}
+
+static void
+signature_preview_class_init (ESignaturePreviewClass *class)
+{
+ GObjectClass *object_class;
+ GtkHTMLClass *html_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ESignaturePreviewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = signature_preview_set_property;
+ object_class->get_property = signature_preview_get_property;
+ object_class->dispose = signature_preview_dispose;
+
+ html_class = GTK_HTML_CLASS (class);
+ html_class->url_requested = signature_preview_url_requested;
+
+ class->refresh = signature_preview_refresh;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ALLOW_SCRIPTS,
+ g_param_spec_boolean (
+ "allow-scripts",
+ "Allow Scripts",
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SIGNATURE,
+ g_param_spec_object (
+ "signature",
+ "Signature",
+ NULL,
+ E_TYPE_SIGNATURE,
+ G_PARAM_READWRITE));
+
+ signals[REFRESH] = g_signal_new (
+ "refresh",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (ESignaturePreviewClass, refresh),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+signature_preview_init (ESignaturePreview *preview)
+{
+ preview->priv = E_SIGNATURE_PREVIEW_GET_PRIVATE (preview);
+}
+
+GType
+e_signature_preview_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (ESignaturePreviewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) signature_preview_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ESignaturePreview),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) signature_preview_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_HTML, "ESignaturePreview", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_signature_preview_new (void)
+{
+ return g_object_new (E_TYPE_SIGNATURE_PREVIEW, NULL);
+}
+
+void
+e_signature_preview_refresh (ESignaturePreview *preview)
+{
+ g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview));
+
+ g_signal_emit (preview, signals[REFRESH], 0);
+}
+
+gboolean
+e_signature_preview_get_allow_scripts (ESignaturePreview *preview)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_PREVIEW (preview), FALSE);
+
+ return preview->priv->allow_scripts;
+}
+
+void
+e_signature_preview_set_allow_scripts (ESignaturePreview *preview,
+ gboolean allow_scripts)
+{
+ g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview));
+
+ preview->priv->allow_scripts = allow_scripts;
+ g_object_notify (G_OBJECT (preview), "allow-scripts");
+}
+
+ESignature *
+e_signature_preview_get_signature (ESignaturePreview *preview)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_PREVIEW (preview), NULL);
+
+ return preview->priv->signature;
+}
+
+void
+e_signature_preview_set_signature (ESignaturePreview *preview,
+ ESignature *signature)
+{
+ g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview));
+
+ if (signature != NULL) {
+ g_return_if_fail (E_IS_SIGNATURE (signature));
+ g_object_ref (signature);
+ }
+
+ if (preview->priv->signature != NULL)
+ g_object_unref (preview->priv->signature);
+
+ preview->priv->signature = signature;
+ g_object_notify (G_OBJECT (preview), "signature");
+
+ e_signature_preview_refresh (preview);
+}
diff --cc widgets/misc/e-signature-preview.h
index 2cedcc1,0000000..a422183
mode 100644,000000..100644
--- a/widgets/misc/e-signature-preview.h
+++ b/widgets/misc/e-signature-preview.h
@@@ -1,81 -1,0 +1,81 @@@
+/*
+ * e-signature-preview.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_SIGNATURE_PREVIEW_H
+#define E_SIGNATURE_PREVIEW_H
+
+#include <gtkhtml/gtkhtml.h>
+#include <e-util/e-signature.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SIGNATURE_PREVIEW \
+ (e_signature_preview_get_type ())
+#define E_SIGNATURE_PREVIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreview))
+#define E_SIGNATURE_PREVIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreviewClass))
+#define E_IS_SIGNATURE_PREVIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SIGNATURE_PREVIEW))
+#define E_IS_SIGNATURE_PREVIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SIGNATURE_PREVIEW))
+#define E_SIGNATURE_PREVIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreview))
+
+G_BEGIN_DECLS
+
+typedef struct _ESignaturePreview ESignaturePreview;
+typedef struct _ESignaturePreviewClass ESignaturePreviewClass;
+typedef struct _ESignaturePreviewPrivate ESignaturePreviewPrivate;
+
+struct _ESignaturePreview {
+ GtkHTML parent;
+ ESignaturePreviewPrivate *priv;
+};
+
+struct _ESignaturePreviewClass {
+ GtkHTMLClass parent_class;
+
+ /* Signals */
+ void (*refresh) (ESignaturePreview *preview);
+};
+
+GType e_signature_preview_get_type (void);
+GtkWidget * e_signature_preview_new (void);
+void e_signature_preview_refresh (ESignaturePreview *preview);
+gboolean e_signature_preview_get_allow_scripts
+ (ESignaturePreview *preview);
+void e_signature_preview_set_allow_scripts
+ (ESignaturePreview *preview,
+ gboolean allow_scripts);
+ESignature * e_signature_preview_get_signature
+ (ESignaturePreview *preview);
+void e_signature_preview_set_signature
+ (ESignaturePreview *preview,
+ ESignature *signature);
+
+G_END_DECLS
+
+#endif /* E_SIGNATURE_PREVIEW_H */
diff --cc widgets/misc/e-signature-script-dialog.c
index 06e021b,0000000..777d064
mode 100644,000000..100644
--- a/widgets/misc/e-signature-script-dialog.c
+++ b/widgets/misc/e-signature-script-dialog.c
@@@ -1,463 -1,0 +1,463 @@@
+/*
+ * e-signature-script-dialog.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-signature-script-dialog.h"
+
+#include <glib/gi18n.h>
+#include "e-util/e-binding.h"
+
+#define E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogPrivate))
+
+struct _ESignatureScriptDialogPrivate {
+ GtkWidget *entry;
+ GtkWidget *file_chooser;
+ GtkWidget *alert;
+};
+
+enum {
+ PROP_0,
+ PROP_SCRIPT_FILE,
+ PROP_SCRIPT_NAME
+};
+
+static gpointer parent_class;
+
+static gboolean
+signature_script_dialog_filter_cb (const GtkFileFilterInfo *filter_info)
+{
+ const gchar *filename = filter_info->filename;
+
+ return g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE);
+}
+
+static void
+signature_script_dialog_update_status (ESignatureScriptDialog *dialog)
+{
+ GFile *script_file;
+ const gchar *script_name;
+ gboolean show_alert;
+ gboolean sensitive;
+
+ script_file = e_signature_script_dialog_get_script_file (dialog);
+ script_name = e_signature_script_dialog_get_script_name (dialog);
+
+ sensitive = (script_name != NULL && *script_name != '\0');
+
+ if (script_file != NULL) {
+ gboolean executable;
+ gchar *filename;
+
+ filename = g_file_get_path (script_file);
+ executable = g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE);
+ g_free (filename);
+
+ show_alert = !executable;
+ sensitive &= executable;
+
+ g_object_unref (script_file);
+ } else {
+ sensitive = FALSE;
+ show_alert = FALSE;
+ }
+
+ if (show_alert)
+ gtk_widget_show (dialog->priv->alert);
+ else
+ gtk_widget_hide (dialog->priv->alert);
+
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
+}
+
+static void
+signature_script_dialog_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SCRIPT_FILE:
+ e_signature_script_dialog_set_script_file (
+ E_SIGNATURE_SCRIPT_DIALOG (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SCRIPT_NAME:
+ e_signature_script_dialog_set_script_name (
+ E_SIGNATURE_SCRIPT_DIALOG (object),
+ g_value_get_string (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_script_dialog_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SCRIPT_FILE:
+ g_value_set_object (
+ value,
+ e_signature_script_dialog_get_script_file (
+ E_SIGNATURE_SCRIPT_DIALOG (object)));
+ return;
+
+ case PROP_SCRIPT_NAME:
+ g_value_set_string (
+ value,
+ e_signature_script_dialog_get_script_name (
+ E_SIGNATURE_SCRIPT_DIALOG (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_script_dialog_dispose (GObject *object)
+{
+ ESignatureScriptDialogPrivate *priv;
+
+ priv = E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (object);
+
+ if (priv->entry != NULL) {
+ g_object_unref (priv->entry);
+ priv->entry = NULL;
+ }
+
+ if (priv->file_chooser != NULL) {
+ g_object_unref (priv->file_chooser);
+ priv->file_chooser = NULL;
+ }
+
+ if (priv->alert != NULL) {
+ g_object_unref (priv->alert);
+ priv->alert = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+signature_script_dialog_map (GtkWidget *widget)
+{
+ GtkWidget *action_area;
+ GtkWidget *content_area;
+
+ /* Chain up to parent's map() method. */
+ GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+ /* XXX Override GtkDialog's broken style property defaults. */
+ action_area = gtk_dialog_get_action_area (GTK_DIALOG (widget));
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (widget));
+
+ gtk_box_set_spacing (GTK_BOX (content_area), 12);
+ gtk_container_set_border_width (GTK_CONTAINER (action_area), 0);
+ gtk_container_set_border_width (GTK_CONTAINER (content_area), 12);
+}
+
+static void
+signature_script_dialog_class_init (ESignatureScriptDialogClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ESignatureScriptDialogPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = signature_script_dialog_set_property;
+ object_class->get_property = signature_script_dialog_get_property;
+ object_class->dispose = signature_script_dialog_dispose;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->map = signature_script_dialog_map;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SCRIPT_FILE,
+ g_param_spec_object (
+ "script-file",
+ "Script File",
+ NULL,
+ G_TYPE_FILE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SCRIPT_NAME,
+ g_param_spec_string (
+ "script-name",
+ "Script Name",
+ NULL,
+ _("Unnamed"),
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+signature_script_dialog_init (ESignatureScriptDialog *dialog)
+{
+ GtkFileFilter *filter;
+ GtkWidget *content_area;
+ GtkWidget *container;
+ GtkWidget *widget;
+ gchar *markup;
+
+ dialog->priv = E_SIGNATURE_SCRIPT_DIALOG_GET_PRIVATE (dialog);
+
+ content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+ gtk_dialog_add_button (
+ GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+ gtk_dialog_add_button (
+ GTK_DIALOG (dialog),
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK);
+
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+ container = content_area;
+
+ widget = gtk_table_new (4, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (widget), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (widget), 6);
+ gtk_table_set_row_spacing (GTK_TABLE (widget), 0, 12);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_image_new_from_stock (
+ GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 1, 0, 1, 0, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new (_(
+ "The output of this script will be used as your\n"
+ "signature. The name you specify will be used\n"
+ "for display purposes only."));
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_entry_new ();
+ gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ dialog->priv->entry = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ widget = gtk_label_new_with_mnemonic (_("_Name:"));
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (widget), dialog->priv->entry);
+ gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_file_chooser_button_new (
+ NULL, GTK_FILE_CHOOSER_ACTION_OPEN);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0);
+ dialog->priv->file_chooser = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Restrict file selection to executable files. */
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_add_custom (
+ filter, GTK_FILE_FILTER_FILENAME,
+ (GtkFileFilterFunc) signature_script_dialog_filter_cb,
+ NULL, NULL);
+ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), filter);
+
+ /* XXX ESignature stores a filename instead of a URI,
+ * so we have to restrict it to local files only. */
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
+
+ widget = gtk_label_new_with_mnemonic (_("S_cript:"));
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (widget), dialog->priv->file_chooser);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 1, 2, 3, GTK_FILL, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ /* This is just a placeholder. */
+ widget = gtk_label_new (NULL);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 0, 1, 3, 4, GTK_FILL, 0, 0, 0);
+ gtk_widget_show (widget);
+
+ widget = gtk_hbox_new (FALSE, 6);
+ gtk_table_attach (
+ GTK_TABLE (container), widget,
+ 1, 2, 3, 4, 0, 0, 0, 0);
+ dialog->priv->alert = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ container = widget;
+
+ widget = gtk_image_new_from_stock (
+ GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_MENU);
+ gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+ gtk_widget_show (widget);
+
+ markup = g_markup_printf_escaped (
+ "<small>%s</small>",
+ _("Script file must be executable."));
+ widget = gtk_label_new (markup);
+ gtk_label_set_use_markup (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);
+ g_free (markup);
+
+ g_signal_connect (
+ dialog, "notify::script-file",
+ G_CALLBACK (signature_script_dialog_update_status), NULL);
+
+ g_signal_connect (
+ dialog, "notify::script-name",
+ G_CALLBACK (signature_script_dialog_update_status), NULL);
+
+ g_signal_connect_swapped (
+ dialog->priv->entry, "changed",
+ G_CALLBACK (signature_script_dialog_update_status), dialog);
+
+ g_signal_connect_swapped (
+ dialog->priv->file_chooser, "file-set",
+ G_CALLBACK (signature_script_dialog_update_status), dialog);
+
+ signature_script_dialog_update_status (dialog);
+}
+
+GType
+e_signature_script_dialog_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (ESignatureScriptDialogClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) signature_script_dialog_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ESignatureScriptDialog),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) signature_script_dialog_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_DIALOG, "ESignatureScriptDialog",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_signature_script_dialog_new (GtkWindow *parent)
+{
+ return g_object_new (
+ E_TYPE_SIGNATURE_SCRIPT_DIALOG,
+ "transient-for", parent, NULL);
+}
+
+GFile *
+e_signature_script_dialog_get_script_file (ESignatureScriptDialog *dialog)
+{
+ GtkFileChooser *file_chooser;
+
+ g_return_val_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog), NULL);
+
+ file_chooser = GTK_FILE_CHOOSER (dialog->priv->file_chooser);
+
+ return gtk_file_chooser_get_file (file_chooser);
+}
+
+void
+e_signature_script_dialog_set_script_file (ESignatureScriptDialog *dialog,
+ GFile *script_file)
+{
+ GtkFileChooser *file_chooser;
+ GError *error = NULL;
+
+ g_return_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog));
+ g_return_if_fail (G_IS_FILE (script_file));
+
+ file_chooser = GTK_FILE_CHOOSER (dialog->priv->file_chooser);
+
+ if (gtk_file_chooser_set_file (file_chooser, script_file, &error))
+ g_object_notify (G_OBJECT (dialog), "script-file");
+ else {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+}
+
+const gchar *
+e_signature_script_dialog_get_script_name (ESignatureScriptDialog *dialog)
+{
+ GtkEntry *entry;
+
+ g_return_val_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog), NULL);
+
+ entry = GTK_ENTRY (dialog->priv->entry);
+
+ return gtk_entry_get_text (entry);
+}
+
+void
+e_signature_script_dialog_set_script_name (ESignatureScriptDialog *dialog,
+ const gchar *script_name)
+{
+ GtkEntry *entry;
+
+ g_return_if_fail (E_IS_SIGNATURE_SCRIPT_DIALOG (dialog));
+
+ if (script_name == NULL)
+ script_name = "";
+
+ entry = GTK_ENTRY (dialog->priv->entry);
+ gtk_entry_set_text (entry, script_name);
+
+ g_object_notify (G_OBJECT (dialog), "script-name");
+}
diff --cc widgets/misc/e-signature-script-dialog.h
index 4cd7f05,0000000..3967ae6
mode 100644,000000..100644
--- a/widgets/misc/e-signature-script-dialog.h
+++ b/widgets/misc/e-signature-script-dialog.h
@@@ -1,76 -1,0 +1,76 @@@
+/*
+ * e-signature-script-dialog.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_SIGNATURE_SCRIPT_DIALOG_H
+#define E_SIGNATURE_SCRIPT_DIALOG_H
+
+#include <gtk/gtk.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SIGNATURE_SCRIPT_DIALOG \
+ (e_signature_script_dialog_get_type ())
+#define E_SIGNATURE_SCRIPT_DIALOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialog))
+#define E_SIGNATURE_SCRIPT_DIALOG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogClass))
+#define E_IS_SIGNATURE_SCRIPT_DIALOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG))
+#define E_IS_SIGNATURE_SCRIPT_DIALOG_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SIGNATURE_SCRIPT_DIALOG))
+#define E_SIGNATURE_SCRIPT_DIALOG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SIGNATURE_SCRIPT_DIALOG, ESignatureScriptDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESignatureScriptDialog ESignatureScriptDialog;
+typedef struct _ESignatureScriptDialogClass ESignatureScriptDialogClass;
+typedef struct _ESignatureScriptDialogPrivate ESignatureScriptDialogPrivate;
+
+struct _ESignatureScriptDialog {
+ GtkDialog parent;
+ ESignatureScriptDialogPrivate *priv;
+};
+
+struct _ESignatureScriptDialogClass {
+ GtkDialogClass parent_class;
+};
+
+GType e_signature_script_dialog_get_type (void);
+GtkWidget * e_signature_script_dialog_new (GtkWindow *parent);
+GFile * e_signature_script_dialog_get_script_file
+ (ESignatureScriptDialog *dialog);
+void e_signature_script_dialog_set_script_file
+ (ESignatureScriptDialog *dialog,
+ GFile *script_file);
+const gchar * e_signature_script_dialog_get_script_name
+ (ESignatureScriptDialog *dialog);
+void e_signature_script_dialog_set_script_name
+ (ESignatureScriptDialog *dialog,
+ const gchar *script_name);
+
+G_END_DECLS
+
+#endif /* E_SIGNATURE_SCRIPT_DIALOG_H */
diff --cc widgets/misc/e-signature-tree-view.c
index 1f6d75b,0000000..b2cc9d6
mode 100644,000000..100644
--- a/widgets/misc/e-signature-tree-view.c
+++ b/widgets/misc/e-signature-tree-view.c
@@@ -1,445 -1,0 +1,445 @@@
+/*
+ * e-signature-tree-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-signature-tree-view.h"
+
+#define E_SIGNATURE_TREE_VIEW_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewPrivate))
+
+enum {
+ COLUMN_STRING,
+ COLUMN_SIGNATURE
+};
+
+enum {
+ PROP_0,
+ PROP_SELECTED,
+ PROP_SIGNATURE_LIST
+};
+
+enum {
+ REFRESHED,
+ LAST_SIGNAL
+};
+
+struct _ESignatureTreeViewPrivate {
+ ESignatureList *signature_list;
+ GHashTable *index;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+signature_tree_view_refresh_cb (ESignatureList *signature_list,
+ ESignature *unused,
+ ESignatureTreeView *tree_view)
+{
+ GtkListStore *store;
+ GtkTreeModel *model;
+ GtkTreeIter tree_iter;
+ EIterator *signature_iter;
+ ESignature *signature;
+ GHashTable *index;
+ GList *list = NULL;
+ GList *iter;
+
+ store = gtk_list_store_new (2, G_TYPE_STRING, E_TYPE_SIGNATURE);
+ model = GTK_TREE_MODEL (store);
+ index = tree_view->priv->index;
+
+ g_hash_table_remove_all (index);
+
+ if (signature_list == NULL)
+ goto skip;
+
+ /* Build a list of ESignatures to display. */
+ signature_iter = e_list_get_iterator (E_LIST (signature_list));
+ while (e_iterator_is_valid (signature_iter)) {
+
+ /* XXX EIterator misuses const. */
+ signature = (ESignature *) e_iterator_get (signature_iter);
+ list = g_list_prepend (list, signature);
+ e_iterator_next (signature_iter);
+ }
+ g_object_unref (signature_iter);
+
+ list = g_list_reverse (list);
+
+ /* Populate the list store and index. */
+ for (iter = list; iter != NULL; iter = iter->next) {
+ GtkTreeRowReference *reference;
+ GtkTreePath *path;
+
+ signature = iter->data;
+
+ /* Skip autogenerated signatures. */
+ if (signature->autogen)
+ continue;
+
+ gtk_list_store_append (store, &tree_iter);
+ gtk_list_store_set (
+ store, &tree_iter,
+ COLUMN_STRING, signature->name,
+ COLUMN_SIGNATURE, signature, -1);
+
+ path = gtk_tree_model_get_path (model, &tree_iter);
+ reference = gtk_tree_row_reference_new (model, path);
+ g_hash_table_insert (index, signature, reference);
+ gtk_tree_path_free (path);
+ }
+
+skip:
+ /* Restore the previously selected signature. */
+ signature = e_signature_tree_view_get_selected (tree_view);
+ if (signature != NULL)
+ g_object_ref (signature);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
+ e_signature_tree_view_set_selected (tree_view, signature);
+ if (signature != NULL)
+ g_object_unref (signature);
+
+ g_signal_emit (tree_view, signals[REFRESHED], 0);
+}
+
+static void
+signature_tree_view_selection_changed_cb (ESignatureTreeView *tree_view)
+{
+ g_object_notify (G_OBJECT (tree_view), "selected");
+}
+
+static GObject *
+signature_tree_view_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ GtkTreeView *tree_view;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ /* Chain up to parent's constructor() method. */
+ object = G_OBJECT_CLASS (parent_class)->constructor (
+ type, n_construct_properties, construct_properties);
+
+ tree_view = GTK_TREE_VIEW (object);
+ gtk_tree_view_set_headers_visible (tree_view, FALSE);
+
+ column = gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_add_attribute (
+ column, renderer, "text", COLUMN_STRING);
+ gtk_tree_view_append_column (tree_view, column);
+
+ return object;
+}
+
+static void
+signature_tree_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SELECTED:
+ e_signature_tree_view_set_selected (
+ E_SIGNATURE_TREE_VIEW (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SIGNATURE_LIST:
+ e_signature_tree_view_set_signature_list (
+ E_SIGNATURE_TREE_VIEW (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_tree_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SELECTED:
+ g_value_set_object (
+ value,
+ e_signature_tree_view_get_selected (
+ E_SIGNATURE_TREE_VIEW (object)));
+ return;
+
+ case PROP_SIGNATURE_LIST:
+ g_value_set_object (
+ value,
+ e_signature_tree_view_get_signature_list (
+ E_SIGNATURE_TREE_VIEW (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+signature_tree_view_dispose (GObject *object)
+{
+ ESignatureTreeViewPrivate *priv;
+
+ priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (object);
+
+ if (priv->signature_list != NULL) {
+ g_signal_handlers_disconnect_by_func (
+ priv->signature_list,
+ signature_tree_view_refresh_cb, object);
+ g_object_unref (priv->signature_list);
+ priv->signature_list = NULL;
+ }
+
+ g_hash_table_remove_all (priv->index);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+signature_tree_view_finalize (GObject *object)
+{
+ ESignatureTreeViewPrivate *priv;
+
+ priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->index);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+signature_tree_view_class_init (ESignatureTreeViewClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ESignatureTreeViewPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = signature_tree_view_constructor;
+ object_class->set_property = signature_tree_view_set_property;
+ object_class->get_property = signature_tree_view_get_property;
+ object_class->dispose = signature_tree_view_dispose;
+ object_class->finalize = signature_tree_view_finalize;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SELECTED,
+ g_param_spec_object (
+ "selected",
+ "Selected Signature",
+ NULL,
+ E_TYPE_SIGNATURE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SIGNATURE_LIST,
+ g_param_spec_object (
+ "signature-list",
+ "Signature List",
+ NULL,
+ E_TYPE_SIGNATURE_LIST,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ signals[REFRESHED] = g_signal_new (
+ "refreshed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+signature_tree_view_init (ESignatureTreeView *tree_view)
+{
+ GHashTable *index;
+ GtkTreeSelection *selection;
+
+ /* Reverse-lookup index */
+ index = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) gtk_tree_row_reference_free);
+
+ tree_view->priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (tree_view);
+ tree_view->priv->index = index;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ g_signal_connect_swapped (
+ selection, "changed",
+ G_CALLBACK (signature_tree_view_selection_changed_cb),
+ tree_view);
+}
+
+GType
+e_signature_tree_view_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (ESignatureTreeViewClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) signature_tree_view_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ESignatureTreeView),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) signature_tree_view_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_TREE_VIEW, "ESignatureTreeView",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_signature_tree_view_new (void)
+{
+ return g_object_new (E_TYPE_SIGNATURE_TREE_VIEW, NULL);
+}
+
+ESignatureList *
+e_signature_tree_view_get_signature_list (ESignatureTreeView *tree_view)
+{
+ g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), NULL);
+
+ return tree_view->priv->signature_list;
+}
+
+void
+e_signature_tree_view_set_signature_list (ESignatureTreeView *tree_view,
+ ESignatureList *signature_list)
+{
+ ESignatureTreeViewPrivate *priv;
+
+ g_return_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view));
+
+ if (signature_list != NULL)
+ g_return_if_fail (E_IS_SIGNATURE_LIST (signature_list));
+
+ priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (tree_view);
+
+ if (priv->signature_list != NULL) {
+ g_signal_handlers_disconnect_by_func (
+ priv->signature_list,
+ signature_tree_view_refresh_cb, tree_view);
+ g_object_unref (priv->signature_list);
+ priv->signature_list = NULL;
+ }
+
+ if (signature_list != NULL) {
+ priv->signature_list = g_object_ref (signature_list);
+
+ /* Listen for changes to the signature list. */
+ g_signal_connect (
+ priv->signature_list, "signature-added",
+ G_CALLBACK (signature_tree_view_refresh_cb),
+ tree_view);
+ g_signal_connect (
+ priv->signature_list, "signature-changed",
+ G_CALLBACK (signature_tree_view_refresh_cb),
+ tree_view);
+ g_signal_connect (
+ priv->signature_list, "signature-removed",
+ G_CALLBACK (signature_tree_view_refresh_cb),
+ tree_view);
+ }
+
+ signature_tree_view_refresh_cb (signature_list, NULL, tree_view);
+
+ g_object_notify (G_OBJECT (tree_view), "signature-list");
+}
+
+ESignature *
+e_signature_tree_view_get_selected (ESignatureTreeView *tree_view)
+{
+ ESignature *signature;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), NULL);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return NULL;
+
+ gtk_tree_model_get (model, &iter, COLUMN_SIGNATURE, &signature, -1);
+
+ return signature;
+}
+
+gboolean
+e_signature_tree_view_set_selected (ESignatureTreeView *tree_view,
+ ESignature *signature)
+{
+ GtkTreeRowReference *reference;
+ GtkTreeSelection *selection;
+ GtkTreePath *path;
+
+ g_return_val_if_fail (E_IS_SIGNATURE_TREE_VIEW (tree_view), FALSE);
+
+ if (signature != NULL)
+ g_return_val_if_fail (E_IS_SIGNATURE (signature), FALSE);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ /* NULL means clear the selection. */
+ if (signature == NULL) {
+ gtk_tree_selection_unselect_all (selection);
+ return TRUE;
+ }
+
+ /* Lookup the tree row reference for the signature. */
+ reference = g_hash_table_lookup (tree_view->priv->index, signature);
+ if (reference == NULL)
+ return FALSE;
+
+ /* Select the referenced path. */
+ path = gtk_tree_row_reference_get_path (reference);
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+
+ g_object_notify (G_OBJECT (tree_view), "selected");
+
+ return TRUE;
+}
diff --cc widgets/misc/e-signature-tree-view.h
index 3afe569,0000000..50d1e11
mode 100644,000000..100644
--- a/widgets/misc/e-signature-tree-view.h
+++ b/widgets/misc/e-signature-tree-view.h
@@@ -1,78 -1,0 +1,78 @@@
+/*
+ * e-signature-tree-view.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_SIGNATURE_TREE_VIEW_H
+#define E_SIGNATURE_TREE_VIEW_H
+
+#include <gtk/gtk.h>
+#include <e-util/e-signature.h>
+#include <e-util/e-signature-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SIGNATURE_TREE_VIEW \
+ (e_signature_tree_view_get_type ())
+#define E_SIGNATURE_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeView))
+#define E_SIGNATURE_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewClass))
+#define E_IS_SIGNATURE_TREE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SIGNATURE_TREE_VIEW))
+#define E_IS_SIGNATURE_TREE_VIEW_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SIGNATURE_TREE_VIEW))
+#define E_SIGNATURE_TREE_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SIGNATURE_TREE_VIEW, ESignatureTreeViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESignatureTreeView ESignatureTreeView;
+typedef struct _ESignatureTreeViewClass ESignatureTreeViewClass;
+typedef struct _ESignatureTreeViewPrivate ESignatureTreeViewPrivate;
+
+struct _ESignatureTreeView {
+ GtkTreeView parent;
+ ESignatureTreeViewPrivate *priv;
+};
+
+struct _ESignatureTreeViewClass {
+ GtkTreeViewClass parent_class;
+};
+
+GType e_signature_tree_view_get_type (void);
+GtkWidget * e_signature_tree_view_new (void);
+ESignatureList *e_signature_tree_view_get_signature_list
+ (ESignatureTreeView *tree_view);
+void e_signature_tree_view_set_signature_list
+ (ESignatureTreeView *tree_view,
+ ESignatureList *signature_list);
+ESignature * e_signature_tree_view_get_selected
+ (ESignatureTreeView *tree_view);
+gboolean e_signature_tree_view_set_selected
+ (ESignatureTreeView *tree_view,
+ ESignature *signature);
+
+G_END_DECLS
+
+#endif /* E_SIGNATURE_TREE_VIEW_H */
diff --cc widgets/misc/e-timeout-activity.c
index 878d6b8,0000000..aa57960
mode 100644,000000..100644
--- a/widgets/misc/e-timeout-activity.c
+++ b/widgets/misc/e-timeout-activity.c
@@@ -1,198 -1,0 +1,198 @@@
+/*
+ * e-timeout-activity.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-timeout-activity.h"
+
+#include <stdarg.h>
+
+#define E_TIMEOUT_ACTIVITY_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityPrivate))
+
+struct _ETimeoutActivityPrivate {
+ guint timeout_id;
+};
+
+enum {
+ TIMEOUT,
+ LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static gulong signals[LAST_SIGNAL];
+
+static gboolean
+timeout_activity_cb (ETimeoutActivity *timeout_activity)
+{
+ g_signal_emit (timeout_activity, signals[TIMEOUT], 0);
+
+ return FALSE;
+}
+
+static void
+timeout_activity_finalize (GObject *object)
+{
+ ETimeoutActivityPrivate *priv;
+
+ priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (object);
+
+ if (priv->timeout_id > 0)
+ g_source_remove (priv->timeout_id);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+timeout_activity_cancelled (EActivity *activity)
+{
+ ETimeoutActivityPrivate *priv;
+
+ priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity);
+
+ if (priv->timeout_id > 0) {
+ g_source_remove (priv->timeout_id);
+ priv->timeout_id = 0;
+ }
+
+ /* Chain up to parent's cancelled() method. */
+ E_ACTIVITY_CLASS (parent_class)->cancelled (activity);
+}
+
+static void
+timeout_activity_completed (EActivity *activity)
+{
+ ETimeoutActivityPrivate *priv;
+
+ priv = E_TIMEOUT_ACTIVITY_GET_PRIVATE (activity);
+
+ if (priv->timeout_id > 0) {
+ g_source_remove (priv->timeout_id);
+ priv->timeout_id = 0;
+ }
+
+ /* Chain up to parent's completed() method. */
+ E_ACTIVITY_CLASS (parent_class)->completed (activity);
+}
+
+static void
+timeout_activity_timeout (ETimeoutActivity *timeout_activity)
+{
+ /* Allow subclasses to safely chain up. */
+}
+
+static void
+timeout_activity_class_init (ETimeoutActivityClass *class)
+{
+ GObjectClass *object_class;
+ EActivityClass *activity_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (ETimeoutActivityPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = timeout_activity_finalize;
+
+ activity_class = E_ACTIVITY_CLASS (class);
+ activity_class->cancelled = timeout_activity_cancelled;
+ activity_class->completed = timeout_activity_completed;
+
+ class->timeout = timeout_activity_timeout;
+
+ signals[TIMEOUT] = g_signal_new (
+ "timeout",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (ETimeoutActivityClass, timeout),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+timeout_activity_init (ETimeoutActivity *timeout_activity)
+{
+ timeout_activity->priv =
+ E_TIMEOUT_ACTIVITY_GET_PRIVATE (timeout_activity);
+}
+
+GType
+e_timeout_activity_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (ETimeoutActivityClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) timeout_activity_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (ETimeoutActivity),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) timeout_activity_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_ACTIVITY, "ETimeoutActivity", &type_info, 0);
+ }
+
+ return type;
+}
+
+EActivity *
+e_timeout_activity_new (const gchar *primary_text)
+{
+ return g_object_new (
+ E_TYPE_TIMEOUT_ACTIVITY,
+ "primary-text", primary_text, NULL);
+}
+
+EActivity *
+e_timeout_activity_newv (const gchar *format, ...)
+{
+ EActivity *activity;
+ gchar *primary_text;
+ va_list args;
+
+ va_start (args, format);
+ primary_text = g_strdup_vprintf (format, args);
+ activity = e_timeout_activity_new (primary_text);
+ g_free (primary_text);
+ va_end (args);
+
+ return activity;
+}
+
+void
+e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
+ guint seconds)
+{
+ g_return_if_fail (E_IS_TIMEOUT_ACTIVITY (timeout_activity));
+
+ if (timeout_activity->priv->timeout_id > 0)
+ e_activity_cancel (E_ACTIVITY (timeout_activity));
+
+ timeout_activity->priv->timeout_id = g_timeout_add_seconds (
+ seconds, (GSourceFunc) timeout_activity_cb, timeout_activity);
+}
diff --cc widgets/misc/e-timeout-activity.h
index b395f39,0000000..82dd113
mode 100644,000000..100644
--- a/widgets/misc/e-timeout-activity.h
+++ b/widgets/misc/e-timeout-activity.h
@@@ -1,73 -1,0 +1,73 @@@
+/*
+ * e-timeout-activity.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_TIMEOUT_ACTIVITY_H
+#define E_TIMEOUT_ACTIVITY_H
+
+#include <e-activity.h>
+
+/* Standard GObject macros */
+#define E_TYPE_TIMEOUT_ACTIVITY \
+ (e_timeout_activity_get_type ())
+#define E_TIMEOUT_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivity))
+#define E_TIMEOUT_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass))
+#define E_IS_TIMEOUT_ACTIVITY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_TIMEOUT_ACTIVITY))
+#define E_IS_TIMEOUT_ACTIVITY_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_TIMEOUT_ACTIVITY))
+#define E_TIMEOUT_ACTIVITY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_TIMEOUT_ACTIVITY, ETimeoutActivityClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ETimeoutActivity ETimeoutActivity;
+typedef struct _ETimeoutActivityClass ETimeoutActivityClass;
+typedef struct _ETimeoutActivityPrivate ETimeoutActivityPrivate;
+
+struct _ETimeoutActivity {
+ EActivity parent;
+ ETimeoutActivityPrivate *priv;
+};
+
+struct _ETimeoutActivityClass {
+ EActivityClass parent_class;
+
+ /* Signals */
+ void (*timeout) (ETimeoutActivity *timeout_activity);
+};
+
+GType e_timeout_activity_get_type (void);
+EActivity * e_timeout_activity_new (const gchar *primary_text);
+EActivity * e_timeout_activity_newv (const gchar *format,
+ ...) G_GNUC_PRINTF (1, 2);
+void e_timeout_activity_set_timeout (ETimeoutActivity *timeout_activity,
+ guint seconds);
+
+G_END_DECLS
+
+#endif /* E_TIMEOUT_ACTIVITY_H */
diff --cc widgets/misc/test-preferences-window.c
index bc53f98,0000000..c0f13f5
mode 100644,000000..100644
--- a/widgets/misc/test-preferences-window.c
+++ b/widgets/misc/test-preferences-window.c
@@@ -1,84 -1,0 +1,84 @@@
+/*
+ * test-preferences-window.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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-preferences-window.c"
+
+#include <gtk/gtk.h>
+
+#define NUM_PAGES 10
+
+static void
+add_pages (EPreferencesWindow *preferences_window)
+{
+ int i;
+
+ for (i = 0; i < NUM_PAGES; i ++) {
+ GtkWidget *widget;
+ char *caption;
+ char *page_name;
+
+ caption = g_strdup_printf ("Title of page %d", i);
+ page_name = g_strdup_printf ("page-%d", i);
+
+ widget = gtk_label_new (caption);
+ gtk_widget_show (widget);
+
+ e_preferences_window_add_page (
+ preferences_window, page_name,
+ "gtk-properties", caption, widget, i);
+
+ g_free (caption);
+ g_free (page_name);
+ }
+}
+
+static int
+delete_event_callback (GtkWidget *widget,
+ GdkEventAny *event,
+ void *data)
+{
+ gtk_main_quit ();
+
+ return TRUE;
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkWidget *window;
+
+ gtk_init (&argc, &argv);
+
+ window = e_preferences_window_new ();
+ gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
+
+ g_signal_connect(
+ window, "delete-event",
+ G_CALLBACK (delete_event_callback), NULL);
+
+ add_pages (E_PREFERENCES_WINDOW (window));
+
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}
diff --cc widgets/table/a11y/gal-a11y-e-cell-popup.h
index 4f205c1,0000000..52e0066
mode 100644,000000..100644
--- a/widgets/table/a11y/gal-a11y-e-cell-popup.h
+++ b/widgets/table/a11y/gal-a11y-e-cell-popup.h
@@@ -1,62 -1,0 +1,62 @@@
+/*
+ *
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Yang Wu <yang wu sun com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_CELL_POPUP_H__
+#define __GAL_A11Y_E_CELL_POPUP_H__
+
+#include <glib-object.h>
+#include <table/e-table-item.h>
+#include <table/a11y/gal-a11y-e-cell.h>
+#include <atk/atkgobjectaccessible.h>
+
+#define GAL_A11Y_TYPE_E_CELL_POPUP (gal_a11y_e_cell_popup_get_type ())
+#define GAL_A11Y_E_CELL_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_POPUP, GalA11yECellPopup))
+#define GAL_A11Y_E_CELL_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_POPUP, GalA11yECellPopupClass))
+#define GAL_A11Y_IS_E_CELL_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_POPUP))
+#define GAL_A11Y_IS_E_CELL_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_POPUP))
+
+typedef struct _GalA11yECellPopup GalA11yECellPopup;
+typedef struct _GalA11yECellPopupClass GalA11yECellPopupClass;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yECellPopupPrivate comes right after the parent class structure.
+ **/
+struct _GalA11yECellPopup {
+ GalA11yECell object;
+};
+
+struct _GalA11yECellPopupClass {
+ GalA11yECellClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_cell_popup_get_type (void);
+AtkObject *gal_a11y_e_cell_popup_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+
+#endif /* ! __GAL_A11Y_E_CELL_POPUP_H__ */
diff --cc widgets/table/a11y/gal-a11y-e-cell-text.h
index 208bc67,0000000..32fce87
mode 100644,000000..100644
--- a/widgets/table/a11y/gal-a11y-e-cell-text.h
+++ b/widgets/table/a11y/gal-a11y-e-cell-text.h
@@@ -1,64 -1,0 +1,64 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Christopher James Lahey <clahey ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __GAL_A11Y_E_CELL_TEXT_H__
+#define __GAL_A11Y_E_CELL_TEXT_H__
+
+#include <glib-object.h>
+#include <table/e-table-item.h>
+#include <table/e-cell-text.h>
+#include <table/a11y/gal-a11y-e-cell.h>
+
+#define GAL_A11Y_TYPE_E_CELL_TEXT (gal_a11y_e_cell_text_get_type ())
+#define GAL_A11Y_E_CELL_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellText))
+#define GAL_A11Y_E_CELL_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAL_A11Y_TYPE_E_CELL_TEXT, GalA11yECellTextClass))
+#define GAL_A11Y_IS_E_CELL_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAL_A11Y_TYPE_E_CELL_TEXT))
+#define GAL_A11Y_IS_E_CELL_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAL_A11Y_TYPE_E_CELL_TEXT))
+
+typedef struct _GalA11yECellText GalA11yECellText;
+typedef struct _GalA11yECellTextClass GalA11yECellTextClass;
+typedef struct _GalA11yECellTextPrivate GalA11yECellTextPrivate;
+
+/* This struct should actually be larger as this isn't what we derive from.
+ * The GalA11yECellTextPrivate comes right after the parent class structure.
+ **/
+struct _GalA11yECellText {
+ GalA11yECell object;
+ gint inserted_id;
+ gint deleted_id;
+};
+
+struct _GalA11yECellTextClass {
+ GalA11yECellClass parent_class;
+};
+
+
+/* Standard Glib function */
+GType gal_a11y_e_cell_text_get_type (void);
+AtkObject *gal_a11y_e_cell_text_new (ETableItem *item,
+ ECellView *cell_view,
+ AtkObject *parent,
+ int model_col,
+ int view_col,
+ int row);
+
+#endif /* ! __GAL_A11Y_E_CELL_TEXT_H__ */
diff --cc widgets/table/e-cell-date-edit.c
index 1cf3838,0000000..2bee6f5
mode 100644,000000..100644
--- a/widgets/table/e-cell-date-edit.c
+++ b/widgets/table/e-cell-date-edit.c
@@@ -1,1033 -1,0 +1,1033 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Damon Chaplin <damon ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/*
+ * ECellDateEdit - a subclass of ECellPopup used to show a date with a popup
+ * window to edit it.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cell-date-edit.h"
+
+#include <string.h>
+#include <time.h>
+#include <glib.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "e-table-item.h"
+#include "e-cell-text.h"
+
+#include <glib/gi18n.h>
+
+#include <libedataserver/e-time-utils.h>
+
+/* This depends on ECalendar which is why I didn't put it in gal. */
+#include <misc/e-calendar.h>
+
+static void e_cell_date_edit_destroy (GtkObject *object);
+static void e_cell_date_edit_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void e_cell_date_edit_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+static gint e_cell_date_edit_do_popup (ECellPopup *ecp,
+ GdkEvent *event,
+ int row,
+ int view_col);
+static void e_cell_date_edit_set_popup_values (ECellDateEdit *ecde);
+static void e_cell_date_edit_select_matching_time(ECellDateEdit *ecde,
+ char *time);
+static void e_cell_date_edit_show_popup (ECellDateEdit *ecde,
+ int row,
+ int view_col);
+static void e_cell_date_edit_get_popup_pos (ECellDateEdit *ecde,
+ int row,
+ int view_col,
+ gint *x,
+ gint *y,
+ gint *height,
+ gint *width);
+
+static void e_cell_date_edit_rebuild_time_list (ECellDateEdit *ecde);
+
+static int e_cell_date_edit_key_press (GtkWidget *popup_window,
+ GdkEventKey *event,
+ ECellDateEdit *ecde);
+static int e_cell_date_edit_button_press (GtkWidget *popup_window,
+ GdkEventButton *event,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_on_ok_clicked (GtkWidget *button,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_show_time_invalid_warning (ECellDateEdit *ecde);
+static void e_cell_date_edit_on_now_clicked (GtkWidget *button,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_on_none_clicked (GtkWidget *button,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_on_today_clicked (GtkWidget *button,
+ ECellDateEdit *ecde);
+static void e_cell_date_edit_update_cell (ECellDateEdit *ecde,
- char *text);
++ const gchar *text);
+static void e_cell_date_edit_on_time_selected (GtkTreeSelection *selection, ECellDateEdit *ecde);
+static void e_cell_date_edit_hide_popup (ECellDateEdit *ecde);
+
+
+/* Our arguments. */
+enum {
+ PROP_0,
+ PROP_SHOW_TIME,
+ PROP_SHOW_NOW_BUTTON,
+ PROP_SHOW_TODAY_BUTTON,
+ PROP_ALLOW_NO_DATE_SET,
+ PROP_USE_24_HOUR_FORMAT,
+ PROP_LOWER_HOUR,
+ PROP_UPPER_HOUR
+};
+
+G_DEFINE_TYPE (ECellDateEdit, e_cell_date_edit, E_CELL_POPUP_TYPE)
+
+
+static void
+e_cell_date_edit_class_init (ECellDateEditClass *class)
+{
+ GObjectClass *object_class;
+ GtkObjectClass *gtk_object_class;
+ ECellPopupClass *ecpc;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->get_property = e_cell_date_edit_get_property;
+ object_class->set_property = e_cell_date_edit_set_property;
+
+ gtk_object_class = GTK_OBJECT_CLASS (class);
+ gtk_object_class->destroy = e_cell_date_edit_destroy;
+
+ ecpc = E_CELL_POPUP_CLASS (class);
+ ecpc->popup = e_cell_date_edit_do_popup;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_TIME,
+ g_param_spec_boolean (
+ "show_time",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_NOW_BUTTON,
+ g_param_spec_boolean (
+ "show_now_button",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHOW_TODAY_BUTTON,
+ g_param_spec_boolean (
+ "show_today_button",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ALLOW_NO_DATE_SET,
+ g_param_spec_boolean (
+ "allow_no_date_set",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_USE_24_HOUR_FORMAT,
+ g_param_spec_boolean (
+ "use_24_hour_format",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_LOWER_HOUR,
+ g_param_spec_int (
+ "lower_hour",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_UPPER_HOUR,
+ g_param_spec_int (
+ "upper_hour",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 24,
+ G_PARAM_READWRITE));
+}
+
+
+static void
+e_cell_date_edit_init (ECellDateEdit *ecde)
+{
+ GtkWidget *frame, *vbox, *hbox, *vbox2;
+ GtkWidget *scrolled_window, *bbox, *tree_view;
+ GtkWidget *now_button, *today_button, *none_button, *ok_button;
+ GtkListStore *store;
+
+ ecde->lower_hour = 0;
+ ecde->upper_hour = 24;
+ ecde->use_24_hour_format = TRUE;
+ ecde->need_time_list_rebuild = TRUE;
+ ecde->freeze_count = 0;
+ ecde->time_callback = NULL;
+ ecde->time_callback_data = NULL;
+ ecde->time_callback_destroy = NULL;
+
+ /* We create one popup window for the ECell, since there will only
+ ever be one popup in use at a time. */
+ ecde->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
+
+ gtk_window_set_type_hint (GTK_WINDOW (ecde->popup_window),
+ GDK_WINDOW_TYPE_HINT_COMBO);
+ gtk_window_set_resizable (GTK_WINDOW (ecde->popup_window), TRUE);
+
+ frame = gtk_frame_new (NULL);
+ gtk_container_add (GTK_CONTAINER (ecde->popup_window), frame);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+ gtk_widget_show (frame);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+ gtk_widget_show (vbox);
+
+ hbox = gtk_hbox_new (FALSE, 4);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
+ ecde->calendar = e_calendar_new ();
+ gnome_canvas_item_set (GNOME_CANVAS_ITEM (E_CALENDAR (ecde->calendar)->calitem),
+ "move_selection_when_moving", FALSE,
+ NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), ecde->calendar, TRUE, TRUE, 0);
+ gtk_widget_show (ecde->calendar);
+
+ vbox2 = gtk_vbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
+ gtk_widget_show (vbox2);
+
+ ecde->time_entry = gtk_entry_new ();
+ gtk_widget_set_size_request (ecde->time_entry, 50, -1);
+ gtk_box_pack_start (GTK_BOX (vbox2), ecde->time_entry,
+ FALSE, FALSE, 0);
+ gtk_widget_show (ecde->time_entry);
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_box_pack_start (GTK_BOX (vbox2), scrolled_window, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_ALWAYS);
+ gtk_widget_show (scrolled_window);
+
+ store = gtk_list_store_new (1, G_TYPE_STRING);
+ tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+ g_object_unref (store);
+
+ gtk_tree_view_append_column (
+ GTK_TREE_VIEW (tree_view),
+ gtk_tree_view_column_new_with_attributes ("Text", gtk_cell_renderer_text_new (), "text", 0, NULL));
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
+
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), tree_view);
+ gtk_container_set_focus_vadjustment (GTK_CONTAINER (tree_view),
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
+ gtk_container_set_focus_hadjustment (GTK_CONTAINER (tree_view),
+ gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
+ gtk_widget_show (tree_view);
+ ecde->time_tree_view = tree_view;
+ g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)), "changed",
+ G_CALLBACK (e_cell_date_edit_on_time_selected),
+ ecde);
+
+ bbox = gtk_hbutton_box_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (bbox), 4);
+ gtk_box_set_spacing (GTK_BOX (bbox), 2);
+ gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+ gtk_widget_show (bbox);
+
+ now_button = gtk_button_new_with_label (_("Now"));
+ gtk_container_add (GTK_CONTAINER (bbox), now_button);
+ gtk_widget_show (now_button);
+ g_signal_connect((now_button), "clicked",
+ G_CALLBACK (e_cell_date_edit_on_now_clicked),
+ ecde);
+ ecde->now_button = now_button;
+
+ today_button = gtk_button_new_with_label (_("Today"));
+ gtk_container_add (GTK_CONTAINER (bbox), today_button);
+ gtk_widget_show (today_button);
+ g_signal_connect((today_button), "clicked",
+ G_CALLBACK (e_cell_date_edit_on_today_clicked),
+ ecde);
+ ecde->today_button = today_button;
+
+ none_button = gtk_button_new_with_label (_("None"));
+ gtk_container_add (GTK_CONTAINER (bbox), none_button);
+ gtk_widget_show (none_button);
+ g_signal_connect((none_button), "clicked",
+ G_CALLBACK (e_cell_date_edit_on_none_clicked),
+ ecde);
+ ecde->none_button = none_button;
+
+ ok_button = gtk_button_new_with_label (_("OK"));
+ gtk_container_add (GTK_CONTAINER (bbox), ok_button);
+ gtk_widget_show (ok_button);
+ g_signal_connect((ok_button), "clicked",
+ G_CALLBACK (e_cell_date_edit_on_ok_clicked),
+ ecde);
+
+
+ g_signal_connect((ecde->popup_window),
+ "key_press_event",
+ G_CALLBACK (e_cell_date_edit_key_press),
+ ecde);
+ g_signal_connect((ecde->popup_window),
+ "button_press_event",
+ G_CALLBACK (e_cell_date_edit_button_press),
+ ecde);
+}
+
+
+/**
+ * e_cell_date_edit_new:
+ *
+ * Creates a new ECellDateEdit renderer.
+ *
+ * Returns: an ECellDateEdit object.
+ */
+ECell *
+e_cell_date_edit_new (void)
+{
+ return g_object_new (e_cell_date_edit_get_type (), NULL);
+}
+
+
+/*
+ * GtkObject::destroy method
+ */
+static void
+e_cell_date_edit_destroy (GtkObject *object)
+{
+ ECellDateEdit *ecde = E_CELL_DATE_EDIT (object);
+
+ e_cell_date_edit_set_get_time_callback (ecde, NULL, NULL, NULL);
+
+ gtk_widget_destroy (ecde->popup_window);
+ ecde->popup_window = NULL;
+
+ GTK_OBJECT_CLASS (e_cell_date_edit_parent_class)->destroy (object);
+}
+
+
+static void
+e_cell_date_edit_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ECellDateEdit *ecde;
+
+ ecde = E_CELL_DATE_EDIT (object);
+
+ switch (property_id) {
+ case PROP_SHOW_TIME:
+ g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->time_entry));
+ return;
+ case PROP_SHOW_NOW_BUTTON:
+ g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->now_button));
+ return;
+ case PROP_SHOW_TODAY_BUTTON:
+ g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->today_button));
+ return;
+ case PROP_ALLOW_NO_DATE_SET:
+ g_value_set_boolean (value, GTK_WIDGET_VISIBLE (ecde->none_button));
+ return;
+ case PROP_USE_24_HOUR_FORMAT:
+ g_value_set_boolean (value, ecde->use_24_hour_format);
+ return;
+ case PROP_LOWER_HOUR:
+ g_value_set_int (value, ecde->lower_hour);
+ return;
+ case PROP_UPPER_HOUR:
+ g_value_set_int (value, ecde->upper_hour);
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+
+static void
+e_cell_date_edit_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ECellDateEdit *ecde;
+ gint ivalue;
+ gboolean bvalue;
+
+ ecde = E_CELL_DATE_EDIT (object);
+
+ switch (property_id) {
+ case PROP_SHOW_TIME:
+ if (g_value_get_boolean (value)) {
+ gtk_widget_show (ecde->time_entry);
+ gtk_widget_show (ecde->time_tree_view);
+ } else {
+ gtk_widget_hide (ecde->time_entry);
+ gtk_widget_hide (ecde->time_tree_view);
+ }
+ return;
+ case PROP_SHOW_NOW_BUTTON:
+ if (g_value_get_boolean (value)) {
+ gtk_widget_show (ecde->now_button);
+ } else {
+ gtk_widget_hide (ecde->now_button);
+ }
+ return;
+ case PROP_SHOW_TODAY_BUTTON:
+ if (g_value_get_boolean (value)) {
+ gtk_widget_show (ecde->today_button);
+ } else {
+ gtk_widget_hide (ecde->today_button);
+ }
+ return;
+ case PROP_ALLOW_NO_DATE_SET:
+ if (g_value_get_boolean (value)) {
+ gtk_widget_show (ecde->none_button);
+ } else {
+ /* FIXME: What if we have no date set now. */
+ gtk_widget_hide (ecde->none_button);
+ }
+ return;
+ case PROP_USE_24_HOUR_FORMAT:
+ bvalue = g_value_get_boolean (value);
+ if (ecde->use_24_hour_format != bvalue) {
+ ecde->use_24_hour_format = bvalue;
+ ecde->need_time_list_rebuild = TRUE;
+ }
+ return;
+ case PROP_LOWER_HOUR:
+ ivalue = g_value_get_int (value);
+ ivalue = CLAMP (ivalue, 0, 24);
+ if (ecde->lower_hour != ivalue) {
+ ecde->lower_hour = ivalue;
+ ecde->need_time_list_rebuild = TRUE;
+ }
+ return;
+ case PROP_UPPER_HOUR:
+ ivalue = g_value_get_int (value);
+ ivalue = CLAMP (ivalue, 0, 24);
+ if (ecde->upper_hour != ivalue) {
+ ecde->upper_hour = ivalue;
+ ecde->need_time_list_rebuild = TRUE;
+ }
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+
+static gint
+e_cell_date_edit_do_popup (ECellPopup *ecp,
+ GdkEvent *event,
+ int row,
+ int view_col)
+{
+ ECellDateEdit *ecde = E_CELL_DATE_EDIT (ecp);
+
+ e_cell_date_edit_show_popup (ecde, row, view_col);
+ e_cell_date_edit_set_popup_values (ecde);
+
+ gtk_grab_add (ecde->popup_window);
+
+ /* Set the focus to the first widget. */
+ gtk_widget_grab_focus (ecde->time_entry);
+ gdk_window_focus (ecde->popup_window->window, GDK_CURRENT_TIME);
+
+ return TRUE;
+}
+
+
+static void
+e_cell_date_edit_set_popup_values (ECellDateEdit *ecde)
+{
+ ECellPopup *ecp = E_CELL_POPUP (ecde);
+ ECellText *ecell_text = E_CELL_TEXT (ecp->child);
+ ECellView *ecv = (ECellView*) ecp->popup_cell_view;
+ ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
+ ETableCol *ecol;
+ char *cell_text;
+ ETimeParseStatus status;
+ struct tm date_tm;
+ GDate date;
+ ECalendarItem *calitem;
+ char buffer[64];
+ gboolean is_date = TRUE;
+
+ ecol = e_table_header_get_column (eti->header, ecp->popup_view_col);
+ cell_text = e_cell_text_get_text (ecell_text, ecv->e_table_model,
+ ecol->col_idx, ecp->popup_row);
+
+ /* Try to parse just a date first. If the value is only a date, we
+ use a DATE value. */
+ status = e_time_parse_date (cell_text, &date_tm);
+ if (status == E_TIME_PARSE_INVALID) {
+ is_date = FALSE;
+ status = e_time_parse_date_and_time (cell_text, &date_tm);
+ }
+
+ /* If there is no date and time set, or the date is invalid, we clear
+ the selections, else we select the appropriate date & time. */
+ calitem = E_CALENDAR_ITEM (E_CALENDAR (ecde->calendar)->calitem);
+ if (status == E_TIME_PARSE_NONE || status == E_TIME_PARSE_INVALID) {
+ gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), "");
+ e_calendar_item_set_selection (calitem, NULL, NULL);
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view)));
+ } else {
+ if (is_date) {
+ buffer[0] = '\0';
+ } else {
+ e_time_format_time (&date_tm, ecde->use_24_hour_format,
+ FALSE, buffer, sizeof (buffer));
+ }
+ gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), buffer);
+
+ g_date_clear (&date, 1);
+ g_date_set_dmy (&date, date_tm.tm_mday, date_tm.tm_mon + 1,
+ date_tm.tm_year + 1900);
+ e_calendar_item_set_selection (calitem, &date, &date);
+
+ if (is_date) {
+ gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view)));
+ } else {
+ e_cell_date_edit_select_matching_time (ecde, buffer);
+ }
+ }
+
+ e_cell_text_free_text (ecell_text, cell_text);
+}
+
+
+static void
+e_cell_date_edit_select_matching_time (ECellDateEdit *ecde,
+ char *time)
+{
+ gboolean found = FALSE;
+ gboolean valid;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (ecde->time_tree_view));
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ecde->time_tree_view));
+
+ for (valid = gtk_tree_model_get_iter_first (model, &iter);
+ valid && !found;
+ valid = gtk_tree_model_iter_next (model, &iter)) {
+ char *str = NULL;
+
+ gtk_tree_model_get (model, &iter, 0, &str, -1);
+
+ if (g_str_equal (str, time)) {
+ GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
+
+ gtk_tree_view_set_cursor (GTK_TREE_VIEW (ecde->time_tree_view), path, NULL, FALSE);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (ecde->time_tree_view), path, NULL, FALSE, 0.0, 0.0);
+ gtk_tree_path_free (path);
+
+ found = TRUE;
+ }
+
+ g_free (str);
+ }
+
+ if (!found) {
+ gtk_tree_selection_unselect_all (selection);
+ gtk_tree_view_scroll_to_point (GTK_TREE_VIEW (ecde->time_tree_view), 0, 0);
+ }
+}
+
+
+static void
+e_cell_date_edit_show_popup (ECellDateEdit *ecde,
+ int row,
+ int view_col)
+{
+ gint x, y, width, height;
+
+ if (ecde->need_time_list_rebuild)
+ e_cell_date_edit_rebuild_time_list (ecde);
+
+ /* This code is practically copied from GtkCombo. */
+
+ e_cell_date_edit_get_popup_pos (ecde, row, view_col, &x, &y, &height, &width);
+
+ gtk_window_move (GTK_WINDOW (ecde->popup_window), x, y);
+ gtk_widget_set_size_request (ecde->popup_window, width, height);
+ gtk_widget_realize (ecde->popup_window);
+ gdk_window_resize (ecde->popup_window->window, width, height);
+ gtk_widget_show (ecde->popup_window);
+
+ e_cell_popup_set_shown (E_CELL_POPUP (ecde), TRUE);
+}
+
+
+/* Calculates the size and position of the popup window (like GtkCombo). */
+static void
+e_cell_date_edit_get_popup_pos (ECellDateEdit *ecde,
+ int row,
+ int view_col,
+ gint *x,
+ gint *y,
+ gint *height,
+ gint *width)
+{
+ ECellPopup *ecp = E_CELL_POPUP (ecde);
+ ETableItem *eti = E_TABLE_ITEM (ecp->popup_cell_view->cell_view.e_table_item_view);
+ GtkWidget *canvas = GTK_WIDGET (GNOME_CANVAS_ITEM (eti)->canvas);
+ GtkRequisition popup_requisition;
+ gint avail_height, screen_width, column_width, row_height;
+ double x1, y1, wx, wy;
+
+ gdk_window_get_origin (canvas->window, x, y);
+
+ x1 = e_table_header_col_diff (eti->header, 0, view_col + 1);
+ y1 = e_table_item_row_diff (eti, 0, row + 1);
+ column_width = e_table_header_col_diff (eti->header, view_col,
+ view_col + 1);
+ row_height = e_table_item_row_diff (eti, row,
+ row + 1);
+ gnome_canvas_item_i2w (GNOME_CANVAS_ITEM (eti), &x1, &y1);
+
+ gnome_canvas_world_to_window (GNOME_CANVAS (canvas),
+ x1,
+ y1,
+ &wx,
+ &wy);
+
+ x1 = wx;
+ y1 = wy;
+
+ *x += x1;
+ /* The ETable positions don't include the grid lines, I think, so we
+ add 1. */
+ *y += y1 + 1
+ - (int)((GnomeCanvas *)canvas)->layout.vadjustment->value
+ + ((GnomeCanvas *)canvas)->zoom_yofs;
+
+ avail_height = gdk_screen_height () - *y;
+
+ /* We'll use the entire screen width if needed, but we save space for
+ the vertical scrollbar in case we need to show that. */
+ screen_width = gdk_screen_width ();
+
+ gtk_widget_size_request (ecde->popup_window, &popup_requisition);
+
+ /* Calculate the desired width. */
+ *width = popup_requisition.width;
+
+ /* Use at least the same width as the column. */
+ if (*width < column_width)
+ *width = column_width;
+
+ /* Check if it fits in the available height. */
+ if (popup_requisition.height > avail_height) {
+ /* It doesn't fit, so we see if we have the minimum space
+ needed. */
+ if (*y - row_height > avail_height) {
+ /* We don't, so we show the popup above the cell
+ instead of below it. */
+ avail_height = *y - row_height;
+ *y -= (popup_requisition.height + row_height);
+ if (*y < 0)
+ *y = 0;
+ }
+ }
+
+ /* We try to line it up with the right edge of the column, but we don't
+ want it to go off the edges of the screen. */
+ if (*x > screen_width)
+ *x = screen_width;
+ *x -= *width;
+ if (*x < 0)
+ *x = 0;
+
+ *height = popup_requisition.height;
+}
+
+
+/* This handles key press events in the popup window. If the Escape key is
+ pressed we hide the popup, and do not change the cell contents. */
+static int
+e_cell_date_edit_key_press (GtkWidget *popup_window,
+ GdkEventKey *event,
+ ECellDateEdit *ecde)
+{
+ /* If the Escape key is pressed we hide the popup. */
+ if (event->keyval != GDK_Escape)
+ return FALSE;
+
+ e_cell_date_edit_hide_popup (ecde);
+
+ return TRUE;
+}
+
+
+/* This handles button press events in the popup window. If the button is
+ pressed outside the popup, we hide it and do not change the cell contents.
+*/
+static int
+e_cell_date_edit_button_press (GtkWidget *popup_window,
+ GdkEventButton *event,
+ ECellDateEdit *ecde)
+{
+ GtkWidget *event_widget;
+
+ event_widget = gtk_get_event_widget ((GdkEvent*) event);
+ if (gtk_widget_get_toplevel (event_widget) != popup_window) {
+ e_cell_date_edit_hide_popup (ecde);
+ }
+
+ return TRUE;
+}
+
+
+/* Clears the time list and rebuilds it using the lower_hour, upper_hour
+ and use_24_hour_format settings. */
+static void
+e_cell_date_edit_rebuild_time_list (ECellDateEdit *ecde)
+{
+ GtkListStore *store;
+ char buffer[40];
+ struct tm tmp_tm;
+ gint hour, min;
+
+ store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (ecde->time_tree_view)));
+ gtk_list_store_clear (store);
+
+ /* Fill the struct tm with some sane values. */
+ tmp_tm.tm_year = 2000;
+ tmp_tm.tm_mon = 0;
+ tmp_tm.tm_mday = 1;
+ tmp_tm.tm_sec = 0;
+ tmp_tm.tm_isdst = 0;
+
+ for (hour = ecde->lower_hour; hour <= ecde->upper_hour; hour++) {
+ /* We don't want to display midnight at the end, since that is
+ really in the next day. */
+ if (hour == 24)
+ break;
+
+ /* We want to finish on upper_hour, with min == 0. */
+ for (min = 0;
+ min == 0 || (min < 60 && hour != ecde->upper_hour);
+ min += 30) {
+ GtkTreeIter iter;
+
+ tmp_tm.tm_hour = hour;
+ tmp_tm.tm_min = min;
+ e_time_format_time (&tmp_tm, ecde->use_24_hour_format,
+ FALSE, buffer, sizeof (buffer));
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter, 0, buffer, -1);
+ }
+ }
+
+ ecde->need_time_list_rebuild = FALSE;
+}
+
+
+static void
+e_cell_date_edit_on_ok_clicked (GtkWidget *button,
+ ECellDateEdit *ecde)
+{
+ ECalendarItem *calitem;
+ GDate start_date, end_date;
+ gboolean day_selected;
+ struct tm date_tm;
+ char buffer[64];
+ const char *text;
+ ETimeParseStatus status;
+ gboolean is_date = FALSE;
+
+ calitem = E_CALENDAR_ITEM (E_CALENDAR (ecde->calendar)->calitem);
+ day_selected = e_calendar_item_get_selection (calitem, &start_date,
+ &end_date);
+
+ text = gtk_entry_get_text (GTK_ENTRY (ecde->time_entry));
+ status = e_time_parse_time (text, &date_tm);
+ if (status == E_TIME_PARSE_INVALID) {
+ e_cell_date_edit_show_time_invalid_warning (ecde);
+ return;
+ } else if (status == E_TIME_PARSE_NONE) {
+ is_date = TRUE;
+ }
+
+ if (day_selected) {
+ date_tm.tm_year = g_date_get_year (&start_date) - 1900;
+ date_tm.tm_mon = g_date_get_month (&start_date) - 1;
+ date_tm.tm_mday = g_date_get_day (&start_date);
+ /* We need to call this to set the weekday. */
+ mktime (&date_tm);
+ e_time_format_date_and_time (&date_tm,
+ ecde->use_24_hour_format,
+ !is_date, FALSE,
+ buffer, sizeof (buffer));
+ } else {
+ buffer[0] = '\0';
+ }
+
+ e_cell_date_edit_update_cell (ecde, buffer);
+ e_cell_date_edit_hide_popup (ecde);
+}
+
+
+static void
+e_cell_date_edit_show_time_invalid_warning (ECellDateEdit *ecde)
+{
+ GtkWidget *dialog;
+ struct tm date_tm;
+ char buffer[64];
+
+ /* Create a useful error message showing the correct format. */
+ date_tm.tm_year = 100;
+ date_tm.tm_mon = 0;
+ date_tm.tm_mday = 1;
+ date_tm.tm_hour = 1;
+ date_tm.tm_min = 30;
+ date_tm.tm_sec = 0;
+ date_tm.tm_isdst = -1;
+ e_time_format_time (&date_tm, ecde->use_24_hour_format, FALSE,
+ buffer, sizeof (buffer));
+
+ /* FIXME: Fix transient settings - I'm not sure it works with popup
+ windows. Maybe we need to use a normal window without decorations.*/
+ dialog = gtk_message_dialog_new (
+ GTK_WINDOW (ecde->popup_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
+ _("The time must be in the format: %s"),
+ buffer);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
+
+static void
+e_cell_date_edit_on_now_clicked (GtkWidget *button,
+ ECellDateEdit *ecde)
+{
+ struct tm tmp_tm;
+ time_t t;
+ char buffer[64];
+
+ if (ecde->time_callback) {
+ tmp_tm = (*ecde->time_callback) (ecde, ecde->time_callback_data);
+ } else {
+ t = time (NULL);
+ tmp_tm = *localtime (&t);
+ }
+ e_time_format_date_and_time (&tmp_tm,
+ ecde->use_24_hour_format,
+ TRUE, FALSE,
+ buffer, sizeof (buffer));
+
+ e_cell_date_edit_update_cell (ecde, buffer);
+ e_cell_date_edit_hide_popup (ecde);
+}
+
+
+static void
+e_cell_date_edit_on_none_clicked (GtkWidget *button,
+ ECellDateEdit *ecde)
+{
+ e_cell_date_edit_update_cell (ecde, "");
+ e_cell_date_edit_hide_popup (ecde);
+}
+
+
+static void
+e_cell_date_edit_on_today_clicked (GtkWidget *button,
+ ECellDateEdit *ecde)
+{
+ struct tm tmp_tm;
+ time_t t;
+ char buffer[64];
+
+ if (ecde->time_callback) {
+ tmp_tm = (*ecde->time_callback) (ecde, ecde->time_callback_data);
+ } else {
+ t = time (NULL);
+ tmp_tm = *localtime (&t);
+ }
+
+ tmp_tm.tm_hour = 0;
+ tmp_tm.tm_min = 0;
+ tmp_tm.tm_sec = 0;
+ e_time_format_date_and_time (&tmp_tm,
+ ecde->use_24_hour_format,
+ FALSE, FALSE,
+ buffer, sizeof (buffer));
+
+ e_cell_date_edit_update_cell (ecde, buffer);
+ e_cell_date_edit_hide_popup (ecde);
+}
+
+
+static void
+e_cell_date_edit_update_cell (ECellDateEdit *ecde,
- char *text)
++ const gchar *text)
+{
+ ECellPopup *ecp = E_CELL_POPUP (ecde);
+ ECellText *ecell_text = E_CELL_TEXT (ecp->child);
+ ECellView *ecv = (ECellView*) ecp->popup_cell_view;
+ ETableItem *eti = E_TABLE_ITEM (ecv->e_table_item_view);
+ ETableCol *ecol;
+ gchar *old_text;
+
+ /* Compare the new text with the existing cell contents. */
+ ecol = e_table_header_get_column (eti->header, ecp->popup_view_col);
+
+ old_text = e_cell_text_get_text (ecell_text, ecv->e_table_model,
+ ecol->col_idx, ecp->popup_row);
+
+ /* If they are different, update the cell contents. */
+ if (strcmp (old_text, text)) {
+ e_cell_text_set_value (ecell_text, ecv->e_table_model,
+ ecol->col_idx, ecp->popup_row, text);
+ e_cell_leave_edit (ecv, ecp->popup_view_col, ecol->col_idx, ecp->popup_row, NULL);
+ }
+
+ e_cell_text_free_text (ecell_text, old_text);
+}
+
+
+static void
+e_cell_date_edit_on_time_selected (GtkTreeSelection *selection, ECellDateEdit *ecde)
+{
+ gchar *list_item_text = NULL;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, 0, &list_item_text, -1);
+
+ g_return_if_fail (list_item_text != NULL);
+
+ gtk_entry_set_text (GTK_ENTRY (ecde->time_entry), list_item_text);
+
+ g_free (list_item_text);
+}
+
+
+static void
+e_cell_date_edit_hide_popup (ECellDateEdit *ecde)
+{
+ gtk_grab_remove (ecde->popup_window);
+ gtk_widget_hide (ecde->popup_window);
+ e_cell_popup_set_shown (E_CELL_POPUP (ecde), FALSE);
+}
+
+
+/* These freeze and thaw the rebuilding of the time list. They are useful when
+ setting several properties which result in rebuilds of the list, e.g. the
+ lower_hour, upper_hour and use_24_hour_format properties. */
+void
+e_cell_date_edit_freeze (ECellDateEdit *ecde)
+{
+ g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
+
+ ecde->freeze_count++;
+}
+
+
+void
+e_cell_date_edit_thaw (ECellDateEdit *ecde)
+{
+ g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
+
+ if (ecde->freeze_count > 0) {
+ ecde->freeze_count--;
+
+ if (ecde->freeze_count == 0)
+ e_cell_date_edit_rebuild_time_list (ecde);
+ }
+}
+
+
+/* Sets a callback to use to get the current time. This is useful if the
+ application needs to use its own timezone data rather than rely on the
+ Unix timezone. */
+void
+e_cell_date_edit_set_get_time_callback (ECellDateEdit *ecde,
+ ECellDateEditGetTimeCallback cb,
+ gpointer data,
+ GDestroyNotify destroy)
+{
+ g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
+
+ if (ecde->time_callback_data && ecde->time_callback_destroy)
+ (*ecde->time_callback_destroy) (ecde->time_callback_data);
+
+ ecde->time_callback = cb;
+ ecde->time_callback_data = data;
+ ecde->time_callback_destroy = destroy;
+}
diff --cc widgets/text/e-reflow.c
index c17b970,0000000..95f3f89
mode 100644,000000..100644
--- a/widgets/text/e-reflow.c
+++ b/widgets/text/e-reflow.c
@@@ -1,1534 -1,0 +1,1534 @@@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Lahey <clahey ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ */
+#include <config.h>
+
+#include <math.h>
+#include <string.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "text/e-text.h"
+#include <glib/gi18n.h>
+#include "e-util/e-util.h"
+#include "e-util/e-unicode.h"
+
+#include "misc/e-canvas.h"
+#include "misc/e-canvas-utils.h"
+#include "e-reflow.h"
+#include "misc/e-selection-model-simple.h"
+
+static gboolean e_reflow_event (GnomeCanvasItem *item, GdkEvent *event);
+static void e_reflow_realize (GnomeCanvasItem *item);
+static void e_reflow_unrealize (GnomeCanvasItem *item);
+static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static void e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags);
+static double e_reflow_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item);
+static void e_reflow_reflow (GnomeCanvasItem *item, int flags);
+static void set_empty(EReflow *reflow);
+
+static void e_reflow_resize_children (GnomeCanvasItem *item);
+
+#define E_REFLOW_DIVIDER_WIDTH 2
+#define E_REFLOW_BORDER_WIDTH 7
+#define E_REFLOW_FULL_GUTTER (E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH * 2)
+
+G_DEFINE_TYPE (EReflow, e_reflow, GNOME_TYPE_CANVAS_GROUP)
+
+/* The arguments we take */
+enum {
+ PROP_0,
+ PROP_MINIMUM_WIDTH,
+ PROP_WIDTH,
+ PROP_HEIGHT,
+ PROP_EMPTY_MESSAGE,
+ PROP_MODEL,
+ PROP_COLUMN_WIDTH
+};
+
+enum {
+ SELECTION_EVENT,
+ COLUMN_WIDTH_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = {0, };
+
+static gint
+er_compare (int i1, int i2, gpointer user_data)
+{
+ EReflow *reflow = user_data;
+ return e_reflow_model_compare (reflow->model, i1, i2);
+}
+
+static gint
+e_reflow_pick_line (EReflow *reflow, double x)
+{
+ x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
+ x /= reflow->column_width + E_REFLOW_FULL_GUTTER;
+ return x;
+}
+
+static int
+er_find_item (EReflow *reflow, GnomeCanvasItem *item)
+{
+ int i;
+ for (i = 0; i < reflow->count; i++) {
+ if (reflow->items[i] == item)
+ return i;
+ }
+ return -1;
+}
+
+static void
+e_reflow_resize_children (GnomeCanvasItem *item)
+{
+ EReflow *reflow;
+ int i;
+ int count;
+
+ reflow = E_REFLOW (item);
+
+ count = reflow->count;
+ for (i = 0; i < count; i++) {
+ if (reflow->items[i])
+ gnome_canvas_item_set(reflow->items[i],
+ "width", (double) reflow->column_width,
+ NULL);
+ }
+}
+
+static inline void
+e_reflow_update_selection_row (EReflow *reflow, int row)
+{
+ if (reflow->items[row]) {
+ g_object_set(reflow->items[row],
+ "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), row),
+ NULL);
+ } else if (e_selection_model_is_row_selected (E_SELECTION_MODEL (reflow->selection), row)) {
+ reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow));
+ g_object_set (reflow->items[row],
+ "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), row),
+ "width", (double) reflow->column_width,
+ NULL);
+ }
+}
+
+static void
+e_reflow_update_selection (EReflow *reflow)
+{
+ int i;
+ int count;
+
+ count = reflow->count;
+ for (i = 0; i < count; i++) {
+ e_reflow_update_selection_row (reflow, i);
+ }
+}
+
+static void
+selection_changed (ESelectionModel *selection, EReflow *reflow)
+{
+ e_reflow_update_selection (reflow);
+}
+
+static void
+selection_row_changed (ESelectionModel *selection, int row, EReflow *reflow)
+{
+ e_reflow_update_selection_row (reflow, row);
+}
+
+static gboolean
+do_adjustment (gpointer user_data)
+{
+ int row;
+ GtkAdjustment *adj ;
+ gfloat value, min_value, max_value;
+ EReflow *reflow = user_data;
+
+ row = reflow->cursor_row;
+ if (row == -1)
+ return FALSE;
+
+ adj = gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas));
+ value = adj->value;
+
+ if ((!reflow->items) || (!reflow->items[row]))
+ return TRUE;
+ min_value = reflow->items[row]->x2 - adj->page_size;
+ max_value = reflow->items[row]->x1;
+
+ if (value < min_value)
+ value = min_value;
+
+ if (value > max_value)
+ value = max_value;
+
+ if (value != adj->value) {
+ adj->value = value;
+ gtk_adjustment_value_changed (adj);
+ }
+
+ reflow->do_adjustment_idle_id = 0;
+
+ return FALSE;
+}
+
+static void
+cursor_changed (ESelectionModel *selection, int row, int col, EReflow *reflow)
+{
+ int count = reflow->count;
+ int old_cursor = reflow->cursor_row;
+
+ if (old_cursor < count && old_cursor >= 0) {
+ if (reflow->items[old_cursor]) {
+ g_object_set (reflow->items[old_cursor],
+ "has_cursor", FALSE,
+ NULL);
+ }
+ }
+
+ reflow->cursor_row = row;
+
+ if (row < count && row >= 0) {
+ if (reflow->items[row]) {
+ g_object_set (reflow->items[row],
+ "has_cursor", TRUE,
+ NULL);
+ } else {
+ reflow->items[row] = e_reflow_model_incarnate (reflow->model, row, GNOME_CANVAS_GROUP (reflow));
+ g_object_set (reflow->items[row],
+ "has_cursor", TRUE,
+ "width", (double) reflow->column_width,
+ NULL);
+ }
+ }
+
+ if (reflow->do_adjustment_idle_id == 0)
+ reflow->do_adjustment_idle_id = g_idle_add (do_adjustment, reflow);
+
+}
+
+
+static void
+incarnate (EReflow *reflow)
+{
+ int column_width;
+ int first_column;
+ int last_column;
+ int first_cell;
+ int last_cell;
+ int i;
+ GtkAdjustment *adjustment = gtk_layout_get_hadjustment (GTK_LAYOUT (GNOME_CANVAS_ITEM (reflow)->canvas));
+
+ column_width = reflow->column_width;
+
+ first_column = adjustment->value - 1 + E_REFLOW_BORDER_WIDTH;
+ first_column /= column_width + E_REFLOW_FULL_GUTTER;
+
+ last_column = adjustment->value + adjustment->page_size + 1 - E_REFLOW_BORDER_WIDTH - E_REFLOW_DIVIDER_WIDTH;
+ last_column /= column_width + E_REFLOW_FULL_GUTTER;
+ last_column ++;
+
+ if (first_column >= 0 && first_column < reflow->column_count)
+ first_cell = reflow->columns[first_column];
+ else
+ first_cell = 0;
+
+ if (last_column >= 0 && last_column < reflow->column_count)
+ last_cell = reflow->columns[last_column];
+ else
+ last_cell = reflow->count;
+
+ for (i = first_cell; i < last_cell; i++) {
+ int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
+ if (reflow->items[unsorted] == NULL) {
+ if (reflow->model) {
+ reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow));
+ g_object_set (reflow->items[unsorted],
+ "selected", e_selection_model_is_row_selected(E_SELECTION_MODEL(reflow->selection), unsorted),
+ "width", (double) reflow->column_width,
+ NULL);
+ }
+ }
+ }
+ reflow->incarnate_idle_id = 0;
+}
+
+static gboolean
+invoke_incarnate (gpointer user_data)
+{
+ EReflow *reflow = user_data;
+ incarnate (reflow);
+ return FALSE;
+}
+
+static void
+queue_incarnate (EReflow *reflow)
+{
+ if (reflow->incarnate_idle_id == 0)
+ reflow->incarnate_idle_id =
+ g_idle_add_full (25, invoke_incarnate, reflow, NULL);
+}
+
+static void
+reflow_columns (EReflow *reflow)
+{
+ GSList *list;
+ int count;
+ int start;
+ int i;
+ int column_count, column_start;
+ double running_height;
+
+ if (reflow->reflow_from_column <= 1) {
+ start = 0;
+ column_count = 1;
+ column_start = 0;
+ }
+ else {
+ /* we start one column before the earliest new entry,
+ so we can handle the case where the new entry is
+ inserted at the start of the column */
+ column_start = reflow->reflow_from_column - 1;
+ start = reflow->columns[column_start];
+ column_count = column_start + 1;
+ }
+
+ list = NULL;
+
+ running_height = E_REFLOW_BORDER_WIDTH;
+
+ count = reflow->count - start;
+ for (i = start; i < count; i++) {
+ int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
+ if (i != 0 && running_height + reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH > reflow->height) {
+ list = g_slist_prepend (list, GINT_TO_POINTER(i));
+ column_count ++;
+ running_height = E_REFLOW_BORDER_WIDTH * 2 + reflow->heights[unsorted];
+ } else
+ running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH;
+ }
+
+ reflow->column_count = column_count;
+ reflow->columns = g_renew (int, reflow->columns, column_count);
+ column_count --;
+
+ for (; column_count > column_start; column_count--) {
+ GSList *to_free;
+ reflow->columns[column_count] = GPOINTER_TO_INT(list->data);
+ to_free = list;
+ list = list->next;
+ g_slist_free_1 (to_free);
+ }
+ reflow->columns[column_start] = start;
+
+ queue_incarnate (reflow);
+
+ reflow->need_reflow_columns = FALSE;
+ reflow->reflow_from_column = -1;
+}
+
+static void
+item_changed (EReflowModel *model, int i, EReflow *reflow)
+{
+ if (i < 0 || i >= reflow->count)
+ return;
+
+ reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
+ if (reflow->items[i] != NULL)
+ e_reflow_model_reincarnate (model, i, reflow->items[i]);
+ e_sorter_array_clean (reflow->sorter);
+ reflow->reflow_from_column = -1;
+ reflow->need_reflow_columns = TRUE;
+ e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
+}
+
+static void
+item_removed (EReflowModel *model, int i, EReflow *reflow)
+{
+ int c;
+ int sorted;
+
+ if (i < 0 || i >= reflow->count)
+ return;
+
+ sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i);
+ for (c = reflow->column_count - 1; c >= 0; c--) {
+ int start_of_column = reflow->columns[c];
+
+ if (start_of_column <= sorted) {
+ if (reflow->reflow_from_column == -1
+ || reflow->reflow_from_column > c) {
+ reflow->reflow_from_column = c;
+ }
+ break;
+ }
+ }
+
+ if (reflow->items[i])
+ gtk_object_destroy (GTK_OBJECT (reflow->items[i]));
+
+ memmove (reflow->heights + i, reflow->heights + i + 1, (reflow->count - i - 1) * sizeof (int));
+ memmove (reflow->items + i, reflow->items + i + 1, (reflow->count - i - 1) * sizeof (GnomeCanvasItem *));
+
+ reflow->count --;
+
+ reflow->heights [reflow->count] = 0;
+ reflow->items [reflow->count] = NULL;
+
+ reflow->need_reflow_columns = TRUE;
+ set_empty (reflow);
+ e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
+
+ e_sorter_array_set_count (reflow->sorter, reflow->count);
+
+ e_selection_model_simple_delete_rows (E_SELECTION_MODEL_SIMPLE (reflow->selection), i, 1);
+}
+
+static void
+items_inserted (EReflowModel *model, int position, int count, EReflow *reflow)
+{
+ int i, oldcount;
+
+ if (position < 0 || position > reflow->count)
+ return;
+
+ oldcount = reflow->count;
+
+ reflow->count += count;
+
+ if (reflow->count > reflow->allocated_count) {
+ while (reflow->count > reflow->allocated_count)
+ reflow->allocated_count += 256;
+ reflow->heights = g_renew (int, reflow->heights, reflow->allocated_count);
+ reflow->items = g_renew (GnomeCanvasItem *, reflow->items, reflow->allocated_count);
+ }
+ memmove (reflow->heights + position + count, reflow->heights + position, (reflow->count - position - count) * sizeof (int));
+ memmove (reflow->items + position + count, reflow->items + position, (reflow->count - position - count) * sizeof (GnomeCanvasItem *));
+ for (i = position; i < position + count; i++) {
+ reflow->items[i] = NULL;
+ reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
+ }
+
+ e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), reflow->count);
+ if (position == oldcount)
+ e_sorter_array_append (reflow->sorter, count);
+ else
+ e_sorter_array_set_count (reflow->sorter, reflow->count);
+
+ for (i = position; i < position + count; i ++) {
+ int sorted = e_sorter_model_to_sorted (E_SORTER (reflow->sorter), i);
+ int c;
+
+ for (c = reflow->column_count - 1; c >= 0; c--) {
+ int start_of_column = reflow->columns[c];
+
+ if (start_of_column <= sorted) {
+ if (reflow->reflow_from_column == -1
+ || reflow->reflow_from_column > c) {
+ reflow->reflow_from_column = c;
+ }
+ break;
+ }
+ }
+ }
+
+ reflow->need_reflow_columns = TRUE;
+ set_empty (reflow);
+ e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
+}
+
+static void
+model_changed (EReflowModel *model, EReflow *reflow)
+{
+ int i;
+ int count;
+ int oldcount;
+
+ count = reflow->count;
+ oldcount = count;
+
+ for (i = 0; i < count; i++) {
+ if (reflow->items[i])
+ gtk_object_destroy (GTK_OBJECT (reflow->items[i]));
+ }
+ g_free (reflow->items);
+ g_free (reflow->heights);
+ reflow->count = e_reflow_model_count (model);
+ reflow->allocated_count = reflow->count;
+ reflow->items = g_new (GnomeCanvasItem *, reflow->count);
+ reflow->heights = g_new (int, reflow->count);
+
+ count = reflow->count;
+ for (i = 0; i < count; i++) {
+ reflow->items[i] = NULL;
+ reflow->heights[i] = e_reflow_model_height (reflow->model, i, GNOME_CANVAS_GROUP (reflow));
+ }
+
+ e_selection_model_simple_set_row_count (E_SELECTION_MODEL_SIMPLE (reflow->selection), count);
+ e_sorter_array_set_count (reflow->sorter, reflow->count);
+
+ reflow->need_reflow_columns = TRUE;
+ if (oldcount > reflow->count)
+ reflow_columns (reflow);
+ set_empty (reflow);
+ e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
+}
+
+static void
+comparison_changed (EReflowModel *model, EReflow *reflow)
+{
+ e_sorter_array_clean (reflow->sorter);
+ reflow->reflow_from_column = -1;
+ reflow->need_reflow_columns = TRUE;
+ e_canvas_item_request_reflow(GNOME_CANVAS_ITEM (reflow));
+}
+
+static void
+set_empty(EReflow *reflow)
+{
+ if (reflow->count == 0) {
+ if (reflow->empty_text) {
+ if (reflow->empty_message) {
+ gnome_canvas_item_set(reflow->empty_text,
+ "width", reflow->minimum_width,
+ "text", reflow->empty_message,
+ NULL);
+ e_canvas_item_move_absolute(reflow->empty_text,
+ reflow->minimum_width / 2,
+ 0);
+ } else {
+ gtk_object_destroy(GTK_OBJECT(reflow->empty_text));
+ reflow->empty_text = NULL;
+ }
+ } else {
+ if (reflow->empty_message) {
+ reflow->empty_text =
+ gnome_canvas_item_new(GNOME_CANVAS_GROUP(reflow),
+ e_text_get_type(),
+ "anchor", GTK_ANCHOR_N,
+ "width", reflow->minimum_width,
+ "clip", TRUE,
+ "use_ellipsis", TRUE,
+ "justification", GTK_JUSTIFY_CENTER,
+ "text", reflow->empty_message,
+ "draw_background", FALSE,
+ NULL);
+ e_canvas_item_move_absolute(reflow->empty_text,
+ reflow->minimum_width / 2,
+ 0);
+ }
+ }
+ } else {
+ if (reflow->empty_text) {
+ gtk_object_destroy(GTK_OBJECT(reflow->empty_text));
+ reflow->empty_text = NULL;
+ }
+ }
+}
+
+static void
+disconnect_model (EReflow *reflow)
+{
+ if (reflow->model == NULL)
+ return;
+
+ g_signal_handler_disconnect (reflow->model,
+ reflow->model_changed_id);
+ g_signal_handler_disconnect (reflow->model,
+ reflow->comparison_changed_id);
+ g_signal_handler_disconnect (reflow->model,
+ reflow->model_items_inserted_id);
+ g_signal_handler_disconnect (reflow->model,
+ reflow->model_item_removed_id);
+ g_signal_handler_disconnect (reflow->model,
+ reflow->model_item_changed_id);
+ g_object_unref (reflow->model);
+
+ reflow->model_changed_id = 0;
+ reflow->comparison_changed_id = 0;
+ reflow->model_items_inserted_id = 0;
+ reflow->model_item_removed_id = 0;
+ reflow->model_item_changed_id = 0;
+ reflow->model = NULL;
+}
+
+static void
+disconnect_selection (EReflow *reflow)
+{
+ if (reflow->selection == NULL)
+ return;
+
+ g_signal_handler_disconnect (reflow->selection,
+ reflow->selection_changed_id);
+ g_signal_handler_disconnect (reflow->selection,
+ reflow->selection_row_changed_id);
+ g_signal_handler_disconnect (reflow->selection,
+ reflow->cursor_changed_id);
+ g_object_unref (reflow->selection);
+
+ reflow->selection_changed_id = 0;
+ reflow->selection_row_changed_id = 0;
+ reflow->cursor_changed_id = 0;
+ reflow->selection = NULL;
+}
+
+static void
+connect_model (EReflow *reflow, EReflowModel *model)
+{
+ if (reflow->model != NULL)
+ disconnect_model (reflow);
+
+ if (model == NULL)
+ return;
+
+ reflow->model = model;
+ g_object_ref (reflow->model);
+ reflow->model_changed_id =
+ g_signal_connect (reflow->model, "model_changed",
+ G_CALLBACK (model_changed), reflow);
+ reflow->comparison_changed_id =
+ g_signal_connect (reflow->model, "comparison_changed",
+ G_CALLBACK (comparison_changed), reflow);
+ reflow->model_items_inserted_id =
+ g_signal_connect (reflow->model, "model_items_inserted",
+ G_CALLBACK (items_inserted), reflow);
+ reflow->model_item_removed_id =
+ g_signal_connect (reflow->model, "model_item_removed",
+ G_CALLBACK (item_removed), reflow);
+ reflow->model_item_changed_id =
+ g_signal_connect (reflow->model, "model_item_changed",
+ G_CALLBACK (item_changed), reflow);
+ model_changed (model, reflow);
+}
+
+static void
+adjustment_changed (GtkAdjustment *adjustment, EReflow *reflow)
+{
+ queue_incarnate (reflow);
+}
+
+static void
+disconnect_adjustment (EReflow *reflow)
+{
+ if (reflow->adjustment == NULL)
+ return;
+
+ g_signal_handler_disconnect (reflow->adjustment,
+ reflow->adjustment_changed_id);
+ g_signal_handler_disconnect (reflow->adjustment,
+ reflow->adjustment_value_changed_id);
+
+ g_object_unref (reflow->adjustment);
+
+ reflow->adjustment_changed_id = 0;
+ reflow->adjustment_value_changed_id = 0;
+ reflow->adjustment = NULL;
+}
+
+static void
+connect_adjustment (EReflow *reflow, GtkAdjustment *adjustment)
+{
+ if (reflow->adjustment != NULL)
+ disconnect_adjustment (reflow);
+
+ if (adjustment == NULL)
+ return;
+
+ reflow->adjustment = adjustment;
+ reflow->adjustment_changed_id =
+ g_signal_connect (adjustment, "changed",
+ G_CALLBACK (adjustment_changed), reflow);
+ reflow->adjustment_value_changed_id =
+ g_signal_connect (adjustment, "value_changed",
+ G_CALLBACK (adjustment_changed), reflow);
+ g_object_ref (adjustment);
+}
+
+#if 0
+static void
+set_scroll_adjustments (GtkLayout *layout, GtkAdjustment *hadj, GtkAdjustment *vadj, EReflow *reflow)
+{
+ connect_adjustment (reflow, hadj);
+}
+
+static void
+connect_set_adjustment (EReflow *reflow)
+{
+ reflow->set_scroll_adjustments_id =
+ g_signal_connect (GNOME_CANVAS_ITEM (reflow)->canvas,
+ "set_scroll_adjustments",
+ G_CALLBACK (set_scroll_adjustments), reflow);
+}
+#endif
+
+static void
+disconnect_set_adjustment (EReflow *reflow)
+{
+ if (reflow->set_scroll_adjustments_id != 0) {
+ g_signal_handler_disconnect (GNOME_CANVAS_ITEM (reflow)->canvas,
+ reflow->set_scroll_adjustments_id);
+ reflow->set_scroll_adjustments_id = 0;
+ }
+}
+
+static void
+column_width_changed (EReflow *reflow)
+{
+ g_signal_emit (reflow, signals[COLUMN_WIDTH_CHANGED], 0, reflow->column_width);
+}
+
+
+
+
+/* Virtual functions */
+static void
+e_reflow_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ EReflow *reflow;
+
+ item = GNOME_CANVAS_ITEM (object);
+ reflow = E_REFLOW (object);
+
+ switch (prop_id){
+ case PROP_HEIGHT:
+ reflow->height = g_value_get_double (value);
+ reflow->need_reflow_columns = TRUE;
+ e_canvas_item_request_reflow(item);
+ break;
+ case PROP_MINIMUM_WIDTH:
+ reflow->minimum_width = g_value_get_double (value);
+ if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(object))
+ set_empty(reflow);
+ e_canvas_item_request_reflow(item);
+ break;
+ case PROP_EMPTY_MESSAGE:
+ g_free(reflow->empty_message);
+ reflow->empty_message = g_strdup(g_value_get_string (value));
+ if (GNOME_CANVAS_ITEM_REALIZED & GTK_OBJECT_FLAGS(object))
+ set_empty(reflow);
+ break;
+ case PROP_MODEL:
+ connect_model (reflow, (EReflowModel *) g_value_get_object (value));
+ break;
+ case PROP_COLUMN_WIDTH:
+ if (reflow->column_width != g_value_get_double (value)) {
+ GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
+ double old_width = reflow->column_width;
+
+ reflow->column_width = g_value_get_double (value);
+ adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2;
+ adjustment->page_increment = adjustment->page_size - adjustment->step_increment;
+ gtk_adjustment_changed(adjustment);
+ e_reflow_resize_children(item);
+ e_canvas_item_request_reflow(item);
+
+ reflow->need_column_resize = TRUE;
+ gnome_canvas_item_request_update(item);
+
+ if (old_width != reflow->column_width)
+ column_width_changed (reflow);
+ }
+ break;
+ }
+}
+
+static void
+e_reflow_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ EReflow *reflow;
+
+ reflow = E_REFLOW (object);
+
+ switch (prop_id) {
+ case PROP_MINIMUM_WIDTH:
+ g_value_set_double (value, reflow->minimum_width);
+ break;
+ case PROP_WIDTH:
+ g_value_set_double (value, reflow->width);
+ break;
+ case PROP_HEIGHT:
+ g_value_set_double (value, reflow->height);
+ break;
+ case PROP_EMPTY_MESSAGE:
+ g_value_set_string (value, reflow->empty_message);
+ break;
+ case PROP_MODEL:
+ g_value_set_object (value, reflow->model);
+ break;
+ case PROP_COLUMN_WIDTH:
+ g_value_set_double (value, reflow->column_width);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+e_reflow_dispose (GObject *object)
+{
+ EReflow *reflow = E_REFLOW(object);
+
+ g_free (reflow->items);
+ g_free (reflow->heights);
+ g_free (reflow->columns);
+
+ reflow->items = NULL;
+ reflow->heights = NULL;
+ reflow->columns = NULL;
+ reflow->count = 0;
+ reflow->allocated_count = 0;
+
+ if (reflow->incarnate_idle_id)
+ g_source_remove (reflow->incarnate_idle_id);
+ reflow->incarnate_idle_id = 0;
+
+ if (reflow->do_adjustment_idle_id)
+ g_source_remove (reflow->do_adjustment_idle_id);
+ reflow->do_adjustment_idle_id = 0;
+
+ disconnect_model (reflow);
+ disconnect_selection (reflow);
+
+ g_free(reflow->empty_message);
+ reflow->empty_message = NULL;
+
+ if (reflow->sorter) {
+ g_object_unref (reflow->sorter);
+ reflow->sorter = NULL;
+ }
+
+ G_OBJECT_CLASS(e_reflow_parent_class)->dispose (object);
+}
+
+static void
+e_reflow_realize (GnomeCanvasItem *item)
+{
+ EReflow *reflow;
+ GtkAdjustment *adjustment;
+ int count;
+ int i;
+
+ reflow = E_REFLOW (item);
+
+ if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->realize)
+ (* GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->realize) (item);
+
+ reflow->arrow_cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
+ reflow->default_cursor = gdk_cursor_new (GDK_LEFT_PTR);
+
+ count = reflow->count;
+ for(i = 0; i < count; i++) {
+ if (reflow->items[i])
+ gnome_canvas_item_set(reflow->items[i],
+ "width", reflow->column_width,
+ NULL);
+ }
+
+ set_empty(reflow);
+
+ reflow->need_reflow_columns = TRUE;
+ e_canvas_item_request_reflow(item);
+
+ adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
+
+#if 0
+ connect_set_adjustment (reflow);
+#endif
+ connect_adjustment (reflow, adjustment);
+
+ adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2;
+ adjustment->page_increment = adjustment->page_size - adjustment->step_increment;
+ gtk_adjustment_changed(adjustment);
+
+ if (!item->canvas->aa) {
+ }
+}
+
+static void
+e_reflow_unrealize (GnomeCanvasItem *item)
+{
+ EReflow *reflow;
+
+ reflow = E_REFLOW (item);
+
+ if (!item->canvas->aa) {
+ }
+
+ gdk_cursor_unref (reflow->arrow_cursor);
+ gdk_cursor_unref (reflow->default_cursor);
+ reflow->arrow_cursor = NULL;
+ reflow->default_cursor = NULL;
+
+ g_free (reflow->columns);
+ reflow->columns = NULL;
+
+ disconnect_set_adjustment (reflow);
+ disconnect_adjustment (reflow);
+
+ if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->unrealize)
+ (* GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->unrealize) (item);
+}
+
+static gboolean
+e_reflow_event (GnomeCanvasItem *item, GdkEvent *event)
+{
+ EReflow *reflow;
+ int return_val = FALSE;
+
+ reflow = E_REFLOW (item);
+
+ switch( event->type )
+ {
+ case GDK_KEY_PRESS:
+ return_val = e_selection_model_key_press(reflow->selection, (GdkEventKey *) event);
+ break;
+#if 0
+ if (event->key.keyval == GDK_Tab ||
+ event->key.keyval == GDK_KP_Tab ||
+ event->key.keyval == GDK_ISO_Left_Tab) {
+ int i;
+ int count;
+ count = reflow->count;
+ for (i = 0; i < count; i++) {
+ int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
+ GnomeCanvasItem *item = reflow->items[unsorted];
+ EFocus has_focus;
+ if (item) {
+ g_object_get(item,
+ "has_focus", &has_focus,
+ NULL);
+ if (has_focus) {
+ if (event->key.state & GDK_SHIFT_MASK) {
+ if (i == 0)
+ return FALSE;
+ i--;
+ } else {
+ if (i == count - 1)
+ return FALSE;
+ i++;
+ }
+
+ unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
+ if (reflow->items[unsorted] == NULL) {
+ reflow->items[unsorted] = e_reflow_model_incarnate (reflow->model, unsorted, GNOME_CANVAS_GROUP (reflow));
+ }
+
+ item = reflow->items[unsorted];
+ gnome_canvas_item_set(item,
+ "has_focus", (event->key.state & GDK_SHIFT_MASK) ? E_FOCUS_END : E_FOCUS_START,
+ NULL);
+ return TRUE;
+ }
+ }
+ }
+ }
+#endif
+ case GDK_BUTTON_PRESS:
+ switch(event->button.button)
+ {
+ case 1:
+ {
+ GdkEventButton *button = (GdkEventButton *) event;
+ double n_x;
+ n_x = button->x;
+ n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
+ n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
+
+ if ( button->y >= E_REFLOW_BORDER_WIDTH && button->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) {
+ /* don't allow to drag the first line*/
+ if (e_reflow_pick_line(reflow, button->x) == 0)
+ return TRUE;
+ reflow->which_column_dragged = e_reflow_pick_line(reflow, button->x);
+ reflow->start_x = reflow->which_column_dragged * (reflow->column_width + E_REFLOW_FULL_GUTTER) - E_REFLOW_DIVIDER_WIDTH / 2;
+ reflow->temp_column_width = reflow->column_width;
+ reflow->column_drag = TRUE;
+
+ gnome_canvas_item_grab (item,
+ GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK,
+ reflow->arrow_cursor,
+ button->time);
+
+ reflow->previous_temp_column_width = -1;
+ reflow->need_column_resize = TRUE;
+ gnome_canvas_item_request_update(item);
+ return TRUE;
+ }
+ }
+ break;
+ case 4:
+ {
+ GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
+ gdouble new_value = adjustment->value;
+ new_value -= adjustment->step_increment;
+ gtk_adjustment_set_value(adjustment, new_value);
+ }
+ break;
+ case 5:
+ {
+ GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
+ gdouble new_value = adjustment->value;
+ new_value += adjustment->step_increment;
+ if ( new_value > adjustment->upper - adjustment->page_size )
+ new_value = adjustment->upper - adjustment->page_size;
+ gtk_adjustment_set_value(adjustment, new_value);
+ }
+ break;
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (reflow->column_drag) {
+ gdouble old_width = reflow->column_width;
+ GdkEventButton *button = (GdkEventButton *) event;
+ GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
+ reflow->temp_column_width = reflow->column_width +
+ (button->x - reflow->start_x)/(reflow->which_column_dragged - e_reflow_pick_line(reflow, adjustment->value));
+ if ( reflow->temp_column_width < 50 )
+ reflow->temp_column_width = 50;
+ reflow->column_drag = FALSE;
+ if ( old_width != reflow->temp_column_width ) {
+ gtk_adjustment_set_value(adjustment, adjustment->value + e_reflow_pick_line(reflow, adjustment->value) * (reflow->temp_column_width - reflow->column_width));
+ reflow->column_width = reflow->temp_column_width;
+ adjustment->step_increment = (reflow->column_width + E_REFLOW_FULL_GUTTER) / 2;
+ adjustment->page_increment = adjustment->page_size - adjustment->step_increment;
+ gtk_adjustment_changed(adjustment);
+ e_reflow_resize_children(item);
+ e_canvas_item_request_reflow(item);
+ gnome_canvas_request_redraw(item->canvas, 0, 0, reflow->width, reflow->height);
+ column_width_changed (reflow);
+ }
+ reflow->need_column_resize = TRUE;
+ gnome_canvas_item_request_update(item);
+ gnome_canvas_item_ungrab (item, button->time);
+ return TRUE;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (reflow->column_drag) {
+ double old_width = reflow->temp_column_width;
+ GdkEventMotion *motion = (GdkEventMotion *) event;
+ GtkAdjustment *adjustment = gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas));
+ reflow->temp_column_width = reflow->column_width +
+ (motion->x - reflow->start_x)/(reflow->which_column_dragged - e_reflow_pick_line(reflow, adjustment->value));
+ if (reflow->temp_column_width < 50)
+ reflow->temp_column_width = 50;
+ if (old_width != reflow->temp_column_width) {
+ reflow->need_column_resize = TRUE;
+ gnome_canvas_item_request_update(item);
+ }
+ return TRUE;
+ } else {
+ GdkEventMotion *motion = (GdkEventMotion *) event;
+ double n_x;
+
+ n_x = motion->x;
+ n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
+ n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
+
+ if ( motion->y >= E_REFLOW_BORDER_WIDTH && motion->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) {
+ if ( reflow->default_cursor_shown ) {
+ gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->arrow_cursor);
+ reflow->default_cursor_shown = FALSE;
+ }
+ } else
+ if ( ! reflow->default_cursor_shown ) {
+ gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->default_cursor);
+ reflow->default_cursor_shown = TRUE;
+ }
+
+ }
+ break;
+ case GDK_ENTER_NOTIFY:
+ if (!reflow->column_drag) {
+ GdkEventCrossing *crossing = (GdkEventCrossing *) event;
+ double n_x;
+ n_x = crossing->x;
+ n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
+ n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
+
+ if ( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) {
+ if ( reflow->default_cursor_shown ) {
+ gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->arrow_cursor);
+ reflow->default_cursor_shown = FALSE;
+ }
+ }
+ }
+ break;
+ case GDK_LEAVE_NOTIFY:
+ if (!reflow->column_drag) {
+ GdkEventCrossing *crossing = (GdkEventCrossing *) event;
+ double n_x;
+ n_x = crossing->x;
+ n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
+ n_x = fmod(n_x,(reflow->column_width + E_REFLOW_FULL_GUTTER));
+ if ( !( crossing->y >= E_REFLOW_BORDER_WIDTH && crossing->y <= reflow->height - E_REFLOW_BORDER_WIDTH && n_x < E_REFLOW_FULL_GUTTER ) ) {
+ if ( ! reflow->default_cursor_shown ) {
+ gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, reflow->default_cursor);
+ reflow->default_cursor_shown = TRUE;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if (return_val)
+ return return_val;
+ else if (GNOME_CANVAS_ITEM_CLASS( e_reflow_parent_class )->event)
+ return (* GNOME_CANVAS_ITEM_CLASS( e_reflow_parent_class )->event) (item, event);
+ else
+ return FALSE;
+}
+
+static void e_reflow_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ int x_rect, y_rect, width_rect, height_rect;
+ gdouble running_width;
+ EReflow *reflow = E_REFLOW(item);
+ int i;
+ double column_width;
+
+ if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->draw)
+ GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->draw (item, drawable, x, y, width, height);
+ column_width = reflow->column_width;
+ running_width = E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
+ x_rect = running_width;
+ y_rect = E_REFLOW_BORDER_WIDTH;
+ width_rect = E_REFLOW_DIVIDER_WIDTH;
+ height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
+
+ /* Compute first column to draw. */
+ i = x;
+ i /= column_width + E_REFLOW_FULL_GUTTER;
+ running_width += i * (column_width + E_REFLOW_FULL_GUTTER);
+
+ for ( ; i < reflow->column_count; i++) {
+ if ( running_width > x + width )
+ break;
+ x_rect = running_width;
+ gtk_paint_flat_box(GTK_WIDGET(item->canvas)->style,
+ drawable,
+ GTK_STATE_ACTIVE,
+ GTK_SHADOW_NONE,
+ NULL,
+ GTK_WIDGET(item->canvas),
+ "reflow",
+ x_rect - x,
+ y_rect - y,
+ width_rect,
+ height_rect);
+ running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
+ }
+ if (reflow->column_drag) {
+ int start_line = e_reflow_pick_line(reflow,
+ gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value);
+ i = x - start_line * (column_width + E_REFLOW_FULL_GUTTER);
+ running_width = start_line * (column_width + E_REFLOW_FULL_GUTTER);
+ column_width = reflow->temp_column_width;
+ running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
+ i += start_line * (column_width + E_REFLOW_FULL_GUTTER);
+ running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
+ x_rect = running_width;
+ y_rect = E_REFLOW_BORDER_WIDTH;
+ width_rect = E_REFLOW_DIVIDER_WIDTH;
+ height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
+
+ /* Compute first column to draw. */
+ i /= column_width + E_REFLOW_FULL_GUTTER;
+ running_width += i * (column_width + E_REFLOW_FULL_GUTTER);
+
+ for ( ; i < reflow->column_count; i++) {
+ if ( running_width > x + width )
+ break;
+ x_rect = running_width;
+ gdk_draw_rectangle(drawable,
+ GTK_WIDGET(item->canvas)->style->fg_gc[GTK_STATE_NORMAL],
+ TRUE,
+ x_rect - x,
+ y_rect - y,
+ width_rect - 1,
+ height_rect - 1);
+ running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
+ }
+ }
+}
+
+static void
+e_reflow_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags)
+{
+ EReflow *reflow;
+ double x0, x1, y0, y1;
+
+ reflow = E_REFLOW (item);
+
+ if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->update)
+ GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->update (item, affine, clip_path, flags);
+
+ x0 = item->x1;
+ y0 = item->y1;
+ x1 = item->x2;
+ y1 = item->y2;
+ if ( x1 < x0 + reflow->width )
+ x1 = x0 + reflow->width;
+ if ( y1 < y0 + reflow->height )
+ y1 = y0 + reflow->height;
+ item->x2 = x1;
+ item->y2 = y1;
+
+ if (reflow->need_height_update) {
+ x0 = item->x1;
+ y0 = item->y1;
+ x1 = item->x2;
+ y1 = item->y2;
+ if ( x0 > 0 )
+ x0 = 0;
+ if ( y0 > 0 )
+ y0 = 0;
+ if ( x1 < E_REFLOW(item)->width )
+ x1 = E_REFLOW(item)->width;
+ if ( x1 < E_REFLOW(item)->height )
+ x1 = E_REFLOW(item)->height;
+
+ gnome_canvas_request_redraw(item->canvas, x0, y0, x1, y1);
+ reflow->need_height_update = FALSE;
+ } else if (reflow->need_column_resize) {
+ int x_rect, y_rect, width_rect, height_rect;
+ int start_line = e_reflow_pick_line(reflow,
+ gtk_layout_get_hadjustment(GTK_LAYOUT(item->canvas))->value);
+ gdouble running_width;
+ int i;
+ double column_width;
+
+ if ( reflow->previous_temp_column_width != -1 ) {
+ running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER);
+ column_width = reflow->previous_temp_column_width;
+ running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
+ running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
+ y_rect = E_REFLOW_BORDER_WIDTH;
+ width_rect = E_REFLOW_DIVIDER_WIDTH;
+ height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
+
+ for ( i = 0; i < reflow->column_count; i++) {
+ x_rect = running_width;
+ gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect);
+ running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
+ }
+ }
+
+ if ( reflow->temp_column_width != -1 ) {
+ running_width = start_line * (reflow->column_width + E_REFLOW_FULL_GUTTER);
+ column_width = reflow->temp_column_width;
+ running_width -= start_line * (column_width + E_REFLOW_FULL_GUTTER);
+ running_width += E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
+ y_rect = E_REFLOW_BORDER_WIDTH;
+ width_rect = E_REFLOW_DIVIDER_WIDTH;
+ height_rect = reflow->height - (E_REFLOW_BORDER_WIDTH * 2);
+
+ for ( i = 0; i < reflow->column_count; i++) {
+ x_rect = running_width;
+ gnome_canvas_request_redraw(item->canvas, x_rect, y_rect, x_rect + width_rect, y_rect + height_rect);
+ running_width += E_REFLOW_DIVIDER_WIDTH + E_REFLOW_BORDER_WIDTH + column_width + E_REFLOW_BORDER_WIDTH;
+ }
+ }
+
+ reflow->previous_temp_column_width = reflow->temp_column_width;
+ reflow->need_column_resize = FALSE;
+ }
+}
+
+static double
+e_reflow_point (GnomeCanvasItem *item,
+ double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item)
+{
+ double distance = 1;
+
+ *actual_item = NULL;
+
+ if (GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->point)
+ distance = GNOME_CANVAS_ITEM_CLASS(e_reflow_parent_class)->point (item, x, y, cx, cy, actual_item);
+ if ((int) (distance * item->canvas->pixels_per_unit + 0.5) <= item->canvas->close_enough && *actual_item)
+ return distance;
+
+ *actual_item = item;
+ return 0;
+#if 0
+ if (y >= E_REFLOW_BORDER_WIDTH && y <= reflow->height - E_REFLOW_BORDER_WIDTH) {
+ float n_x;
+ n_x = x;
+ n_x += E_REFLOW_BORDER_WIDTH + E_REFLOW_DIVIDER_WIDTH;
+ n_x = fmod(n_x, (reflow->column_width + E_REFLOW_FULL_GUTTER));
+ if (n_x < E_REFLOW_FULL_GUTTER) {
+ *actual_item = item;
+ return 0;
+ }
+ }
+ return distance;
+#endif
+}
+
+static void
+e_reflow_reflow( GnomeCanvasItem *item, int flags )
+{
+ EReflow *reflow = E_REFLOW(item);
+ gdouble old_width;
+ gdouble running_width;
+ gdouble running_height;
+ int next_column;
+ int i;
+
+ if (! (GTK_OBJECT_FLAGS (reflow) & GNOME_CANVAS_ITEM_REALIZED))
+ return;
+
+ if (reflow->need_reflow_columns) {
+ reflow_columns (reflow);
+ }
+
+ old_width = reflow->width;
+
+ running_width = E_REFLOW_BORDER_WIDTH;
+ running_height = E_REFLOW_BORDER_WIDTH;
+
+ next_column = 1;
+
+ for (i = 0; i < reflow->count; i++) {
+ int unsorted = e_sorter_sorted_to_model (E_SORTER (reflow->sorter), i);
+ if (next_column < reflow->column_count && i == reflow->columns[next_column]) {
+ running_height = E_REFLOW_BORDER_WIDTH;
+ running_width += reflow->column_width + E_REFLOW_FULL_GUTTER;
+ next_column ++;
+ }
+
+ if (unsorted >= 0 && reflow->items[unsorted]) {
+ e_canvas_item_move_absolute(GNOME_CANVAS_ITEM(reflow->items[unsorted]),
+ (double) running_width,
+ (double) running_height);
+ running_height += reflow->heights[unsorted] + E_REFLOW_BORDER_WIDTH;
+ }
+ }
+ reflow->width = running_width + reflow->column_width + E_REFLOW_BORDER_WIDTH;
+ if ( reflow->width < reflow->minimum_width )
+ reflow->width = reflow->minimum_width;
+ if (old_width != reflow->width)
+ e_canvas_item_request_parent_reflow(item);
+}
+
+static int
+e_reflow_selection_event_real (EReflow *reflow, GnomeCanvasItem *item, GdkEvent *event)
+{
+ int row;
+ int return_val = TRUE;
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ switch (event->button.button) {
+ case 1: /* Fall through. */
+ case 2:
+ row = er_find_item (reflow, item);
+ if (event->button.button == 1) {
+ reflow->maybe_did_something =
+ e_selection_model_maybe_do_something(reflow->selection, row, 0, event->button.state);
+ reflow->maybe_in_drag = TRUE;
+ } else {
+ e_selection_model_do_something(reflow->selection, row, 0, event->button.state);
+ }
+ break;
+ case 3:
+ row = er_find_item (reflow, item);
+ e_selection_model_right_click_down(reflow->selection, row, 0, 0);
+ break;
+ default:
+ return_val = FALSE;
+ break;
+ }
+ break;
+ case GDK_BUTTON_RELEASE:
+ if (event->button.button == 1) {
+ if (reflow->maybe_in_drag) {
+ reflow->maybe_in_drag = FALSE;
+ if (!reflow->maybe_did_something) {
+ row = er_find_item (reflow, item);
+ e_selection_model_do_something(reflow->selection, row, 0, event->button.state);
+ }
+ }
+ }
+ break;
+ case GDK_KEY_PRESS:
+ return_val = e_selection_model_key_press(reflow->selection, (GdkEventKey *) event);
+ break;
+ default:
+ return_val = FALSE;
+ break;
+ }
+
+ return return_val;
+}
+
+static void
+e_reflow_class_init (EReflowClass *klass)
+{
+ GObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ object_class = (GObjectClass*) klass;
+ item_class = (GnomeCanvasItemClass *) klass;
+
+ object_class->set_property = e_reflow_set_property;
+ object_class->get_property = e_reflow_get_property;
+ object_class->dispose = e_reflow_dispose;
+
+ /* GnomeCanvasItem method overrides */
+ item_class->event = e_reflow_event;
+ item_class->realize = e_reflow_realize;
+ item_class->unrealize = e_reflow_unrealize;
+ item_class->draw = e_reflow_draw;
+ item_class->update = e_reflow_update;
+ item_class->point = e_reflow_point;
+
+ klass->selection_event = e_reflow_selection_event_real;
+ klass->column_width_changed = NULL;
+
+ g_object_class_install_property (object_class, PROP_MINIMUM_WIDTH,
+ g_param_spec_double ("minimum_width",
+ _( "Minimum width" ),
+ _( "Minimum Width" ),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROP_WIDTH,
+ g_param_spec_double ("width",
+ _( "Width" ),
+ _( "Width" ),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READABLE));
+
+
+ g_object_class_install_property (object_class, PROP_HEIGHT,
+ g_param_spec_double ("height",
+ _( "Height" ),
+ _( "Height" ),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROP_EMPTY_MESSAGE,
+ g_param_spec_string ("empty_message",
+ _( "Empty message" ),
+ _( "Empty message" ),
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROP_MODEL,
+ g_param_spec_object ("model",
+ _( "Reflow model" ),
+ _( "Reflow model" ),
+ E_REFLOW_MODEL_TYPE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROP_COLUMN_WIDTH,
+ g_param_spec_double ("column_width",
+ _( "Column width" ),
+ _( "Column width" ),
+ 0.0, G_MAXDOUBLE, 150.0,
+ G_PARAM_READWRITE));
+
+ signals [SELECTION_EVENT] =
+ g_signal_new ("selection_event",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EReflowClass, selection_event),
+ NULL, NULL,
+ e_marshal_INT__OBJECT_BOXED,
+ G_TYPE_INT, 2, G_TYPE_OBJECT,
+ GDK_TYPE_EVENT);
+
+ signals [COLUMN_WIDTH_CHANGED] =
+ g_signal_new ("column_width_changed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EReflowClass, column_width_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
+ G_TYPE_NONE, 1, G_TYPE_DOUBLE);
+}
+
+static void
+e_reflow_init (EReflow *reflow)
+{
+ reflow->model = NULL;
+ reflow->items = NULL;
+ reflow->heights = NULL;
+ reflow->count = 0;
+
+ reflow->columns = NULL;
+ reflow->column_count = 0;
+
+ reflow->empty_text = NULL;
+ reflow->empty_message = NULL;
+
+ reflow->minimum_width = 10;
+ reflow->width = 10;
+ reflow->height = 10;
+
+ reflow->column_width = 150;
+
+ reflow->column_drag = FALSE;
+
+ reflow->need_height_update = FALSE;
+ reflow->need_column_resize = FALSE;
+ reflow->need_reflow_columns = FALSE;
+
+ reflow->maybe_did_something = FALSE;
+ reflow->maybe_in_drag = FALSE;
+
+ reflow->default_cursor_shown = TRUE;
+ reflow->arrow_cursor = NULL;
+ reflow->default_cursor = NULL;
+
+ reflow->cursor_row = -1;
+
+ reflow->incarnate_idle_id = 0;
+ reflow->do_adjustment_idle_id = 0;
+ reflow->set_scroll_adjustments_id = 0;
+
+ reflow->selection = E_SELECTION_MODEL (e_selection_model_simple_new());
+ reflow->sorter = e_sorter_array_new (er_compare, reflow);
+
+ g_object_set (reflow->selection,
+ "sorter", reflow->sorter,
+ NULL);
+
+ reflow->selection_changed_id =
+ g_signal_connect(reflow->selection, "selection_changed",
+ G_CALLBACK (selection_changed), reflow);
+ reflow->selection_row_changed_id =
+ g_signal_connect(reflow->selection, "selection_row_changed",
+ G_CALLBACK (selection_row_changed), reflow);
+ reflow->cursor_changed_id =
+ g_signal_connect(reflow->selection, "cursor_changed",
+ G_CALLBACK (cursor_changed), reflow);
+
+ e_canvas_item_set_reflow_callback(GNOME_CANVAS_ITEM(reflow), e_reflow_reflow);
+}
diff --cc widgets/text/e-reflow.h
index afdc9ed,0000000..3ea840d
mode 100644,000000..100644
--- a/widgets/text/e-reflow.h
+++ b/widgets/text/e-reflow.h
@@@ -1,146 -1,0 +1,146 @@@
+/*
+ * 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; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
++ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Authors:
+ * Chris Lahey <clahey ximian com>
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __E_REFLOW_H__
+#define __E_REFLOW_H__
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <text/e-reflow-model.h>
+#include <misc/e-selection-model.h>
+#include <e-util/e-sorter-array.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+/* EReflow - A canvas item container.
+ *
+ * The following arguments are available:
+ *
+ * name type read/write description
+ * --------------------------------------------------------------------------------
+ * minimum_width double RW minimum width of the reflow. width >= minimum_width
+ * width double R width of the reflow
+ * height double RW height of the reflow
+ */
+
+#define E_REFLOW_TYPE (e_reflow_get_type ())
+#define E_REFLOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_REFLOW_TYPE, EReflow))
+#define E_REFLOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_REFLOW_TYPE, EReflowClass))
+#define E_IS_REFLOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_REFLOW_TYPE))
+#define E_IS_REFLOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_REFLOW_TYPE))
+
+
+typedef struct EReflowPriv EReflowPriv;
+
+typedef struct _EReflow EReflow;
+typedef struct _EReflowClass EReflowClass;
+
+struct _EReflow
+{
+ GnomeCanvasGroup parent;
+
+ /* item specific fields */
+ EReflowModel *model;
+ guint model_changed_id;
+ guint comparison_changed_id;
+ guint model_items_inserted_id;
+ guint model_item_removed_id;
+ guint model_item_changed_id;
+
+ ESelectionModel *selection;
+ guint selection_changed_id;
+ guint selection_row_changed_id;
+ guint cursor_changed_id;
+ ESorterArray *sorter;
+
+ GtkAdjustment *adjustment;
+ guint adjustment_changed_id;
+ guint adjustment_value_changed_id;
+ guint set_scroll_adjustments_id;
+
+ int *heights;
+ GnomeCanvasItem **items;
+ int count;
+ int allocated_count;
+
+ int *columns;
+ gint column_count; /* Number of columnns */
+
+ GnomeCanvasItem *empty_text;
+ gchar *empty_message;
+
+ double minimum_width;
+ double width;
+ double height;
+
+ double column_width;
+
+ int incarnate_idle_id;
+ int do_adjustment_idle_id;
+
+ /* These are all for when the column is being dragged. */
+ gdouble start_x;
+ gint which_column_dragged;
+ double temp_column_width;
+ double previous_temp_column_width;
+
+ int cursor_row;
+
+ int reflow_from_column;
+
+ guint column_drag : 1;
+
+ guint need_height_update : 1;
+ guint need_column_resize : 1;
+ guint need_reflow_columns : 1;
+
+ guint default_cursor_shown : 1;
+
+ guint maybe_did_something : 1;
+ guint maybe_in_drag : 1;
+ GdkCursor *arrow_cursor;
+ GdkCursor *default_cursor;
+};
+
+struct _EReflowClass
+{
+ GnomeCanvasGroupClass parent_class;
+
+ int (*selection_event) (EReflow *reflow, GnomeCanvasItem *item, GdkEvent *event);
+ void (*column_width_changed) (EReflow *reflow, double width);
+};
+
+/*
+ * To be added to a reflow, an item must have the argument "width" as
+ * a Read/Write argument and "height" as a Read Only argument. It
+ * should also do an ECanvas parent reflow request if its size
+ * changes.
+ */
+GType e_reflow_get_type (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __E_REFLOW_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]