214893 - Mail Integration UI - add "Mail" button to toolbar palette, with a submenu providing convenient access to mail, newsgroups. also adds Ctrl+M to compose new message.

This commit is contained in:
ben%bengoodger.com 2004-03-07 04:42:17 +00:00
parent bdc6736616
commit 877fe21ca1
11 changed files with 343 additions and 54 deletions

View File

@ -76,8 +76,14 @@
<command id="cmd_newNavigatorTab" oncommand="BrowserOpenTab();"/>
<command id="Browser:OpenFile" oncommand="BrowserOpenFileWindow();"/>
<command id="Browser:SavePage" oncommand="saveDocument(window._content.document);"/>
<command id="Browser:SendLink" oncommand="sendLink(Components.lookupMethod(window._content, 'location').call(window._content).href,
Components.lookupMethod(window._content.document, 'title').call(window._content.document));"/>
<command id="Browser:SendLink" oncommand="MailIntegration.sendLinkForContent();"/>
<command id="Browser:NewMessage" oncommand="MailIntegration.sendMessage('', '');"/>
#ifdef XP_WIN
<command id="Browser:ReadMail" oncommand="MailIntegration.readMail();"/>
<command id="Browser:ReadNews" oncommand="MailIntegration.readNews();"/>
#endif
<command id="cmd_print" oncommand="PrintUtils.print();"/>
<command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/>
<command id="cmd_closeWindow" oncommand="BrowserCloseWindow()"/>
@ -256,6 +262,8 @@
<key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/>
<key id="key_newMessage" key="&sendMessage.commandkey;" command="Browser:NewMessage" modifiers="accel"/>
<key id="key_textZoomReduce" key="&textZoomReduceCmd.commandkey;" command="cmd_textZoomReduce" modifiers="accel"/>
<key id="key_textZoomEnlarge" key="&textZoomEnlargeCmd.commandkey;" command="cmd_textZoomEnlarge" modifiers="accel"/>
<key key="&textZoomEnlargeCmd.commandkey2;" command="cmd_textZoomEnlarge" modifiers="accel"/>

View File

@ -1503,7 +1503,6 @@ function updateToolbarStates(toolbarMenuElt)
function BrowserImport()
{
// goats
#ifdef XP_MACOSX
var features = "centerscreen,chrome,resizable=no";
#else
@ -3207,14 +3206,14 @@ nsContextMenu.prototype = {
saveURL( this.linkURL(), this.linkText(), null, true, true );
},
sendLink : function () {
sendLink( this.linkURL(), "" ); // we don't know the title of the link so pass in an empty string
MailIntegration.sendMessage( this.linkURL(), "" ); // we don't know the title of the link so pass in an empty string
},
// Save URL of clicked-on image.
saveImage : function () {
saveURL( this.imageURL, null, "SaveImageTitle", false );
},
sendImage : function () {
sendLink(this.imageURL, "");
MailIntegration.sendMessage(this.imageURL, "");
},
toggleImageBlocking : function (aBlock) {
var nsIPermissionManager = Components.interfaces.nsIPermissionManager;
@ -3942,27 +3941,6 @@ function charsetLoadListener (event)
}
}
// a generic method which can be used to pass arbitrary urls to the operating system.
// aURL --> a nsIURI which represents the url to launch
function launchExternalUrl(aURL)
{
var extProtocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"].getService(Components.interfaces.nsIExternalProtocolService);
if (extProtocolSvc)
extProtocolSvc.loadUrl(aURL);
}
function sendLink(url, title)
{
// generate a mailto url based on the url and the url's title
var mailtoUrl = url ? "mailto:?body=" + encodeURIComponent(url) + "&subject=" + encodeURIComponent(title) : "mailto:";
var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
var uri = ioService.newURI(mailtoUrl, null, null);
// now pass this url to the operating system
launchExternalUrl(uri);
}
#ifdef XP_MACOSX
const nsIWindowDataSource = Components.interfaces.nsIWindowDataSource;
@ -4317,3 +4295,61 @@ function WindowIsClosing()
return reallyClose;
}
var MailIntegration = {
sendLinkForContent: function ()
{
this.sendMessage(Components.lookupMethod(window._content, 'location').call(window._content).href,
Components.lookupMethod(window._content.document, 'title').call(window._content.document));
},
sendMessage: function (aBody, aSubject)
{
// generate a mailto url based on the url and the url's title
var mailtoUrl = aBody ? "mailto:?body=" + encodeURIComponent(aBody) + "&subject=" + encodeURIComponent(aSubject) : "mailto:";
var ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
var uri = ioService.newURI(mailtoUrl, null, null);
// now pass this url to the operating system
this._launchExternalUrl(uri);
},
// a generic method which can be used to pass arbitrary urls to the operating system.
// aURL --> a nsIURI which represents the url to launch
_launchExternalUrl: function(aURL)
{
var extProtocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"].getService(Components.interfaces.nsIExternalProtocolService);
if (extProtocolSvc)
extProtocolSvc.loadUrl(aURL);
#ifdef XP_WIN
},
readMail: function ()
{
var whs = Components.classes["@mozilla.org/winhooks;1"].getService(Components.interfaces.nsIWindowsHooks);
whs.openDefaultClient("Mail");
},
readNews: function ()
{
var whs = Components.classes["@mozilla.org/winhooks;1"].getService(Components.interfaces.nsIWindowsHooks);
whs.openDefaultClient("News");
},
updateUnreadCount: function ()
{
var whs = Components.classes["@mozilla.org/winhooks;1"].getService(Components.interfaces.nsIWindowsHooks);
var unreadCount = whs.unreadMailCount;
var message = gNavigatorBundle.getFormattedString("mailUnreadTooltip", [unreadCount]);
var element = document.getElementById("mail-button");
element.setAttribute("tooltiptext", message);
message = gNavigatorBundle.getFormattedString("mailUnreadMenuitem", [unreadCount]);
element = document.getElementById("readMailItem");
element.setAttribute("label", message);
}
#else
}
#endif
};

