Bug 1619732 - Make the iMIP bar work when calendar component is deactivated. r=darktrojan
authorPaul Morris <paul@thunderbird.net>
Wed, 11 Mar 2020 22:13:00 +0200
changeset 38470 44f5cf16dec6331c5b8e877063d3531ec8f3a15c
parent 38469 4a8fd4b3cb7479b4f503977b6543f382eb7b2496
child 38471 506be393d5ef8d60b287903bb8e0cb1fca37460e
push id400
push userclokep@gmail.com
push dateMon, 04 May 2020 18:56:09 +0000
reviewersdarktrojan
bugs1619732
Bug 1619732 - Make the iMIP bar work when calendar component is deactivated. r=darktrojan
calendar/base/content/dialogs/calendar-properties-dialog.xhtml
calendar/base/modules/calCalendarDeactivator.jsm
calendar/base/modules/utils/calItipUtils.jsm
calendar/base/themes/common/lightning.css
calendar/lightning/content/imip-bar-overlay.inc.xhtml
calendar/lightning/content/imip-bar.js
calendar/lightning/content/lightning.js
calendar/locales/en-US/chrome/calendar/calendar.dtd
calendar/locales/en-US/chrome/lightning/lightning.dtd
calendar/locales/en-US/chrome/lightning/lightning.properties
--- a/calendar/base/content/dialogs/calendar-properties-dialog.xhtml
+++ b/calendar/base/content/dialogs/calendar-properties-dialog.xhtml
@@ -39,17 +39,17 @@
   <script src="chrome://lightning/content/caldav-lightning-calendar-properties.js"/>
 
   <description id="force-disabled-description" hidden="true">&calendarproperties.forceDisabled.label;</description>
 
   <vbox id="no-identity-notification" class="notification-inline">
     <!-- notificationbox will be added here lazily. -->
   </vbox>
   <checkbox id="calendar-enabled-checkbox"
-            label="&calendarproperties.enabled.label;"
+            label="&calendarproperties.enabled2.label;"
             oncommand="setupEnabledCheckbox()"/>
   <html:table id="calendar-properties-table">
     <html:tr id="calendar-name-row">
       <html:th>
         <label id="calendar-name-label"
                value="&calendar.server.dialog.name.label;"
                disable-with-calendar="true"
                control="calendar-name"/>
--- a/calendar/base/modules/calCalendarDeactivator.jsm
+++ b/calendar/base/modules/calCalendarDeactivator.jsm
@@ -1,12 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 var { cal } = ChromeUtils.import("resource:///modules/calendar/calUtils.jsm");
 
 this.EXPORTED_SYMBOLS = ["calendarDeactivator"];
 
 /**
  * Handles deactivation of calendar UI and background processes/services (such
  * as the alarms service) when users do not want to use calendar functionality.
  * Also handles re-activation when users change their mind.
@@ -81,16 +82,21 @@ var calendarDeactivator = {
 
     for (let window of this.windows) {
       if (someCalsEnabled) {
         window.document.documentElement.removeAttribute("calendar-deactivated");
       } else {
         window.document.documentElement.setAttribute("calendar-deactivated", "");
       }
     }
+
+    if (someCalsEnabled) {
+      Services.prefs.setBoolPref("calendar.itip.showImipBar", true);
+    }
+
     this.isCalendarActivated = someCalsEnabled;
   },
 
   // calICalendarManagerObserver methods
   onCalendarRegistered(calendar) {
     this.calendars.add(calendar);
 
     if (!this.isCalendarActivated && !calendar.getProperty("disabled")) {
--- a/calendar/base/modules/utils/calItipUtils.jsm
+++ b/calendar/base/modules/utils/calItipUtils.jsm
@@ -1,14 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 var { MailServices } = ChromeUtils.import("resource:///modules/MailServices.jsm");
+var { calendarDeactivator } = ChromeUtils.import(
+  "resource:///modules/calendar/calCalendarDeactivator.jsm"
+);
 
 ChromeUtils.defineModuleGetter(this, "cal", "resource:///modules/calendar/calUtils.jsm");
 
 /*
  * Scheduling and iTIP helper code
  */
 
 // NOTE: This module should not be loaded directly, it is available when
