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:
parent
155bee388d
commit
e3eaa69948
@ -438,6 +438,20 @@
|
|||||||
</locale>
|
</locale>
|
||||||
</schema>
|
</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>
|
</schemalist>
|
||||||
|
|
||||||
</gconfschemafile>
|
</gconfschemafile>
|
||||||
|
@ -899,6 +899,10 @@ StTooltip {
|
|||||||
padding: 0px 4px 2px 0px;
|
padding: 0px 4px 2px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.calendar-calendarweek {
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
/* App Switcher */
|
/* App Switcher */
|
||||||
#altTabPopup {
|
#altTabPopup {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
@ -3,10 +3,14 @@
|
|||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
const Gettext_gtk20 = imports.gettext.domain('gtk20');
|
const Gettext_gtk20 = imports.gettext.domain('gtk20');
|
||||||
|
|
||||||
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
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) {
|
function _sameDay(dateA, dateB) {
|
||||||
return (dateA.getDate() == dateB.getDate() &&
|
return (dateA.getDate() == dateB.getDate() &&
|
||||||
@ -14,6 +18,24 @@ function _sameDay(dateA, dateB) {
|
|||||||
dateA.getYear() == dateB.getYear());
|
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() {
|
function Calendar() {
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
@ -24,6 +46,13 @@ Calendar.prototype = {
|
|||||||
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
|
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
|
||||||
// should add a C function so we can do the full handling.
|
// should add a C function so we can do the full handling.
|
||||||
this._weekStart = NaN;
|
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');
|
let weekStartString = Gettext_gtk20.gettext('calendar:week_start:0');
|
||||||
if (weekStartString.indexOf('calendar:week_start:') == 0) {
|
if (weekStartString.indexOf('calendar:week_start:') == 0) {
|
||||||
this._weekStart = parseInt(weekStartString.substring(20));
|
this._weekStart = parseInt(weekStartString.substring(20));
|
||||||
@ -58,11 +87,28 @@ Calendar.prototype = {
|
|||||||
this.actor.connect('scroll-event',
|
this.actor.connect('scroll-event',
|
||||||
Lang.bind(this, this._onScroll));
|
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 |>'
|
// Top line of the calendar '<| September 2009 |>'
|
||||||
this._topBox = new St.BoxLayout();
|
this._topBox = new St.BoxLayout();
|
||||||
this.actor.add(this._topBox,
|
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] = ['<', '>'];
|
let [backlabel, forwardlabel] = ['<', '>'];
|
||||||
if (St.Widget.get_default_direction () == St.TextDirection.RTL) {
|
if (St.Widget.get_default_direction () == St.TextDirection.RTL) {
|
||||||
[backlabel, forwardlabel] = [forwardlabel, backlabel];
|
[backlabel, forwardlabel] = [forwardlabel, backlabel];
|
||||||
@ -85,25 +131,39 @@ Calendar.prototype = {
|
|||||||
let iter = new Date(this.date);
|
let iter = new Date(this.date);
|
||||||
iter.setSeconds(0); // Leap second protection. Hah!
|
iter.setSeconds(0); // Leap second protection. Hah!
|
||||||
iter.setHours(12);
|
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++) {
|
for (let i = 0; i < 7; i++) {
|
||||||
this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }),
|
this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }),
|
||||||
{ row: 1,
|
{ 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 });
|
x_fill: false, x_align: St.Align.END });
|
||||||
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All the children after this are days, and get removed when we update the calendar
|
// All the children after this are days, and get removed when we update the calendar
|
||||||
this._firstDayIndex = this.actor.get_children().length;
|
this._firstDayIndex = this.actor.get_children().length;
|
||||||
|
|
||||||
this._update();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sets the calendar to show a specific date
|
_onStyleChange: function(actor, event) {
|
||||||
setDate: function(date) {
|
// width of a digit in pango units
|
||||||
if (!_sameDay(date, this.date)) {
|
this._digitWidth = _getDigitWidth(this.actor) / Pango.SCALE;
|
||||||
this.date = date;
|
this._setWeekdateHeaderWidth();
|
||||||
this._update();
|
},
|
||||||
|
|
||||||
|
_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();
|
this._update();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onSettingsChange: function() {
|
||||||
|
this._useWeekdate = this._gconf.get_boolean(SHOW_WEEKDATE_KEY);
|
||||||
|
this._buildHeader();
|
||||||
|
this._update();
|
||||||
|
},
|
||||||
|
|
||||||
_update: function() {
|
_update: function() {
|
||||||
this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat);
|
this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat);
|
||||||
|
|
||||||
@ -166,10 +232,20 @@ Calendar.prototype = {
|
|||||||
label.style_class = 'calendar-day calendar-other-month-day';
|
label.style_class = 'calendar-day calendar-other-month-day';
|
||||||
else
|
else
|
||||||
label.style_class = 'calendar-day';
|
label.style_class = 'calendar-day';
|
||||||
|
|
||||||
|
let offsetCols = this._useWeekdate ? 1 : 0;
|
||||||
this.actor.add(label,
|
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 });
|
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);
|
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
||||||
if (iter.getDay() == this._weekStart) {
|
if (iter.getDay() == this._weekStart) {
|
||||||
// We stop on the first "first day of the week" after the month we are displaying
|
// We stop on the first "first day of the week" after the month we are displaying
|
||||||
|
@ -1268,6 +1268,7 @@ CalendarPopup.prototype = {
|
|||||||
Main.chrome.addActor(this.actor, { visibleInOverview: true,
|
Main.chrome.addActor(this.actor, { visibleInOverview: true,
|
||||||
affectsStruts: false });
|
affectsStruts: false });
|
||||||
this.actor.y = (panelActor.y + panelActor.height - this.actor.height);
|
this.actor.y = (panelActor.y + panelActor.height - this.actor.height);
|
||||||
|
this.calendar.actor.connect('notify::width', Lang.bind(this, this._centerPopup));
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
@ -1276,7 +1277,7 @@ CalendarPopup.prototype = {
|
|||||||
// Reset the calendar to today's date
|
// Reset the calendar to today's date
|
||||||
this.calendar.setDate(new 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.lower(panelActor);
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
Tweener.addTween(this.actor,
|
Tweener.addTween(this.actor,
|
||||||
@ -1296,5 +1297,10 @@ CalendarPopup.prototype = {
|
|||||||
onComplete: function() { this.actor.hide(); },
|
onComplete: function() { this.actor.hide(); },
|
||||||
onCompleteScope: this
|
onCompleteScope: this
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_centerPopup: function() {
|
||||||
|
let panelActor = Main.panel.actor;
|
||||||
|
this.actor.x = Math.round(panelActor.x + (panelActor.width - this.actor.width) / 2);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user