View File

@ -289,7 +289,31 @@
<toolbarbutton id="history-button" class="toolbarbutton-1"
observes="viewHistorySidebar"
tooltiptext="&historyButton.tooltip;"/>
#ifdef XP_WIN
<toolbarbutton id="mail-button" type="menu" class="toolbarbutton-1"
label="&mailButton.label;" orient="horizontal"
onmouseover="MailIntegration.updateUnreadCount();"
tooltiptext="&mailButton.tooltip;">
<menupopup tooltiptext="">
<menuitem label="&mailButton.readMail.label;"
id="readMailItem"
accesskey="&mailButton.readMail.accesskey;"
command="Browser:ReadMail"/>
<menuitem label="&mailButton.newMessage.label;"
accesskey="&mailButton.newMessage.accesskey;"
command="Browser:NewMessage"/>
<menuitem label="&mailButton.sendLink.label;"
accesskey="&mailButton.sendLink.accesskey;"
command="Browser:SendLink"/>
<menuseparator/>
<menuitem label="&mailButton.readNews.label;"
accesskey="&mailButton.readNews.accesskey;"
command="Browser:ReadNews"/>
</menupopup>
</toolbarbutton>
#endif
<toolbarbutton id="bookmarks-button" class="toolbarbutton-1"
observes="viewBookmarksSidebar"
tooltiptext="&bookmarksButton.tooltip;"/>

View File

@ -268,6 +268,18 @@
<!ENTITY historyButton.label "History">
<!ENTITY historyButton.tooltip "Display pages you've viewed recently">
<!ENTITY mailButton.label "Mail">
<!ENTITY mailButton.tooltip "Read and Send Mail">
<!ENTITY mailButton.readMail.label "Read Mail">
<!ENTITY mailButton.readMail.accesskey "M">
<!ENTITY mailButton.newMessage.label "New Message...">
<!ENTITY mailButton.newMessage.accesskey "w">
<!ENTITY mailButton.sendLink.label "Send Link...">
<!ENTITY mailButton.sendLink.accesskey "L">
<!ENTITY mailButton.readNews.label "Read News">
<!ENTITY mailButton.readNews.accesskey "N">
<!ENTITY sendMessage.commandkey "m">
<!ENTITY newTabButton.tooltip "Open a new tab">
<!ENTITY newWindowButton.tooltip "Open a new window">
<!ENTITY sidebarCloseButton.tooltip "Close sidebar">

