[gnome-shell] Add ISO week dates to the calendar



commit e3eaa699481b9b48e12f2d5a10baab3aed9f8acf
Author: Raphael Bosshard <raphael bosshard gmail com>
Date:   Thu May 27 09:31:46 2010 +0200

    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

 data/gnome-shell.schemas   |   14 ++++++
 data/theme/gnome-shell.css |    4 ++
 js/ui/calendar.js          |   96 +++++++++++++++++++++++++++++++++++++++-----
 js/ui/panel.js             |    8 +++-
 4 files changed, 111 insertions(+), 11 deletions(-)
---
diff --git a/data/gnome-shell.schemas b/data/gnome-shell.schemas
index 8e5c91f..434986f 100644
--- a/data/gnome-shell.schemas
+++ b/data/gnome-shell.schemas
@@ -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>
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index bee6c9f..c34ae63 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -899,6 +899,10 @@ StTooltip {
     padding: 0px 4px 2px 0px;
 }
 
+.calendar-calendarweek {
+    color: #666666;
+}
+
 /* App Switcher */
 #altTabPopup {
     padding: 8px;
diff --git a/js/ui/calendar.js b/js/ui/calendar.js
index 8122e50..080ab1d 100644
--- a/js/ui/calendar.js
+++ b/js/ui/calendar.js
@@ -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();
+    _onStyleChange: function(actor, event) {
+        // width of a digit in pango units
+        this._digitWidth = _getDigitWidth(this.actor) / Pango.SCALE;
+        this._setWeekdateHeaderWidth();
     },
 
-    // Sets the calendar to show a specific date
-    setDate: function(date) {
-        if (!_sameDay(date, this.date)) {
-            this.date = date;
-            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();
     },
 
+    _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
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 58e1d5f..0a6a484 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -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);
     }
 };



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]