Add ISO week dates to the calendar

This patch adds ISO week dates to the calendar. Week dates are an
often used feature in business and government offices. Can be turned
on through gconf, off by default.

https://bugzilla.gnome.org/show_bug.cgi?id=603532
This commit is contained in:
Raphael Bosshard 2010-05-27 09:31:46 +02:00 committed by Florian Müllner
parent 155bee388d
commit e3eaa69948
4 changed files with 112 additions and 12 deletions

View File

@ -438,6 +438,20 @@
</locale>
</schema>
<!-- Calendar -->
<schema>
<key>/schemas/desktop/gnome/shell/calendar/show_weekdate</key>
<applyto>/desktop/gnome/shell/calendar/show_weekdate</applyto>
<owner>gnome-shell</owner>
<type>bool</type>
<default>false</default>
<locale name="C">
<short>Show the week date in the calendar</short>
<long>
If true, display the ISO week date in the calendar.
</long>
</locale>
</schema>
</schemalist>
</gconfschemafile>

View File

@ -899,6 +899,10 @@ StTooltip {
padding: 0px 4px 2px 0px;
}
.calendar-calendarweek {
color: #666666;
}
/* App Switcher */
#altTabPopup {
padding: 8px;

View File

@ -3,10 +3,14 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const St = imports.gi.St;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const Gettext_gtk20 = imports.gettext.domain('gtk20');
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const MSECS_IN_WEEK = MSECS_IN_DAY * 7;
const WEEKDATE_HEADER_WIDTH_DIGITS = 3;
const SHOW_WEEKDATE_KEY = 'calendar/show_weekdate';
function _sameDay(dateA, dateB) {
return (dateA.getDate() == dateB.getDate() &&
@ -14,6 +18,24 @@ function _sameDay(dateA, dateB) {
dateA.getYear() == dateB.getYear());
}
function _getCalendarWeekForDate(date) {
let startOfYear = new Date(date.getFullYear(), 0, 1);
let sday = startOfYear.getDay();
let offset = 4 + (7 * Math.floor(sday * (1/5))) - sday;
let firstThursday = new Date(date.getFullYear(), 0, 1 + offset);
let weekOfYear = Math.ceil((date.getTime() - firstThursday.getTime()) / MSECS_IN_WEEK);
return weekOfYear;
}
function _getDigitWidth(actor){
let context = actor.get_pango_context();
let themeNode = actor.get_theme_node();
let font = themeNode.get_font();
let metrics = context.get_metrics(font, context.get_language());
let width = metrics.get_approximate_digit_width();
return width;
}
function Calendar() {
this._init();
}
@ -24,6 +46,13 @@ Calendar.prototype = {
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
// should add a C function so we can do the full handling.
this._weekStart = NaN;
this._weekdate = NaN;
this._digitWidth = NaN;
this._gconf = Shell.GConf.get_default();
this._gconf.connect('changed', Lang.bind(this, this._onSettingsChange));
this._useWeekdate = this._gconf.get_boolean(SHOW_WEEKDATE_KEY);
let weekStartString = Gettext_gtk20.gettext('calendar:week_start:0');
if (weekStartString.indexOf('calendar:week_start:') == 0) {
this._weekStart = parseInt(weekStartString.substring(20));
@ -58,11 +87,28 @@ Calendar.prototype = {
this.actor.connect('scroll-event',
Lang.bind(this, this._onScroll));
this._buildHeader ();
this._update();
},
// Sets the calendar to show a specific date
setDate: function(date) {
if (!_sameDay(date, this.date)) {
this.date = date;
this._update();
}
},
_buildHeader: function() {
let offsetCols = this._useWeekdate ? 1 : 0;
this.actor.destroy_children();
// Top line of the calendar '<| September 2009 |>'
this._topBox = new St.BoxLayout();
this.actor.add(this._topBox,
{ row: 0, col: 0, col_span: 7 });
{ row: 0, col: 0, col_span: offsetCols + 7 });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChange));
let [backlabel, forwardlabel] = ['&lt;', '&gt;'];
if (St.Widget.get_default_direction () == St.TextDirection.RTL) {
[backlabel, forwardlabel] = [forwardlabel, backlabel];
@ -85,25 +131,39 @@ Calendar.prototype = {
let iter = new Date(this.date);
iter.setSeconds(0); // Leap second protection. Hah!
iter.setHours(12);
if (this._useWeekdate) {
this._weekdateHeader = new St.Label();
this.actor.add(this._weekdateHeader,
{ row: 1,
col: 0,
x_fill: false, x_align: St.Align.MIDDLE });
this._setWeekdateHeaderWidth();
} else {
this._weekdateHeader = null;
}
for (let i = 0; i < 7; i++) {
this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }),
{ row: 1,
col: (7 + iter.getDay() - this._weekStart) % 7,
col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END });
iter.setTime(iter.getTime() + MSECS_IN_DAY);
}
// All the children after this are days, and get removed when we update the calendar
this._firstDayIndex = this.actor.get_children().length;
this._update();
},
// Sets the calendar to show a specific date
setDate: function(date) {
if (!_sameDay(date, this.date)) {
this.date = date;
this._update();
_onStyleChange: function(actor, event) {
// width of a digit in pango units
this._digitWidth = _getDigitWidth(this.actor) / Pango.SCALE;
this._setWeekdateHeaderWidth();
},
_setWeekdateHeaderWidth: function() {
if (this.digitWidth != NaN && this._useWeekdate && this._weekdateHeader) {
this._weekdateHeader.set_width (this._digitWidth * WEEKDATE_HEADER_WIDTH_DIGITS);
}
},
@ -140,6 +200,12 @@ Calendar.prototype = {
this._update();
},
_onSettingsChange: function() {
this._useWeekdate = this._gconf.get_boolean(SHOW_WEEKDATE_KEY);
this._buildHeader();
this._update();
},
_update: function() {
this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat);
@ -166,10 +232,20 @@ Calendar.prototype = {
label.style_class = 'calendar-day calendar-other-month-day';
else
label.style_class = 'calendar-day';
let offsetCols = this._useWeekdate ? 1 : 0;
this.actor.add(label,
{ row: row, col: (7 + iter.getDay() - this._weekStart) % 7,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END });
if (this._useWeekdate && iter.getDay() == 4) {
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
style_class: 'calendar-day calendar-calendarweek'});
this.actor.add(label,
{ row: row, col: 0,
x_fill: false, x_align: St.Align.MIDDLE });
}
iter.setTime(iter.getTime() + MSECS_IN_DAY);
if (iter.getDay() == this._weekStart) {
// We stop on the first "first day of the week" after the month we are displaying

View File

@ -1268,6 +1268,7 @@ CalendarPopup.prototype = {
Main.chrome.addActor(this.actor, { visibleInOverview: true,
affectsStruts: false });
this.actor.y = (panelActor.y + panelActor.height - this.actor.height);
this.calendar.actor.connect('notify::width', Lang.bind(this, this._centerPopup));
},
show: function() {
@ -1276,7 +1277,7 @@ CalendarPopup.prototype = {
// Reset the calendar to today's date
this.calendar.setDate(new Date());
this.actor.x = Math.round(panelActor.x + (panelActor.width - this.actor.width) / 2);
this._centerPopup();
this.actor.lower(panelActor);
this.actor.show();
Tweener.addTween(this.actor,
@ -1296,5 +1297,10 @@ CalendarPopup.prototype = {
onComplete: function() { this.actor.hide(); },
onCompleteScope: this
});
},
_centerPopup: function() {
let panelActor = Main.panel.actor;
this.actor.x = Math.round(panelActor.x + (panelActor.width - this.actor.width) / 2);
}
};