Evolution Shell and Components
The evolution shell both centralizes control of version and upgrade handling and manages display of user interface. It provides the top level window as well as menu items that are applicable across all components. Built in components for Evolution include mail, contacts, calendar, tasks.
When Evolution is run it creates a shell (e-shell.h and e-shell.c) which can control multiple shell windows (e-shell-window.h and e-shell-window.c). A shell is a bonobo object which implements the Evolution-Shell.idl CORBA interface. Being a bonobo object allows subsequent invocations of Evolution to in fact trigger additional shell windows of an existing evolution process, by calling the createNewWindow interface method. This also has the drawback of not allowing Evolution to run in two displays at once (Bonobo can activate based on display, but the Camel mail library is not architected to run in the same user space in two processes at once). The two other shell interface methods are handleURI, which allows an already running evolution to handle uris like mailto:, and setLineStatus, which allows setting the online/offline status from the command line.
Evolution components are discovered during shell start up by doing a bonobo query for objects that support the interface in Evolution-Shell.idl. The shell creates a component registry (e-component-registry.h and e-component-registry.c) that performs the component query the first time information is demanded and stores results. Both the shell and the shell windows then use this data. During start up, if migration is required (changes to data or settings) the shell calls the upgradeFromVersion method and each component can upgrade data accordingly.
The shell window UI is populated by component controls obtained via the createControls component interface method, and components implement this by providing three bonobo controls - a sidebar control, a main view control and a status bar control. There are five major menu options driven by the shell window:
- Work Offline/Online
The New menu items are constructed by reading the userCreatableItems attribute on each component and constructing menu items based on each creatable item returned. If the user activates a New menu item, the shell window matches the item to a component and calls requestCreateItem with a unique string name obtained for the userCreatableItems attribute, the component is then to take appropriate actions to make the new item.
For Send/Receive the shell window calls back to the shell which simply calls the sendAndReceive method on the component. The only builtin component that acts on this is the mail component which sends pending mail and downloads new mail.
The online/offline state is at the shell level and applies to all shell windows and components. If Work Offline/Online is selected the shell window calls back to shell to set the status to online or offline as appropriate.
There are two phases for the Quit menu implementation, one is to prepare for quit using the requestQuit method which allows components to prepare for quitting by, for instance, prompting the user to save any unsaved changes. The component can abort the quit process by return false from the requestQuit method. If any component returns false, the shell will not exit. If all components return true, the quit method will be called and the components should shutdown, they are not allowed to abort the process at this point.
The Evolution calendar is implemented in 2 components, one for the calendar itself, and another one for tasks. Both of these implement the Evolution::Component CORBA interface, needed to communicate with the Shell.
The calendar component has 3 different types of view widgets, all of them being a subclass of the generic ECalendarView, which implements all common things.
EDayView: implements the day and work week views. It is separated into different files:
e-day-view.c: this implements the view itself.
e-day-view-layout.c: takes care of the layout in the view.
e-day-view-main-item.c: this is for drawing the events in the time divisions of the view. This includes all events that start and end on the day being shown.
e-day-view-top-item.c: draws the events that span for more than one day, and which are displayed at the top of the view, out of the time divisions.
e-day-view-config.c: manages the configuration of the day view.
EWeekView: implements the week and month views. It is, as the day view, separated into different files:
e-week-view: implements the view itself.
e-week-view-event-item.c: displays the background, times and icons for an event in the week/month views.
e-week-view-main-item.c: displays the background grid and dates for the Week and Month calendar views.
e-week-view-titles-item.c: displays the week day names at the top of the Month calendar view
e-week-view-layout.c: Lays out events for the Week & Month views of the calendar. It is also used for printing.
e-week-view-config.c: manages the configuration of the week view.
ECalListView: implements the list view, and is all done in a single file, e-calendar-view.c.
Both EDayView and EWeekView are based on GnomeCanvas, and thus all the e*view-*item* files implement the different canvas items that are drawn in the view/canvas.
For storing the data coming from the calendar backends, views use ECalModel-based classes, which in turn is based on ETreeModel, from GAL. The model is implemented as an array of components, having a separated field in a specific column of the array, which allows access to individual fields' values. There are 2 implementations of the ECalModel interface:
ECalModelCalendar: implements the model for calendar events.
ECalModelTasks: implements the model for tasks.
Calendar and task editors
The calendar and task editors use the same architecture, which is supported by two base classes:
comp-editor.c: base class for editor windows.
comp-editor-page.c: base class for editor pages.
There are, on top of that, many classes based on those two generic ones. First of all, there is EventEditor and TaskEditor, which implement, on top of CompEditor, the editors for events and tasks, respectively. The CompEditor base class contains virtual methods that need to be implemented by the subclasses. These are the following:
set_e_cal: used to set the calendar client to save the edited component to.
edit_comp: used when initializing the edition of a component. Implementors need to create the pages the editor is going to use.
send_comp: used when sending a component via email (for iTiP).
On the other hand, CompEditorPage provides an interface for editor pages. This interface contains the following virtual methods, that need to be implemented by pages.
get_widget: used to retrieve the GtkWidget used to implement the page.
focus_main_widget: used to set the focus to the main widget of the page.
fill_widget: used to fill the widgets on the page with values from an ECalComponent.
fill_component: used to fill an ECalComponent with the values from the page's widgets.
fill_timezones: used to populate a GHashTable with all the timezones being used in the page for dates.
set_summary: used to change the summary of the component being edited. Page implementations will change, accordingly, the values on the widgets using the summary text.
set_dates: used to change the dates used in the page.
This interface is implemented by several classes, some for the event editor, some others for the task editor:
- Event editor:
event-page.c: implements the event details page.
recurrence-page.c: implements the recurrenge page, where users can set recurrence rules for recurring appointments.
meeting-page.c: implements the invitations page.
schedule-page.c: implements the scheduling page, where we show the F/B information for attendees to meetings.
- Task editor:
task-page.c: implements the main task page, where the basics, like summary, can be set.
task-details-page.c: implements the extended details page for tasks.
The alarm daemon is the responsible to fire the alarms set up by the user in the calendar/tasks managed by Evolution.
Its mode of operation is very simple. When starting (notify-main.c), it creates the alarm notification CORBA service (alarm-notify.c), which in turn looks at all the available calendar and tasks sources, and adds them to the alarm queue (alarm-queue.c). The alarm queue, for each client added, retrieves all pending alarms since the last notification (/apps/evolution/calendar/notify/last_notification_time GConf entry) until midnight of the current day. Each alarm is sent to the alarm scheduler, which notifies a specific callback when the trigger for the alarm has been reached. At that time, the alarm queue, depending on the kind of alarm, it would display it (alarm-notify-dialog.c), run a specified program, play a sound or send an email.
Alarms are setup by using the alarm scheduler (alarm.c), which allow the addition and removal of alarms. Once alarms are added, the alarm scheduler runs a timeout function which, in short intervals, looks for pending alarms