@@ -274,18 +277,18 @@ var calitip = {
   /**
    * Scope: iTIP message receiver
    *
    * Gets localized toolbar label about the message state and triggers buttons to show.
    * This returns a JS object with the following structure:
    *
    * {
    *    label: "This is a desciptive text about the itip item",
-   *    buttons: ["imipXXXButton", ...],
-   *    hideMenuItem: ["imipXXXButton_Option", ...]
+   *    showItems: ["imipXXXButton", ...],
+   *    hideItems: ["imipXXXButton_Option", ...]
    * }
    *
    * @see processItipItem   This takes the same parameters as its optionFunc.
    * @param {calIItipItem} itipItem       The itipItem to query.
    * @param {Number} rc                   The result of retrieving the item
    * @param {Function} actionFunc         The action function.
    * @param {calIItemBase[]} foundItems   An array of items found while searching for the item
    *                                        in subscribed calendars
@@ -302,19 +305,26 @@ var calitip = {
       false
     );
 
     let disallowedCounter = false;
     if (foundItems && foundItems.length) {
       let disallow = foundItems[0].getProperty("X-MICROSOFT-DISALLOW-COUNTER");
       disallowedCounter = disallow && disallow == "TRUE";
     }
-    if (rc == Ci.calIErrors.CAL_IS_READONLY) {
+    if (!calendarDeactivator.isCalendarActivated) {
+      // Calendar is deactivated (no calendars are enabled).
+      data.label = cal.l10n.getLtnString("imipBarCalendarDeactivated");
+      data.showItems.push("imipGoToCalendarButton", "imipMoreButton");
+      data.hideItems.push("imipMoreButton_SaveCopy");
+    } else if (rc == Ci.calIErrors.CAL_IS_READONLY) {
       // No writable calendars, tell the user about it
       data.label = cal.l10n.getLtnString("imipBarNotWritable");
+      data.showItems.push("imipGoToCalendarButton", "imipMoreButton");
+      data.hideItems.push("imipMoreButton_SaveCopy");
     } else if (Components.isSuccessCode(rc) && !actionFunc) {
       // This case, they clicked on an old message that has already been
       // added/updated, we want to tell them that.
       data.label = cal.l10n.getLtnString("imipBarAlreadyProcessedText");
       if (foundItems && foundItems.length) {
         data.showItems.push("imipDetailsButton");
         if (itipItem.receivedMethod == "COUNTER" && itipItem.sender) {
           if (disallowedCounter) {
@@ -427,17 +437,17 @@ var calitip = {
               data.showItems.push("imipAcceptButton_TentativeLabel");
               data.showItems.push("imipAcceptButton_Tentative");
               data.showItems.push("imipAcceptButton_TentativeDontSend");
             }
             data.showItems.push("imipDeclineButton");
           }
           data.showItems.push("imipMoreButton");
           // Use data.hideItems.push("idOfMenuItem") to hide specific menuitems
-          // from the dropdown menu of a button.  This might be useful to to remove
+          // from the dropdown menu of a button.  This might be useful to remove
           // a generally available option for a specific invitation, because the
           // respective feature is not available for the calendar, the invitation
           // is in or the feature is prohibited by the organizer
           break;
         }
         case "CANCEL": {
           data.showItems.push("imipDeleteButton");
           break;
--- a/calendar/base/themes/common/lightning.css
+++ b/calendar/base/themes/common/lightning.css
@@ -161,16 +161,20 @@
 .imipDeleteButton {
     list-style-image: url(chrome://messenger/skin/icons/delete.svg);
 }
 
 .imipReconfirmButton {
     list-style-image: url(chrome://calendar/skin/shared/icons/priority.svg);
 }
 
+.imipGoToCalendarButton {
+    list-style-image: url(chrome://calendar/skin/shared/icons/icon32.svg);
+}
+
 .imipAcceptLabel {
     font-weight: bold;
     font-style: italic;
 }
 
 #calsidebar_splitter,
 #today-splitter {
   /* splitter grip area */
--- a/calendar/lightning/content/imip-bar-overlay.inc.xhtml
+++ b/calendar/lightning/content/imip-bar-overlay.inc.xhtml
@@ -95,16 +95,24 @@
               <!-- re-confirm partstat -->
               <toolbarbutton id="imipReconfirmButton"
                              label="&lightning.imipbar.btnReconfirm2.label;"
                              tooltiptext="&lightning.imipbar.btnReconfirm.tooltiptext;"
                              class="toolbarbutton-1 msgHeaderView-button imipReconfirmButton"
                              oncommand="ltnImipBar.executeAction()"
                              hidden="true"/>
 
+              <!-- go to calendar tab -->
+              <toolbarbutton id="imipGoToCalendarButton"
+                             label="&lightning.imipbar.btnGoToCalendar.label;"
+                             tooltiptext="&lightning.imipbar.btnGoToCalendar.tooltiptext;"
+                             class="toolbarbutton-1 msgHeaderView-button imipGoToCalendarButton"
+                             oncommand="ltnImipBar.goToCalendar();"
+                             hidden="true"/>
+
               <!-- accept -->
               <toolbarbutton is="toolbarbutton-menu-button" id="imipAcceptButton"
                              tooltiptext="&lightning.imipbar.btnAccept2.tooltiptext;"
                              label="&lightning.imipbar.btnAccept.label;"
                              oncommand="ltnImipBar.executeAction('ACCEPTED', 'AUTO');"
                              type="menu-button"
                              class="imip-button toolbarbutton-1 msgHeaderView-button imipAcceptButton"
                              hidden="true">
@@ -269,14 +277,17 @@
                              label="&lightning.imipbar.btnMore.label;"
                              class="toolbarbutton-1 msgHeaderView-button imipMoreButton"
                              hidden="true">
                 <menupopup id="imipMoreDropdown">
                   <menuitem id="imipMoreButton_SaveCopy"
                             tooltiptext="&lightning.imipbar.btnSaveCopy.tooltiptext;"
                             label="&lightning.imipbar.btnSaveCopy.label;"
                             oncommand="ltnImipBar.executeAction('X-SAVECOPY'); event.stopPropagation();"/>
+                  <menuitem id="imipMoreButton_DoNotShowImipBar"
+                            label="&lightning.imipbar.btnDoNotShowImipBar.label;"
+                            oncommand="ltnImipBar.doNotShowImipBar();"/>
                   <!-- add here a menuitem as needed -->
                 </menupopup>
               </toolbarbutton>
             </hbox>
           </vbox>
         </hbox>
--- a/calendar/lightning/content/imip-bar.js
+++ b/calendar/lightning/content/imip-bar.js
@@ -61,19 +61,19 @@ var ltnImipBar = {
   load() {
     // Add a listener to gMessageListeners defined in msgHdrView.js
     gMessageListeners.push(ltnImipBar);
 
     // We need to extend the HideMessageHeaderPane function to also hide the
     // message header pane. Otherwise, the imip bar will still be shown when
     // changing folders.
     ltnImipBar.tbHideMessageHeaderPane = HideMessageHeaderPane;
-    HideMessageHeaderPane = function() {
+    HideMessageHeaderPane = function(...args) {
       ltnImipBar.resetBar();
-      ltnImipBar.tbHideMessageHeaderPane.apply(null, arguments);
+      ltnImipBar.tbHideMessageHeaderPane(...args);
     };
 
     // Set up our observers
     Services.obs.addObserver(ltnImipBar, "onItipItemCreation");
   },
 
   /**
    * Unload handler to clean up after the imip bar
@@ -84,16 +84,21 @@ var ltnImipBar = {
     removeEventListener("messagepane-unloaded", ltnImipBar.unload, true);
 
     ltnImipBar.resetBar();
     Services.obs.removeObserver(ltnImipBar, "onItipItemCreation");
   },
 
   observe(subject, topic, state) {
     if (topic == "onItipItemCreation") {
+      if (!Services.prefs.getBoolPref("calendar.itip.showImipBar", true)) {
+        // Do not show the imip bar if the user has opted out of seeing it.
+        return;
+      }
+
       let itipItem = null;
       let msgOverlay = null;
       try {
         if (!subject) {
           let sinkProps = msgWindow.msgHeaderSink.properties;
           // This property was set by lightningTextCalendarConverter.js
           itipItem = sinkProps.getPropertyAsInterface("itipItem", Ci.calIItipItem);
           msgOverlay = sinkProps.getPropertyAsAUTF8String("msgOverlay");
@@ -528,16 +533,66 @@ var ltnImipBar = {
         ltnImipBar.itipItem,
         window,
         aParticipantStatus,
         response
       );
     }
     return false;
   },
+
+  /**
+   * Hide the imip bar in all windows and set a pref to prevent it from being
+   * shown again. Called when clicking the imip bar's "do not show..." menu item.
+   */
+  doNotShowImipBar() {
+    Services.prefs.setBoolPref("calendar.itip.showImipBar", false);
+    for (let window of Services.ww.getWindowEnumerator()) {
+      if (window.ltnImipBar) {
+        window.ltnImipBar.resetBar();
+      }
+    }
+  },
+
+  /**
+   * Open (or focus if already open) the calendar tab, even if the imip bar is
+   * in a message window, and even if there is no main three pane Thunderbird
+   * window open. Called when clicking the imip bar's calendar button.
+   */
+  goToCalendar() {
+    let openCal = mainWindow => {
+      mainWindow.focus();
+      mainWindow.document.getElementById("tabmail").openTab("calendar", {
+        title: mainWindow.document.getElementById("calendar-tab-button").getAttribute("title"),
+      });
+    };
+
+    let mainWindow = Services.wm.getMostRecentWindow("mail:3pane");
+
+    if (mainWindow) {
+      openCal(mainWindow);
+    } else {
+      mainWindow = Services.ww.openWindow(
+        null,
+        "chrome://messenger/content/messenger.xhtml",
+        "_blank",
+        "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar",
+        null
+      );
+
+      // Wait until calendar is set up in the new window.
+      let calStartupObserver = {
+        observe(subject, topic, data) {
+          openCal(mainWindow);
+          Services.obs.removeObserver(calStartupObserver, "lightning-startup-done");
+        },
+      };
+      Services.obs.addObserver(calStartupObserver, "lightning-startup-done");
+    }
+  },
 };
 
 {
   let msgHeaderView = document.getElementById("msgHeaderView");
   if (msgHeaderView && msgHeaderView.loaded) {
     ltnImipBar.load();
   } else {
     addEventListener("messagepane-loaded", ltnImipBar.load, true);
--- a/calendar/lightning/content/lightning.js
+++ b/calendar/lightning/content/lightning.js
@@ -77,16 +77,19 @@ pref("calendar.itip.displayInvitationCha
 pref("calendar.itip.notifyDelegatorOnReply", true);
 
 // whether to prefix the subject field for email invitation invites or updates.
 pref("calendar.itip.useInvitationSubjectPrefixes", true);
 
 // whether separate invitation actions to more separate buttons or integrate into few buttons
 pref("calendar.itip.separateInvitationButtons", true);
 
+// Whether to show the imip bar.
+pref("calendar.itip.showImipBar", true);
+
 // whether CalDAV (experimental) scheduling is enabled or not.
 pref("calendar.caldav.sched.enabled", false);
 
 // 0=Sunday, 1=Monday, 2=Tuesday, etc.  One day we might want to move this to
 // a locale specific file.
 pref("calendar.week.start", 0);
 pref("calendar.weeks.inview", 4);
 pref("calendar.previousweeks.inview", 0);
--- a/calendar/locales/en-US/chrome/calendar/calendar.dtd
+++ b/calendar/locales/en-US/chrome/calendar/calendar.dtd
@@ -356,17 +356,17 @@
 <!ENTITY calendarproperties.format.label                   "Format:">
 <!ENTITY calendarproperties.location.label                 "Location:">
 <!ENTITY calendarproperties.refreshInterval.label          "Refresh Calendar:">
 <!ENTITY calendarproperties.refreshInterval.manual.label   "Manually">
 <!ENTITY calendarproperties.name.label                     "Name:">
 <!ENTITY calendarproperties.readonly.label                 "Read Only">
 <!ENTITY calendarproperties.firealarms.label               "Show Reminders">
 <!ENTITY calendarproperties.cache3.label                   "Offline Support">
-<!ENTITY calendarproperties.enabled.label                  "Switch this calendar on">
+<!ENTITY calendarproperties.enabled2.label                 "Enable This Calendar">
 <!ENTITY calendarproperties.forceDisabled.label            "The provider for this calendar could not be found. This often happens if you have disabled or uninstalled certain addons.">
 <!ENTITY calendarproperties.unsubscribe.label              "Unsubscribe">
 <!ENTITY calendarproperties.unsubscribe.accesskey          "U">
 
 <!-- Calendar Publish Dialog -->
 <!ENTITY calendar.publish.dialog.title              "Publish Calendar">
 <!ENTITY calendar.publish.url.label                 "Publishing URL">
 <!ENTITY calendar.publish.publish.button      "Publish">
--- a/calendar/locales/en-US/chrome/lightning/lightning.dtd
+++ b/calendar/locales/en-US/chrome/lightning/lightning.dtd
@@ -58,16 +58,19 @@
 <!ENTITY lightning.imipbar.btnDeclineRecurrences.label                      "Decline all">
 <!ENTITY lightning.imipbar.btnDeclineRecurrences2.tooltiptext               "Decline event invitation for all occurrences of the event">
 <!ENTITY lightning.imipbar.btnDeclineCounter.label                          "Decline">
 <!ENTITY lightning.imipbar.btnDeclineCounter.tooltiptext                    "Decline the counter proposal">
 <!ENTITY lightning.imipbar.btnDelete.label                                  "Delete">
 <!ENTITY lightning.imipbar.btnDelete.tooltiptext                            "Delete from calendar">
 <!ENTITY lightning.imipbar.btnDetails.label                                 "Details…">
 <!ENTITY lightning.imipbar.btnDetails.tooltiptext                           "Show event details">
+<!ENTITY lightning.imipbar.btnDoNotShowImipBar.label                        "Don't show me these messages">
+<!ENTITY lightning.imipbar.btnGoToCalendar.label                            "Calendar">
+<!ENTITY lightning.imipbar.btnGoToCalendar.tooltiptext                      "Go to the calendar tab">
 <!ENTITY lightning.imipbar.btnMore.label                                    "More">
 <!ENTITY lightning.imipbar.btnMore.tooltiptext                              "Click to show more options">
 <!ENTITY lightning.imipbar.btnReconfirm2.label                              "Reconfirm">
 <!ENTITY lightning.imipbar.btnReconfirm.tooltiptext                         "Sends a reconfirmation to the organizer">
 <!ENTITY lightning.imipbar.btnReschedule.label                              "Reschedule">
 <!ENTITY lightning.imipbar.btnReschedule.tooltiptext                        "Reschedule the event">
 <!ENTITY lightning.imipbar.btnSaveCopy.label                                "Save a copy">
 <!ENTITY lightning.imipbar.btnSaveCopy.tooltiptext                          "Save a copy of the event to the calendar independently of replying to the organizer. The list of attendees will be cleared.">
--- a/calendar/locales/en-US/chrome/lightning/lightning.properties
+++ b/calendar/locales/en-US/chrome/lightning/lightning.properties
@@ -137,16 +137,17 @@ imipBarProcessedMultipleNeedsAction=This
 imipBarProcessedSeriesNeedsAction=This message contains an event series that you have not yet responded to.
 imipBarReplyText=This message contains a reply to an invitation.
 imipBarReplyToNotExistingItem=This message contains a reply referring to an event that is not in your calendar.
 # LOCALIZATION_NOTE(imipBarReplyToRecentlyRemovedItem):
 # %1$S - datetime of deletion
 imipBarReplyToRecentlyRemovedItem=This message contains a reply referring to an event that was removed from your calendar at %1$S.
 imipBarUnsupportedText=This message contains an event that this version of Lightning cannot process.
 imipBarProcessingFailed=Processing message failed. Status: %1$S.
+imipBarCalendarDeactivated=This message contains event information. Enable a calendar to handle it.
 imipBarNotWritable=No writable calendars are configured for invitations, please check the calendar properties.
 imipSendMail.title=E-Mail Notification
 imipSendMail.text=Would you like to send out notification E-Mail now?
 imipNoIdentity=None
 imipNoCalendarAvailable=There are no writable calendars available.
 
 itipReplySubject2=Invitation Reply: %1$S
 itipReplyBodyAccept=%1$S has accepted your event invitation.