View File

@ -56,3 +56,6 @@ tabs.closeWarningTitle=Confirm close
tabs.closeWarning=This Browser window has %S tabs open. Do you want to close it and all its tabs?
tabs.closeButton=Close all tabs
tabs.closeWarningPromptMe=Warn me when closing multiple tabs
mailUnreadTooltip=Read Mail and News (%S new messages)
mailUnreadMenuitem=Read Mail (%S new)

View File

@ -302,6 +302,17 @@ toolbar[mode="text"] .toolbarbutton-text {
-moz-image-region: rect(64px 224px 96px 192px);
}
#mail-button {
-moz-image-region: rect(0px 224px 32px 192px);
}
#mail-button:hover,
#mail-button[checked="true"] {
-moz-image-region: rect(32px 224px 64px 192px);
}
#mail-button[disabled="true"] {
-moz-image-region: rect(64px 224px 96px 192px);
}
#cut-button {
-moz-image-region: rect(0px 384px 32px 352px);
}
@ -453,6 +464,17 @@ toolbar[iconsize="small"] #history-button[disabled="true"] {
-moz-image-region: rect(40px 140px 60px 120px) !important;
}
toolbar[iconsize="small"] #mail-button {
-moz-image-region: rect(0px 140px 20px 120px);
}
toolbar[iconsize="small"] #mail-button:hover,
toolbar[iconsize="small"] #mail-button[checked="true"] {
-moz-image-region: rect(20px 140px 40px 120px);
}
toolbar[iconsize="small"] #mail-button[disabled="true"] {
-moz-image-region: rect(40px 140px 60px 120px) !important;
}
toolbar[iconsize="small"] #cut-button {
-moz-image-region: rect(0px 240px 20px 220px);
}

View File

@ -767,3 +767,125 @@ nsWindowsHooks::SetImageAsWallpaper(nsIDOMElement* aElement, PRBool aUseBackgrou
return rv;
}
NS_IMETHODIMP
nsWindowsHooks::OpenDefaultClient(const char* aClient)
{
nsresult rv;
// The Default Client section of the Windows Registry looks like this:
//
// Clients\aClient\
// e.g. aClient = "Mail"...
// \Mail\(default) = Client Subkey Name
// \Client Subkey Name
// \Client Subkey Name\shell\open\command\
// \Client Subkey Name\shell\open\command\(default) = path to exe
//
nsCAutoString clientKey(NS_LITERAL_CSTRING("SOFTWARE\\Clients\\"));
clientKey += aClient;
nsXPIDLCString defaultClient;
rv = GetRegistryEntry(nsIWindowsRegistry::HKLM, clientKey.get(), "",
getter_Copies(defaultClient));
if (NS_FAILED(rv) || defaultClient.IsEmpty())
return rv;
clientKey.Append("\\");
clientKey.Append(defaultClient.get());
clientKey.Append("\\shell\\open\\command");
nsXPIDLCString path;
rv = GetRegistryEntry(nsIWindowsRegistry::HKLM, clientKey.get(), "",
getter_Copies(path));
if (NS_FAILED(rv) || path.IsEmpty())
return rv;
// Look for any embedded environment variables and substitute their
// values, as |::CreateProcess| is unable to do this.
PRInt32 end = path.Length();
PRInt32 cursor = 0, temp = 0;
char buf[_MAX_PATH];
do {
cursor = path.FindChar('%', cursor);
if (cursor < 0)
break;
temp = path.FindChar('%', cursor + 1);
++cursor;
::ZeroMemory(&buf, sizeof(buf));
::GetEnvironmentVariable(nsCAutoString(Substring(path, cursor, temp - cursor)).get(),
buf, sizeof(buf));
// "+ 2" is to subtract the extra characters used to delimit the environment
// variable ('%').
path.Replace((cursor - 1), temp - cursor + 2, nsDependentCString(buf));
++cursor;
}
while (cursor < end);
STARTUPINFO si;
PROCESS_INFORMATION pi;
::ZeroMemory(&si, sizeof(STARTUPINFO));
::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
char* pathCStr = ToNewCString(path);
BOOL success = ::CreateProcess(NULL, pathCStr, NULL, NULL, FALSE, 0, NULL,
NULL, &si, &pi);
nsCRT::free(pathCStr);
if (!success)
return NS_ERROR_FAILURE;
return NS_OK;
}
NS_IMETHODIMP
nsWindowsHooks::GetUnreadMailCount(PRUint32* aResult)
{
*aResult = 0;
HKEY accountKey;
if (GetMailAccountKey(&accountKey)) {
DWORD type, length, unreadCount;
DWORD result = ::RegQueryValueEx(accountKey, "MessageCount", 0, &type,
(LPBYTE)&unreadCount, &length);
if (result == ERROR_SUCCESS) {
*aResult = unreadCount;
}
}
return NS_OK;
}
PRBool
nsWindowsHooks::GetMailAccountKey(HKEY* aResult)
{
HKEY mailKey;
DWORD result = ::RegOpenKeyEx(HKEY_CURRENT_USER,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\",
0, KEY_ENUMERATE_SUB_KEYS, &mailKey);
PRInt32 i = 0;
do {
char subkeyName[_MAX_PATH];
DWORD len = sizeof subkeyName;
result = ::RegEnumKeyEx(mailKey, i++, subkeyName, &len, 0, 0, 0, 0);
if (result == ERROR_SUCCESS) {
HKEY accountKey;
result = ::RegOpenKeyEx(mailKey, subkeyName, 0, KEY_READ, &accountKey);
if (result == ERROR_SUCCESS) {
*aResult = accountKey;
return PR_TRUE;
}
}
else
break;
}
while (1);
return PR_FALSE;
}

