home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / sunbird / js / calMonthGridPrinter.js < prev    next >
Encoding:
JavaScript  |  2007-05-23  |  14.4 KB  |  372 lines

  1. /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  * ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is Mozilla Calendar code.
  16.  *
  17.  * The Initial Developer of the Original Code is
  18.  *   Joey Minta <jminta@gmail.com>
  19.  * Portions created by the Initial Developer are Copyright (C) 2006
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *   Matthew Willis <mattwillis@gmail.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. /**
  40.  * Prints a rough month-grid of events/tasks
  41.  */
  42.  
  43. function calMonthPrinter() {
  44.     this.wrappedJSObject = this;
  45. }
  46.  
  47. calMonthPrinter.prototype.QueryInterface =
  48. function QueryInterface(aIID) {
  49.     if (!aIID.equals(Components.interfaces.nsISupports) &&
  50.         !aIID.equals(Components.interfaces.calIPrintFormatter)) {
  51.         throw Components.results.NS_ERROR_NO_INTERFACE;
  52.     }
  53.  
  54.     return this;
  55. };
  56.  
  57. calMonthPrinter.prototype.getName =
  58. function monthPrint_getName() {
  59.     return calGetString("calendar", "monthPrinterName");
  60. };
  61. calMonthPrinter.prototype.__defineGetter__("name", calMonthPrinter.prototype.getName);
  62.  
  63. calMonthPrinter.prototype.formatToHtml =
  64. function monthPrint_format(aStream, aStart, aEnd, aCount, aItems, aTitle) {
  65.     var html = <html/>
  66.     html.appendChild(
  67.             <head>
  68.                 <title>{aTitle}</title>
  69.                 <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>
  70.                 <style type='text/css'/>
  71.             </head>);
  72.     html.head.style = ".main-table { font-size: 26px; font-weight: bold; }\n";
  73.     html.head.style += ".day-name { border: 1px solid black; background-color: #e0e0e0; font-size: 12px; font-weight: bold; }\n";
  74.     html.head.style += ".day-box { border: 1px solid black; vertical-align: top; }\n";
  75.     html.head.style += ".out-of-month { background-color: gray !important; }\n";
  76.     html.head.style += ".day-off { background-color: #D3D3D3 !important; }\n";
  77.  
  78.     // If aStart or aEnd weren't passed in, we need to calculate them based on
  79.     // aItems data.
  80.  
  81.     var start = aStart;
  82.     var end = aEnd;
  83.     if (!start || !end) {
  84.         for each (var item in aItems) {
  85.             var itemStart = item.startDate || item.entryDate;
  86.             var itemEnd = item.endDate || item.dueDate;
  87.             if (!start || (itemStart && start.compare(itemStart) == 1)) {
  88.                 start = itemStart;
  89.             }
  90.             if (!end || (itemEnd && end.compare(itemEnd) == -1)) {
  91.                 end = itemEnd;
  92.             }
  93.         }
  94.     }
  95.  
  96.     // Play around with aStart and aEnd to determine the minimal number of
  97.     // months we can show to still technically meet their requirements.  This
  98.     // is most useful when someone printed 'Current View' in the month view. If
  99.     // we take the aStart and aEnd literally, we'll print 3 months (because of
  100.     // the extra days at the start/end), but we should avoid that.
  101.     //
  102.     // Basically, we check whether aStart falls in the same week as the start
  103.     // of a month (ie aStart  is Jan 29, which often is in the same week as
  104.     // Feb 1), and similarly whether aEnd falls in the same week as the end of
  105.     // a month.
  106.     var weekStart = getPrefSafe("calendar.week.start", 0);
  107.     maybeNewStart = start.clone();
  108.     maybeNewStart.day = 1;
  109.     maybeNewStart.month = start.month+1;
  110.     maybeNewStart.normalize();
  111.  
  112.     var date = start.clone();
  113.  
  114.     // First we have to adjust the end date for comparison, as the
  115.     // provided end date is exclusive, i.e. will not be displayed.
  116.  
  117.     var realEnd = end.clone();
  118.     realEnd.day -= 1;
  119.     realEnd.normalize();
  120.  
  121.     if (start.compare(realEnd) <= 0) {
  122.         // Only adjust dates if start date is earlier than end date.
  123.  
  124.         if ((start.month != realEnd.month) || (start.year != realEnd.year)) {
  125.             // We only need to adjust if start and end are in different months.
  126.  
  127.             // We want to check whether or not the start day is in the same
  128.             // week as the beginning of the next month. To do this, we take
  129.             // the start date, add seven days and subtract the "day of week"
  130.             // value (which has to be corrected in case we do not start on
  131.             // Sunday).
  132.             var testBegin = start.clone();
  133.             var startWeekday = testBegin.weekday;
  134.             if (startWeekday < weekStart) {
  135.                 startWeekday += 7;
  136.                 startWeekday.normalize();
  137.             }
  138.             testBegin.day += 7 + weekStart - startWeekday;
  139.             testBegin.normalize();
  140.             if (testBegin.compare(maybeNewStart) > 0) {
  141.                 start = maybeNewStart;
  142.                 date = start.clone();
  143.             }
  144.         }
  145.         if ((start.month != realEnd.month) || (start.year != realEnd.year)) {
  146.             // We only need to adjust if start and end are in different months.
  147.  
  148.             // Next, we want to check whether or not the end day is in the same
  149.             // week as the end of the previous month. So we have to get the
  150.             // "day of week" value for the end of the previous month, adjust it
  151.             // if necessary (when start of week is not Sunday) and check if the
  152.             // end day is in the same week.
  153.  
  154.             var lastDayOfPreviousMonth = end.clone();
  155.             lastDayOfPreviousMonth.day = 0;
  156.             lastDayOfPreviousMonth.normalize();
  157.             var lastDayWeekday = lastDayOfPreviousMonth.weekday;
  158.             if (lastDayWeekday < weekStart) {
  159.                 lastDayWeekday += 7;
  160.                 lastDayWeekday.normalize();
  161.             }
  162.             if (date.month != end.month) {
  163.                 date.day = 1;
  164.                 date.normalize();
  165.             }
  166.             if ((lastDayWeekday + end.day - 1) < (7 + weekStart)) {
  167.                 date.day = end.day;
  168.                 date.normalize();
  169.             }
  170.  
  171.             // Finally, we have to check whether we adjusted the dates too
  172.             // well so that nothing is printed. That happens if you print just
  173.             // one week which has the last day of a month in it.
  174.  
  175.             if (date.compare(end) >= 0) {
  176.                 date.day = 1;
  177.                 date.normalize();
  178.             }
  179.         } else {
  180.             date.day = 1;
  181.             date.normalize();
  182.         }
  183.     } else {
  184.          // If start date is after end date, just print empty month.
  185.          date = realEnd.clone();
  186.     }
  187.  
  188.     var body = <body/>
  189.  
  190.     while (date.compare(end) < 0) {
  191.         var monthName = calGetString("dateFormat", "month." + (date.month +1)+ ".name");
  192.         monthName += " " + date.year;
  193.         body.appendChild(
  194.                      <table border='0' width='100%' class='main-table'>
  195.                          <tr> 
  196.                              <td align='center' valign='bottom'>{monthName}</td>
  197.                          </tr>
  198.                      </table>);
  199.         body.appendChild(this.getStringForMonth(date, aItems));
  200.         // Make sure each month gets put on its own page
  201.         body.appendChild(<br style="page-break-after:always;"/>);
  202.         date.month++;
  203.         date.normalize();
  204.     }
  205.     html.appendChild(body);
  206.  
  207.     var convStream = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
  208.                                .getService(Components.interfaces.nsIConverterOutputStream);
  209.     convStream.init(aStream, 'UTF-8', 0, 0x0000);
  210.     convStream.writeString(html.toXMLString());
  211. };
  212.  
  213. calMonthPrinter.prototype.getStringForMonth =
  214. function monthPrint_getHTML(aStart, aItems) {
  215.     var weekStart = getPrefSafe("calendar.week.start", 0);
  216.  
  217.     var monthTable = <table style='border:1px solid black;' width='100%'/>
  218.     var dayNameRow = <tr/>
  219.     for (var i = 0; i < 7; i++) {
  220.         var dayName = calGetString("dateFormat", "day."+ (((weekStart+i)%7)+1) + ".Mmm");
  221.         dayNameRow.appendChild(<td class='day-name' align='center'>{dayName}</td>);
  222.     }
  223.     monthTable.appendChild(dayNameRow);
  224.  
  225.     // Set up the item-list so it's easy to work with.
  226.     function hasUsableDate(item) {
  227.         return item.startDate || item.entryDate || item.dueDate;
  228.     }
  229.     var filteredItems = aItems.filter(hasUsableDate);
  230.  
  231.     var calIEvent = Components.interfaces.calIEvent;
  232.     var calITodo = Components.interfaces.calITodo
  233.     function compareItems(a, b) {
  234.         // Sort tasks before events
  235.         if (a instanceof calIEvent && b instanceof calITodo) {
  236.             return 1;
  237.         }
  238.         if (a instanceof calITodo && b instanceof calIEvent) {
  239.             return -1;
  240.         }
  241.         if (a instanceof calIEvent) {
  242.             var startCompare = a.startDate.compare(b.startDate);
  243.             if (startCompare != 0) {
  244.                 return startCompare;
  245.             }
  246.             return a.endDate.compare(b.endDate);
  247.         }
  248.         var aDate = a.entryDate || a.dueDate;
  249.         var bDate = b.entryDate || b.dueDate;
  250.         return aDate.compare(bDate);
  251.     }
  252.     var sortedList = filteredItems.sort(compareItems);
  253.     var firstDate = aStart.startOfMonth.startOfWeek.clone();
  254.     firstDate.day += weekStart;
  255.     firstDate.normalize();
  256.     if (aStart.startOfMonth.weekday < weekStart) {
  257.         // Go back one week to make sure we display this day
  258.         firstDate.day -= 7;
  259.         firstDate.normalize();
  260.     }
  261.  
  262.     var lastDate = aStart.endOfMonth.endOfWeek.clone();
  263.     if (aStart.endOfMonth.weekday < weekStart) {
  264.         // Go back one week so we don't display any extra days
  265.         lastDate.day -= 7;
  266.         lastDate.normalize();
  267.     }
  268.     firstDate.isDate = true;
  269.     lastDate.isDate = true;
  270.  
  271.     var date = firstDate.clone();
  272.     var itemListIndex = 0;
  273.     while (date.compare(lastDate) != 1) {
  274.         monthTable.appendChild(this.makeHTMLWeek(date, sortedList, aStart.month));
  275.     }
  276.     return monthTable;
  277. };
  278.  
  279. calMonthPrinter.prototype.makeHTMLWeek =
  280. function makeHTMLWeek(date, sortedList, targetMonth) {
  281.     var weekRow = <tr/>;
  282.     const weekPrefix = "calendar.week.";
  283.     var prefNames = ["d0sundaysoff", "d1mondaysoff", "d2tuesdaysoff",
  284.                      "d3wednesdaysoff", "d4thursdaysoff", "d5fridaysoff", "d6saturdaysoff"];
  285.     var defaults = [true, false, false, false, false, false, true];
  286.     var daysOff = new Array();
  287.     for (var i in prefNames) {
  288.         if (getPrefSafe(weekPrefix+prefNames[i], defaults[i])) {
  289.             daysOff.push(Number(i));
  290.         }
  291.     }
  292.  
  293.     for (var i = 0; i < 7; i++) {
  294.         var myClass = 'day-box';
  295.         if (date.month != targetMonth) {
  296.             myClass += ' out-of-month';
  297.         } else if (daysOff.some(function(a) { return a == date.weekday; })) {
  298.             myClass += ' day-off';
  299.         }
  300.         var day = <td align='left' valign='top' class={myClass} height='100' width='100'/>
  301.         var innerTable = <table valign='top' style='font-size: 10px;'/>
  302.         var dateLabel = <tr valign='top'>
  303.                             <td valign='top' align='left'>{date.day}</td>
  304.                         </tr>
  305.         innerTable.appendChild(dateLabel);
  306.         for each (var item in sortedList) {
  307.             var sDate = item.startDate || item.entryDate || item.dueDate;
  308.             var eDate = item.endDate || item.dueDate || item.entryDate;
  309.  
  310.             // end dates are exclusive
  311.             if (sDate.isDate) {
  312.                 eDate = eDate.clone();
  313.                 eDate.day -= 1;
  314.                 eDate.normalize();
  315.             }
  316.             if (!eDate || eDate.compare(date) == -1) {
  317.                 continue;
  318.             }
  319.             itemListIndex = i;
  320.             if (!sDate || sDate.compare(date) == 1) {
  321.                 break;
  322.             }
  323.             var dateFormatter = 
  324.                     Components.classes["@mozilla.org/calendar/datetime-formatter;1"]
  325.                               .getService(Components.interfaces.calIDateTimeFormatter);
  326.  
  327.  
  328.             function getStringForDate(date) {
  329.                 var dstring;
  330.                 if (!date.isDate) {
  331.                     return dateFormatter.formatTime(sDate);
  332.                 }
  333.                 return calGetString("dateFormat", "AllDay");
  334.             }
  335.  
  336.             var time;
  337.             if (sDate) {
  338.                 time = getStringForDate(sDate);
  339.             }
  340.  
  341.             var calMgr = Components.classes["@mozilla.org/calendar/manager;1"]
  342.                                    .getService(Components.interfaces.calICalendarManager);
  343.             var calColor = calMgr.getCalendarPref(item.calendar, 'color');
  344.             if (!calColor) {
  345.                 calColor = "#A8C2E1";
  346.             }
  347.             var pb2 = Components.classes["@mozilla.org/preferences-service;1"]
  348.                                 .getService(Components.interfaces.nsIPrefBranch2);
  349.             var catColor;
  350.             try {
  351.                 catColor = pb2.getCharPref("calendar.category.color."+item.getProperty("CATEGORIES").toLowerCase());
  352.             } catch(ex) {}
  353.  
  354.             var style = 'font-size: 11px; text-align: left;';
  355.             style += ' background-color: ' + calColor + ';';
  356.             style += ' color: ' + getContrastingTextColor(calColor);
  357.             if (catColor) {
  358.                 style += ' border: solid ' + catColor + ' 2px;';
  359.             }
  360.             var item = <tr>
  361.                            <td valign='top' style={style}>{time} {item.title}</td>
  362.                        </tr>;
  363.             innerTable.appendChild(item);
  364.         }
  365.         day.appendChild(innerTable);
  366.         weekRow.appendChild(day);
  367.         date.day++;
  368.         date.normalize();
  369.     }
  370.     return weekRow;
  371. };
  372.