2011-09-28 09:16:26 -04:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2011-01-28 16:35:46 -05:00
|
|
|
|
|
|
|
const GLib = imports.gi.GLib;
|
|
|
|
const Gio = imports.gi.Gio;
|
2011-08-21 03:31:16 -04:00
|
|
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
2014-10-01 17:28:14 -04:00
|
|
|
const GObject = imports.gi.GObject;
|
2011-01-28 16:35:46 -05:00
|
|
|
const Lang = imports.lang;
|
|
|
|
const Mainloop = imports.mainloop;
|
|
|
|
const Cairo = imports.cairo;
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
|
|
const Shell = imports.gi.Shell;
|
|
|
|
const St = imports.gi.St;
|
2012-02-27 11:31:10 -05:00
|
|
|
const Atk = imports.gi.Atk;
|
2011-01-28 16:35:46 -05:00
|
|
|
|
2011-08-22 14:21:51 -04:00
|
|
|
const Params = imports.misc.params;
|
2011-01-28 16:35:46 -05:00
|
|
|
const Util = imports.misc.util;
|
|
|
|
const Main = imports.ui.main;
|
|
|
|
const PanelMenu = imports.ui.panelMenu;
|
|
|
|
const PopupMenu = imports.ui.popupMenu;
|
|
|
|
const Calendar = imports.ui.calendar;
|
|
|
|
|
2014-06-13 13:09:30 -04:00
|
|
|
function _onVertSepRepaint(area) {
|
2011-01-28 16:35:46 -05:00
|
|
|
let cr = area.get_context();
|
|
|
|
let themeNode = area.get_theme_node();
|
|
|
|
let [width, height] = area.get_surface_size();
|
2011-02-14 09:20:22 -05:00
|
|
|
let stippleColor = themeNode.get_color('-stipple-color');
|
2011-01-28 16:35:46 -05:00
|
|
|
let stippleWidth = themeNode.get_length('-stipple-width');
|
|
|
|
let x = Math.floor(width/2) + 0.5;
|
|
|
|
cr.moveTo(x, 0);
|
|
|
|
cr.lineTo(x, height);
|
|
|
|
Clutter.cairo_set_source_color(cr, stippleColor);
|
|
|
|
cr.setDash([1, 3], 1); // Hard-code for now
|
|
|
|
cr.setLineWidth(stippleWidth);
|
|
|
|
cr.stroke();
|
2013-01-07 15:07:40 -05:00
|
|
|
cr.$dispose();
|
2014-06-13 13:09:30 -04:00
|
|
|
}
|
2011-01-28 16:35:46 -05:00
|
|
|
|
2011-11-20 09:38:48 -05:00
|
|
|
const DateMenuButton = new Lang.Class({
|
|
|
|
Name: 'DateMenuButton',
|
|
|
|
Extends: PanelMenu.Button,
|
2011-01-28 16:35:46 -05:00
|
|
|
|
2012-05-17 18:32:04 -04:00
|
|
|
_init: function() {
|
2011-01-28 16:35:46 -05:00
|
|
|
let item;
|
|
|
|
let hbox;
|
|
|
|
let vbox;
|
|
|
|
|
2011-02-18 18:09:01 -05:00
|
|
|
let menuAlignment = 0.25;
|
2012-02-13 20:37:28 -05:00
|
|
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
2011-02-18 18:09:01 -05:00
|
|
|
menuAlignment = 1.0 - menuAlignment;
|
2011-11-20 09:38:48 -05:00
|
|
|
this.parent(menuAlignment);
|
2011-01-28 16:35:46 -05:00
|
|
|
|
2013-08-03 08:30:46 -04:00
|
|
|
this._clockDisplay = new St.Label({ y_align: Clutter.ActorAlign.CENTER });
|
2013-08-27 09:44:46 -04:00
|
|
|
this.actor.label_actor = this._clockDisplay;
|
2011-08-21 03:31:16 -04:00
|
|
|
this.actor.add_actor(this._clockDisplay);
|
2013-08-07 14:35:56 -04:00
|
|
|
this.actor.add_style_class_name ('clock-display');
|
2011-01-28 16:35:46 -05:00
|
|
|
|
2013-07-15 20:00:41 -04:00
|
|
|
hbox = new St.BoxLayout({ name: 'calendarArea' });
|
|
|
|
this.menu.box.add_child(hbox);
|
2011-01-28 16:35:46 -05:00
|
|
|
|
|
|
|
// Fill up the first column
|
|
|
|
|
|
|
|
vbox = new St.BoxLayout({vertical: true});
|
|
|
|
hbox.add(vbox);
|
|
|
|
|
|
|
|
// Date
|
2014-03-19 10:23:05 -04:00
|
|
|
// Having the ability to go to the current date if the user is already
|
|
|
|
// on the current date can be confusing. So don't make the button reactive
|
|
|
|
// until the selected date changes.
|
2012-01-16 07:01:18 -05:00
|
|
|
this._date = new St.Button({ style_class: 'datemenu-date-label',
|
2014-03-19 10:23:05 -04:00
|
|
|
reactive: false
|
2012-01-16 07:01:18 -05:00
|
|
|
});
|
|
|
|
this._date.connect('clicked',
|
|
|
|
Lang.bind(this, function() {
|
|
|
|
this._calendar.setDate(new Date(), false);
|
|
|
|
}));
|
|
|
|
vbox.add(this._date, { x_fill: false });
|
2011-01-28 16:35:46 -05:00
|
|
|
|
2012-09-01 08:42:53 -04:00
|
|
|
this._eventList = new Calendar.EventsList();
|
|
|
|
this._calendar = new Calendar.Calendar();
|
2011-08-22 14:21:51 -04:00
|
|
|
|
2011-01-28 16:35:46 -05:00
|
|
|
this._calendar.connect('selected-date-changed',
|
|
|
|
Lang.bind(this, function(calendar, date) {
|
|
|
|
this._eventList.setDate(date);
|
2014-03-19 10:23:05 -04:00
|
|
|
|
|
|
|
// Make the button reactive only if the selected date is not the current date.
|
|
|
|
this._date.can_focus = this._date.reactive = !this._isToday(date)
|
2011-01-28 16:35:46 -05:00
|
|
|
}));
|
|
|
|
vbox.add(this._calendar.actor);
|
|
|
|
|
2012-12-21 16:54:20 -05:00
|
|
|
let separator = new PopupMenu.PopupSeparatorMenuItem();
|
2013-06-08 12:31:30 -04:00
|
|
|
vbox.add(separator.actor, { y_align: St.Align.END, expand: true, y_fill: false });
|
2012-12-21 16:54:20 -05:00
|
|
|
|
|
|
|
this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
|
|
|
this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
|
|
|
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
|
|
|
|
2012-12-15 05:30:03 -05:00
|
|
|
this._openClocksItem = new PopupMenu.PopupMenuItem(_("Open Clocks"));
|
|
|
|
this._openClocksItem.connect('activate', Lang.bind(this, this._onOpenClocksActivate));
|
|
|
|
vbox.add(this._openClocksItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
|
|
|
|
|
|
|
Shell.AppSystem.get_default().connect('installed-changed',
|
|
|
|
Lang.bind(this, this._appInstalledChanged));
|
|
|
|
|
2013-02-05 08:54:16 -05:00
|
|
|
item = this.menu.addSettingsAction(_("Date & Time Settings"), 'gnome-datetime-panel.desktop');
|
2011-08-28 22:15:53 -04:00
|
|
|
if (item) {
|
2012-10-02 13:32:55 -04:00
|
|
|
item.actor.show_on_set_parent = false;
|
2011-08-28 22:15:53 -04:00
|
|
|
item.actor.reparent(vbox);
|
2012-10-02 13:32:55 -04:00
|
|
|
this._dateAndTimeSeparator = separator;
|
2011-08-28 22:15:53 -04:00
|
|
|
}
|
2011-01-28 16:35:46 -05:00
|
|
|
|
2012-09-01 08:42:53 -04:00
|
|
|
this._separator = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
|
|
|
pseudo_class: 'highlighted' });
|
|
|
|
this._separator.connect('repaint', Lang.bind(this, _onVertSepRepaint));
|
|
|
|
hbox.add(this._separator);
|
2011-01-28 16:35:46 -05:00
|
|
|
|
2012-09-01 08:42:53 -04:00
|
|
|
// Fill up the second column
|
2013-06-08 12:31:30 -04:00
|
|
|
hbox.add(this._eventList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
|
2011-01-28 16:35:46 -05:00
|
|
|
|
|
|
|
// Whenever the menu is opened, select today
|
|
|
|
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
|
|
|
if (isOpen) {
|
|
|
|
let now = new Date();
|
2013-12-11 19:58:42 -05:00
|
|
|
this._calendar.setDate(now);
|
2014-10-01 17:28:14 -04:00
|
|
|
|
|
|
|
/* Translators: This is the date format to use when the calendar popup is
|
|
|
|
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
|
|
|
|
*/
|
2014-11-08 11:45:13 -05:00
|
|
|
let dateFormat = Shell.util_translate_time_string (N_("%A %B %e, %Y"));
|
2014-10-01 17:28:14 -04:00
|
|
|
this._date.set_label(now.toLocaleFormat(dateFormat));
|
2011-01-28 16:35:46 -05:00
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
|
|
|
// Done with hbox for calendar and event list
|
|
|
|
|
2011-08-21 03:31:16 -04:00
|
|
|
this._clock = new GnomeDesktop.WallClock();
|
2014-10-01 17:28:14 -04:00
|
|
|
this._clock.bind_property('clock', this._clockDisplay, 'text', GObject.BindingFlags.SYNC_CREATE);
|
2012-09-01 08:42:53 -04:00
|
|
|
|
|
|
|
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
|
|
|
this._sessionUpdated();
|
|
|
|
},
|
|
|
|
|
2014-03-19 10:23:05 -04:00
|
|
|
_isToday: function(date) {
|
|
|
|
let now = new Date();
|
|
|
|
return now.getYear() == date.getYear() &&
|
|
|
|
now.getMonth() == date.getMonth() &&
|
2014-10-23 16:11:09 -04:00
|
|
|
now.getDate() == date.getDate();
|
2014-03-19 10:23:05 -04:00
|
|
|
},
|
|
|
|
|
2012-12-15 05:30:03 -05:00
|
|
|
_appInstalledChanged: function() {
|
2013-04-10 10:29:01 -04:00
|
|
|
this._calendarApp = undefined;
|
|
|
|
this._updateEventsVisibility();
|
2012-12-15 05:30:03 -05:00
|
|
|
},
|
|
|
|
|
2012-10-29 11:37:07 -04:00
|
|
|
_updateEventsVisibility: function() {
|
|
|
|
let visible = this._eventSource.hasCalendars;
|
2013-04-10 10:29:01 -04:00
|
|
|
this._openCalendarItem.actor.visible = visible &&
|
|
|
|
(this._getCalendarApp() != null);
|
|
|
|
this._openClocksItem.actor.visible = visible &&
|
|
|
|
(this._getClockApp() != null);
|
2012-09-01 08:42:53 -04:00
|
|
|
this._separator.visible = visible;
|
2013-06-24 15:03:29 -04:00
|
|
|
this._eventList.actor.visible = visible;
|
2012-10-02 13:32:55 -04:00
|
|
|
if (visible) {
|
2013-06-24 15:03:29 -04:00
|
|
|
let alignment = 0.25;
|
|
|
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
|
|
|
alignment = 1.0 - alignment;
|
|
|
|
this.menu._arrowAlignment = alignment;
|
2012-10-02 13:32:55 -04:00
|
|
|
} else {
|
2013-06-24 15:03:29 -04:00
|
|
|
this.menu._arrowAlignment = 0.5;
|
2012-10-02 13:32:55 -04:00
|
|
|
}
|
2012-09-01 08:42:53 -04:00
|
|
|
},
|
|
|
|
|
2012-03-21 03:59:39 -04:00
|
|
|
_getEventSource: function() {
|
|
|
|
return new Calendar.DBusEventSource();
|
|
|
|
},
|
|
|
|
|
2012-09-01 08:42:53 -04:00
|
|
|
_setEventSource: function(eventSource) {
|
2013-03-04 11:04:28 -05:00
|
|
|
if (this._eventSource)
|
|
|
|
this._eventSource.destroy();
|
|
|
|
|
2012-09-01 08:42:53 -04:00
|
|
|
this._calendar.setEventSource(eventSource);
|
|
|
|
this._eventList.setEventSource(eventSource);
|
2013-03-04 11:04:28 -05:00
|
|
|
|
|
|
|
this._eventSource = eventSource;
|
2012-10-29 11:37:07 -04:00
|
|
|
this._eventSource.connect('notify::has-calendars', Lang.bind(this, function() {
|
|
|
|
this._updateEventsVisibility();
|
|
|
|
}));
|
2012-09-01 08:42:53 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_sessionUpdated: function() {
|
|
|
|
let eventSource;
|
|
|
|
let showEvents = Main.sessionMode.showCalendarEvents;
|
|
|
|
if (showEvents) {
|
2012-03-21 03:59:39 -04:00
|
|
|
eventSource = this._getEventSource();
|
2012-09-01 08:42:53 -04:00
|
|
|
} else {
|
2013-03-04 11:04:28 -05:00
|
|
|
eventSource = new Calendar.EmptyEventSource();
|
2012-09-01 08:42:53 -04:00
|
|
|
}
|
|
|
|
this._setEventSource(eventSource);
|
2012-10-29 11:37:07 -04:00
|
|
|
this._updateEventsVisibility();
|
2012-10-02 13:32:55 -04:00
|
|
|
|
|
|
|
// This needs to be handled manually, as the code to
|
|
|
|
// autohide separators doesn't work across the vbox
|
|
|
|
this._dateAndTimeSeparator.actor.visible = Main.sessionMode.allowSettings;
|
2011-01-28 16:35:46 -05:00
|
|
|
},
|
|
|
|
|
2013-04-10 10:29:01 -04:00
|
|
|
_getCalendarApp: function() {
|
|
|
|
if (this._calendarApp !== undefined)
|
|
|
|
return this._calendarApp;
|
|
|
|
|
|
|
|
let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
|
2014-01-16 07:41:46 -05:00
|
|
|
if (apps && (apps.length > 0)) {
|
|
|
|
let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
|
|
|
|
let defaultInRecommended = apps.some(function(a) { return a.equal(app); });
|
|
|
|
this._calendarApp = defaultInRecommended ? app : apps[0];
|
|
|
|
} else {
|
2013-04-10 10:29:01 -04:00
|
|
|
this._calendarApp = null;
|
2014-01-16 07:41:46 -05:00
|
|
|
}
|
2013-04-10 10:29:01 -04:00
|
|
|
return this._calendarApp;
|
|
|
|
},
|
|
|
|
|
|
|
|
_getClockApp: function() {
|
2014-02-13 06:53:42 -05:00
|
|
|
return Shell.AppSystem.get_default().lookup_app('org.gnome.clocks.desktop');
|
2013-04-10 10:29:01 -04:00
|
|
|
},
|
|
|
|
|
2011-01-28 16:35:46 -05:00
|
|
|
_onOpenCalendarActivate: function() {
|
|
|
|
this.menu.close();
|
2012-12-24 19:29:18 -05:00
|
|
|
|
2013-04-10 10:29:01 -04:00
|
|
|
let app = this._getCalendarApp();
|
2013-04-26 02:35:22 -04:00
|
|
|
if (app.get_id() == 'evolution.desktop')
|
|
|
|
app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
|
2014-01-19 12:34:32 -05:00
|
|
|
app.launch([], global.create_app_launch_context(0, -1));
|
2012-12-15 05:30:03 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
_onOpenClocksActivate: function() {
|
|
|
|
this.menu.close();
|
2013-04-10 10:29:01 -04:00
|
|
|
let app = this._getClockApp();
|
2012-12-15 05:30:03 -05:00
|
|
|
app.activate();
|
2011-03-14 09:05:59 -04:00
|
|
|
}
|
2011-11-20 09:38:48 -05:00
|
|
|
});
|