View File

@ -42,6 +42,8 @@
#include "nscore.h"
#include "nsIWindowsHooks.h"
#include <windows.h>
#ifndef MAX_BUF
#define MAX_BUF 4096
#endif
@ -113,6 +115,8 @@ protected:
// Internal flavor of GetPreferences.
NS_IMETHOD GetSettings( nsWindowsHooksSettings ** );
PRBool GetMailAccountKey(HKEY* aResult);
// Set registry according to settings.
NS_IMETHOD SetRegistry();
char mShortcutPath[MAX_BUF];

View File

@ -148,39 +148,70 @@ interface nsIWindowsHooksSettings : nsISupports {
* by the nsIWindowsHooksPrefs attributes.
*/
[scriptable, uuid(19c9fbb0-06a3-11d4-8076-00600811a9c3)]
interface nsIWindowsHooks : nsISupports {
// settings
// --------
// Get/set this to query or modify them. The Windows
// registry is updated when you set this attribute.
interface nsIWindowsHooks : nsISupports
{
/**
* See nsIWindowsHooksSettings; The Windows Registry is updated when
* this attribute is set.
*/
attribute nsIWindowsHooksSettings settings;
// checkSettings
// -------------
// Check that registry matches settings and if not,
// prompt user for whether to reset. This is
// controlled by the showDialog setting. This will
// perform the check only the first time the
// service is called.
// aParent - parent window for any dialogs that
// will appear
// Returns true if the windows integration dialog was shown
boolean checkSettings( in nsIDOMWindowInternal aParent );
/**
* Check that registry matches settings and if not, prompt user for whether
* to reset. This is controlled by the showDialog setting. This will
* perform the check only the first time the service is called.
*
* @param aParent parent window for any dialogs that will appear.
* @return true if the windows integration dialog was shown, false if not.
*/
boolean checkSettings(in nsIDOMWindowInternal aParent);
const PRInt32 WALLPAPER_TILE = 0;
const PRInt32 WALLPAPER_STRETCH = 1;
const PRInt32 WALLPAPER_CENTER = 2;
/**
* Accepts an element, either an HTML img element or an element with
* a background image, serializes the image to a bitmap file
* in the windows directory, and sets it to be the desktop wallpaper.
* Sets the desktop background image using either the HTML <IMG>
* element supplied or the background image of the element supplied.
*
* @param aImageElement Either a HTML <IMG> element or an element with
* a background image from which to source the
* background image.
* @param useBackground Determines whether or not to interpret aImageElement
* as a HTML <IMG> element or as another element whose
* background image should be used.
* @param position How to place the image on the desktop
*/
void setImageAsWallpaper(in nsIDOMElement aImageElement, in boolean useBackground, in PRInt32 position);
/**
* Retrieves the current desktop background color.
*/
PRUint32 getDesktopColor();
/**
* Sets the current desktop background color.
*
* @param color The color to use, in rgb format.
*/
void setDesktopColor(in PRUint32 color);
/**
* Launches one of the Windows default clients.
*
* @param aClient The client type to open, as specified in the Windows Registry under:
* HKEY_LOCAL_MACHINE\Software\Clients\
* Typical values include "Mail", "News", "Contacts" etc.
*/
void openDefaultClient(in string aClient);
/**
* Retrieve the number of unread mail messages from the system for the current user.
*
* @return The number of unread (new) mail messages for the current user.
*/
readonly attribute unsigned long unreadMailCount;
};
/* nsIWindowsRegistry
@ -193,23 +224,31 @@ interface nsIWindowsHooks : nsISupports {
[scriptable, uuid(e07e7430-8d11-417c-83ee-c994400c452f)]
interface nsIWindowsRegistry : nsISupports {
/**
* Returns a Win32 registry entry value. The returned string will be truncated
* at 4096 bytes. The constants define the set of valid starting keys. You
* pass in the subkey name and a value identifier (an empty string returns
* the "default" value for that subkey).
* Valid starting keys for the Windows Registry.
*/
const long HKCR = 0; // HKEY_CLASSES_ROOT
const long HKCC = 1; // HKEY_CURRENT_CONFIG
const long HKCU = 2; // HKEY_CURRENT_USER
const long HKLM = 3; // HKEY_LOCAL_MACHINE
const long HKU = 4; // HKEY_USERS
string getRegistryEntry( in long aHKeyConstant, in string aSubKeyName, in string aValueName );
/**
* Retrieves a Windows Registry entry value.
*
* @param aHKeyConstant The starting key, using the constants defined above.
* @param aSubKeyName The sub key to locate
* @param aValueName The value to locate in the sub key. The empty string
* returns the default value of the sub key.
* @return The value of the specified sub key/value, truncated to 4096 bytes.
*/
string getRegistryEntry(in long aHKeyConstant, in string aSubKeyName, in string aValueName);
};
%{C++
#define NS_IWINDOWSHOOKS_CONTRACTID "@mozilla.org/winhooks;1"
#define NS_IWINDOWSHOOKS_CONTRACTID "@mozilla.org/winhooks;1"
#define NS_IWINDOWSHOOKS_CLASSNAME "Mozilla Windows Integration Hooks"
// XXXben - get rid of this
// The key that is used to write the quick launch appname in the windows registry
#define NS_QUICKLAUNCH_RUN_KEY "Mozilla Quick Launch"
%}

View File

@ -30,6 +30,21 @@
</content>
</binding>
<binding id="menu-orient" display="xul:menu"
extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
<content>
<children includes="observes|template|menupopup|tooltip"/>
<xul:hbox flex="1" align="center">
<xul:box xbl:inherits="orient" flex="1">
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,toolbarmode,buttonstyle"/>
<xul:label class="toolbarbutton-text" crop="right" flex="1"
xbl:inherits="value=label,accesskey,crop,dragover-top,toolbarmode,buttonstyle"/>
</xul:box>
<xul:dropmarker type="menu" class="toolbarbutton-menu-dropmarker" xbl:inherits="disabled"/>
</xul:hbox>
</content>
</binding>
<binding id="menu-button" display="xul:menu"
extends="chrome://global/content/bindings/button.xml#menu-button-base">
<resources>

View File

@ -123,6 +123,10 @@ toolbarbutton[type="menu"] {
-moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#menu");
}
toolbarbutton[orient] {
-moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#menu-orient");
}
toolbarbutton[type="menu-button"] {
-moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#menu-button");
}