Back to index

lightning-sunbird  0.9+nobinonly
CHClickListener.mm
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is Netscape
00018  * Communications Corporation. Portions created by Netscape are
00019  * Copyright (C) 2002 Netscape Communications Corporation. All
00020  * Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  David Hyatt <hyatt@netscape.com> (Original Author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #import "NSString+Utils.h"
00040 #import "CHBrowserView.h"
00041 
00042 #include "nsCOMPtr.h"
00043 #include "CHClickListener.h"
00044 #include "nsIDOMEventTarget.h"
00045 #include "nsIContent.h"
00046 #include "nsIDOMElement.h"
00047 #include "nsIDOMMouseEvent.h"
00048 #include "nsEmbedAPI.h"
00049 #include "nsIDOMDocument.h"
00050 #include "nsIDOMDocumentEvent.h"
00051 #include "nsIDOMEventTarget.h"
00052 #include "nsIDOMNSHTMLElement.h"
00053 #include "nsIDOMHTMLSelectElement.h"
00054 #include "nsIDOMHTMLOptionElement.h"
00055 #include "nsIDOMHTMLOptionsCollection.h"
00056 #include "nsIDOMWindow.h"
00057 #include "nsIScriptGlobalObject.h"
00058 #include "nsIDocument.h"
00059 #include "nsString.h"
00060 
00061 
00062 @interface CHOptionSelector : NSObject
00063 {
00064   nsIDOMHTMLSelectElement* mSelectElt;
00065 }
00066 
00067 -(id)initWithSelect:(nsIDOMHTMLSelectElement*)aSel;
00068 -(IBAction)selectOption:(id)aSender;
00069 
00070 @end
00071 
00072 @implementation CHOptionSelector
00073 
00074 -(id)initWithSelect:(nsIDOMHTMLSelectElement*)aSel
00075 {
00076   if ( (self = [super init]) ) {
00077     mSelectElt = aSel;
00078   }
00079   return self;
00080 }
00081 
00082 -(IBAction)selectOption:(id)aSender
00083 {
00084   nsIDOMHTMLOptionElement* optionElt = (nsIDOMHTMLOptionElement*) [aSender tag];
00085   optionElt->SetSelected(PR_TRUE);
00086   [self autorelease]; // Free up ourselves.
00087   [[aSender menu] autorelease]; // Free up the menu.
00088 
00089   // Fire a DOM event for the title change.
00090   nsCOMPtr<nsIDOMEvent> event;
00091   nsCOMPtr<nsIDOMDocument> domDocument;
00092   mSelectElt->GetOwnerDocument(getter_AddRefs(domDocument));
00093   nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(domDocument));
00094   
00095   docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
00096   if (event) {
00097     event->InitEvent(NS_LITERAL_STRING("change"), PR_TRUE, PR_TRUE);
00098     nsCOMPtr<nsIDOMEventTarget> target(do_QueryInterface(mSelectElt));
00099     PRBool defaultActionEnabled;
00100     target->DispatchEvent(event, &defaultActionEnabled);
00101   }  
00102 }
00103 
00104 @end
00105 
00106 
00107 NS_IMPL_ISUPPORTS2(CHClickListener, nsIDOMMouseListener, nsIDOMEventListener)
00108 
00109 CHClickListener::CHClickListener()
00110 {
00111 }
00112 
00113 CHClickListener::~CHClickListener()
00114 {
00115 }
00116 
00117 NS_IMETHODIMP
00118 CHClickListener::MouseDown(nsIDOMEvent* aEvent)
00119 {
00120   nsCOMPtr<nsIDOMEventTarget> target;
00121   aEvent->GetTarget(getter_AddRefs(target));
00122   if (!target)
00123     return NS_OK;
00124   nsCOMPtr<nsIDOMHTMLSelectElement> sel(do_QueryInterface(target));
00125   if (sel) {
00126     PRInt32 size = 0;
00127     sel->GetSize(&size);
00128     PRBool multiple = PR_FALSE;
00129     sel->GetMultiple(&multiple);
00130     if(size > 1 || multiple)
00131       return NS_OK;
00132       
00133     NSMenu* menu = [[NSMenu alloc] init]; // Retain the menu.
00134 
00135     // We'll set the disabled state as the options are created, so disable
00136     // auto-enabling via NSMenuValidation.
00137     [menu setAutoenablesItems: NO];
00138 
00139     nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
00140     sel->GetOptions(getter_AddRefs(options));
00141     PRUint32 count;
00142     options->GetLength(&count);
00143     PRInt32 selIndex = 0;
00144     for (PRUint32 i = 0; i < count; i++) {
00145       nsCOMPtr<nsIDOMNode> node;
00146       options->Item(i, getter_AddRefs(node));
00147       nsCOMPtr<nsIDOMHTMLOptionElement> option(do_QueryInterface(node));
00148       nsAutoString text;
00149       option->GetLabel(text);
00150       if (text.IsEmpty())
00151         option->GetText(text);
00152       NSString* title = [[NSString stringWith_nsAString: text] stringByTruncatingTo:75 at:kTruncateAtMiddle];
00153       NSMenuItem* menuItem = [[[NSMenuItem alloc] initWithTitle: title action: NULL keyEquivalent: @""] autorelease];
00154       [menu addItem: menuItem];
00155       [menuItem setTag: (int)option.get()];
00156       PRBool selected;
00157       option->GetSelected(&selected);
00158       if (selected) {
00159         [menuItem setState: NSOnState];
00160         selIndex = i;
00161       }
00162       PRBool disabled;
00163       option->GetDisabled(&disabled);
00164       if (disabled)
00165         [menuItem setEnabled: NO];
00166       CHOptionSelector* optSelector = [[CHOptionSelector alloc] initWithSelect: sel];
00167       [menuItem setTarget: optSelector];
00168       [menuItem setAction: @selector(selectOption:)];
00169     }
00170 
00171     nsCOMPtr<nsIDOMNSHTMLElement> nsSel(do_QueryInterface(sel));
00172     PRInt32 left, top, height;
00173     PRInt32 clientX, clientY;
00174     nsSel->GetOffsetLeft(&left);
00175     nsSel->GetOffsetTop(&top);
00176     nsSel->GetOffsetHeight(&height);
00177 
00178     nsCOMPtr<nsIDOMElement> currOffsetParent;
00179     nsSel->GetOffsetParent(getter_AddRefs(currOffsetParent));
00180     while (currOffsetParent) {
00181       nsCOMPtr<nsIDOMNSHTMLElement> currNS(do_QueryInterface(currOffsetParent));
00182       PRInt32 currLeft, currTop;
00183       currNS->GetOffsetLeft(&currLeft);
00184       currNS->GetOffsetTop(&currTop);
00185       left += currLeft;
00186       top += currTop;
00187       currNS->GetOffsetParent(getter_AddRefs(currOffsetParent));
00188     }
00189     
00190     nsCOMPtr<nsIDOMMouseEvent> msEvent(do_QueryInterface(aEvent));
00191     msEvent->GetClientX(&clientX);
00192     msEvent->GetClientY(&clientY);
00193 
00194     PRInt32 xDelta = clientX - left;
00195     PRInt32 yDelta = top + height - clientY;
00196 
00197     nsCOMPtr<nsIContent> selContent = do_QueryInterface(sel);
00198     nsCOMPtr<nsIDocument> doc = selContent->GetDocument();
00199 
00200     // I'm going to assume that if we got a mousedown for a content node,
00201     // it's actually in a document.
00202 
00203     nsCOMPtr<nsIScriptGlobalObject> sgo;
00204     doc->GetScriptGlobalObject(getter_AddRefs(sgo));
00205     nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(sgo);
00206     if (!window)
00207       return NS_OK;
00208 
00209     PRInt32 scrollX, scrollY;
00210     window->GetScrollX(&scrollX);
00211     window->GetScrollY(&scrollY);
00212     xDelta += scrollX; // Normal direction.
00213     yDelta -= scrollY; // Remember, y is flipped.
00214     
00215 #define XMENUOFFSET 20
00216 #define MENUHEIGHT 20
00217     
00218     xDelta += XMENUOFFSET;
00219     yDelta -= MENUHEIGHT*(selIndex+1);
00220     
00221     NSEvent* event = [NSApp currentEvent];
00222     NSPoint point = [event locationInWindow];
00223     point.x -= xDelta;
00224     point.y -= yDelta;
00225 
00226     NSEvent* mouseEvent = [NSEvent mouseEventWithType: NSLeftMouseDown location: point
00227                                         modifierFlags: 0 timestamp: [event timestamp]
00228                                          windowNumber: [event windowNumber] context: [event context]
00229                                           eventNumber: [event eventNumber] clickCount: [event clickCount]                                                                                                                                                           pressure: [event pressure]];
00230     [NSMenu popUpContextMenu: menu withEvent: mouseEvent forView: [[event window] contentView]];
00231   }
00232   return NS_OK;
00233 }