aboutsummaryrefslogblamecommitdiffstats
path: root/embed/mozilla/EphyFind.cpp
blob: 0b7d8bf89fe6f4b16bfda753614980df5fa9b8d6 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  
                                      












                                                                        
                                                                                  



        
                           

                   
                 
 
                        


                                 
                                    
                     
                        

                                


                               
                        

                                    





                                       
                             


                                  
 




                                


                       
 
                                                                  
 


                                                                                            

                       
                      














                                         

                                   
                         
                       

                        
                                                                                        

                                                                 
 
                                                                      






                                                                   
                     
                                                                               
     
                                     
      



                                         











                                                       

                                             

 


                                                   
                                       


                          











                                                          












                                                                      


                                                                            


                                                   
                                                                 






                                                                         
                           

 
                   


                                          
                                                
 

                                                                    

                                                              

                                  



                                                         
                                     

 
                   

                                       
 
                                                
 

                                  

                                                   
                     
                                                          
     
                 



                                        
      
 
                                     
 





                                              
                                                           
                                                  















                                                                         
                                                                                  




                                                                      
                                                          





                                                                            
                                                                            










                                                                      
                                                     
 
/*
 *  Copyright © 2005 Christian Persch
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *  $Id$
 */

#include "mozilla-config.h"
#include "config.h"

#include <glib.h>

#include <nsStringAPI.h>

#include <gtkmozembed.h>
#include <gtkmozembed_internal.h>
#include <nsComponentManagerUtils.h>
#include <nsCOMPtr.h>
#include <nsIDocShell.h>
#include <nsIDOMAbstractView.h>
#include <nsIDOMDocumentEvent.h>
#include <nsIDOMDocument.h>
#include <nsIDOMDocumentView.h>
#include <nsIDOMElement.h>
#include <nsIDOMEvent.h>
#include <nsIDOMEventTarget.h>
#include <nsIDOMHTMLAnchorElement.h>
#include <nsIDOMKeyEvent.h>
#include <nsIDOMNode.h>
#include <nsIDOMWindow.h>
#include <nsIInterfaceRequestorUtils.h>
#include <nsISelectionController.h>
#include <nsISelectionDisplay.h>
#include <nsITypeAheadFind.h>
#include <nsIWebBrowserFocus.h>
#include <nsIWebBrowser.h>
#include <nsServiceManagerUtils.h>

#ifndef HAVE_GECKO_1_9
#include <nsIDocShellTreeItem.h>
#include <nsISimpleEnumerator.h>
#endif

#include "ephy-debug.h"

#include "EphyFind.h"

#define NS_TYPEAHEADFIND_CONTRACTID "@mozilla.org/typeaheadfind;1"

static const PRUnichar kKeyEvents[] = { 'K', 'e', 'y', 'E', 'v', 'e', 'n', 't', 's', '\0' };
static const PRUnichar kKeyPress[] = { 'k', 'e', 'y', 'p', 'r', 'e', 's', 's', '\0' };

EphyFind::EphyFind ()
: mCurrentEmbed(nsnull)
, mAttention(PR_FALSE)
{
  LOG ("EphyFind ctor [%p]", this);
}

EphyFind::~EphyFind ()
{
  LOG ("EphyFind dtor [%p]", this);
}

nsresult
EphyFind::SetEmbed (EphyEmbed *aEmbed)
{
  nsresult rv = NS_OK;
  if (aEmbed == mCurrentEmbed) return rv;

  SetSelectionAttention (PR_FALSE);

  mCurrentEmbed = nsnull;
  mWebBrowser = nsnull;

  rv = NS_ERROR_FAILURE;
  gtk_moz_embed_get_nsIWebBrowser (GTK_MOZ_EMBED (gtk_bin_get_child (GTK_BIN (aEmbed))),
                   getter_AddRefs (mWebBrowser));
  NS_ENSURE_TRUE (mWebBrowser, rv);

  nsCOMPtr<nsIDocShell> docShell (do_GetInterface (mWebBrowser, &rv));
  NS_ENSURE_SUCCESS (rv, rv);

  if (!mFinder) {
    mFinder = do_CreateInstance (NS_TYPEAHEADFIND_CONTRACTID, &rv);
    NS_ENSURE_SUCCESS (rv, rv);

    rv = mFinder->Init (docShell);
#ifdef HAVE_GECKO_1_9
    mFinder->SetSelectionModeAndRepaint (nsISelectionController::SELECTION_ON);
#else
    mFinder->SetFocusLinks (PR_TRUE);
#endif
  } else {
    rv = mFinder->SetDocShell (docShell);
  }
  NS_ENSURE_SUCCESS (rv, rv);

  mCurrentEmbed = aEmbed;

  return rv;
}

void
EphyFind::SetFindProperties (const char *aSearchString,
                 PRBool aCaseSensitive)
{
  if (!mFinder) return;

  mFinder->SetCaseSensitive (aCaseSensitive);
  /* search string is set on ::Find */
}

void
EphyFind::SetSelectionAttention (PRBool aAttention)
{
  if (aAttention == mAttention) return;

  mAttention = aAttention;

  PRInt16 display;
  if (aAttention) {
    display = nsISelectionController::SELECTION_ATTENTION;
  } else {
    display = nsISelectionController::SELECTION_ON;
  }

#ifdef HAVE_GECKO_1_9
  if (mFinder) {
    mFinder->SetSelectionModeAndRepaint (display);
  }
#else
  nsresult rv;
  nsCOMPtr<nsIDocShell> shell (do_GetInterface (mWebBrowser, &rv));
  /* It's okay for this to fail, if the tab is closing, or if
   * we weren't attached to any tab yet
   */
  if (NS_FAILED (rv) || !shell) return;

  nsCOMPtr<nsISimpleEnumerator> enumerator;
  rv = shell->GetDocShellEnumerator (nsIDocShellTreeItem::typeContent,
                     nsIDocShell::ENUMERATE_FORWARDS,
                     getter_AddRefs (enumerator));
  NS_ENSURE_SUCCESS (rv, );

  PRBool hasMore = PR_FALSE;
  while (NS_SUCCEEDED (enumerator->HasMoreElements (&hasMore)) && hasMore) {
    nsCOMPtr<nsISupports> element;
    enumerator->GetNext (getter_AddRefs (element));
    if (!element) continue;
     
    nsCOMPtr<nsISelectionDisplay> sd (do_GetInterface (element));
    if (!sd) continue;
  
    nsCOMPtr<nsISelectionController> controller (do_QueryInterface (sd));
    if (!controller) continue;

    controller->SetDisplaySelection (display);
  }
#endif /* HAVE_GECKO_1_9 */
}

EphyEmbedFindResult
EphyFind::Find (const char *aSearchString,
                PRBool aLinksOnly)
{
  if (!mFinder) return EPHY_EMBED_FIND_NOTFOUND;

  nsString uSearchString;
  NS_CStringToUTF16 (nsCString (aSearchString ? aSearchString : ""),
             NS_CSTRING_ENCODING_UTF8, uSearchString);

  SetSelectionAttention (PR_TRUE);

  nsresult rv;
  PRUint16 found = nsITypeAheadFind::FIND_NOTFOUND;
  rv = mFinder->Find (uSearchString, aLinksOnly, &found);

  return (EphyEmbedFindResult) found;
}

EphyEmbedFindResult
EphyFind::FindAgain (PRBool aForward,
             PRBool aLinksOnly)
{
  if (!mFinder) return EPHY_EMBED_FIND_NOTFOUND;

  SetSelectionAttention (PR_TRUE);

  nsresult rv;
  PRUint16 found = nsITypeAheadFind::FIND_NOTFOUND;
#ifdef HAVE_GECKO_1_9
  rv = mFinder->FindAgain (!aForward, aLinksOnly, &found);
#else
  if (aForward) {
    rv = mFinder->FindNext (&found);
  } else {
    rv = mFinder->FindPrevious (&found);
  }
#endif

  return (EphyEmbedFindResult) found;
}

PRBool
EphyFind::ActivateLink (GdkModifierType aMask)
{
    nsresult rv;
    nsCOMPtr<nsIDOMElement> link;
    rv = mFinder->GetFoundLink (getter_AddRefs (link));
    if (NS_FAILED (rv) || !link) return FALSE;

    nsCOMPtr<nsIDOMDocument> doc;
    rv = link->GetOwnerDocument (getter_AddRefs (doc));
    NS_ENSURE_TRUE (doc, FALSE);

    nsCOMPtr<nsIDOMDocumentView> docView (do_QueryInterface (doc));
    NS_ENSURE_TRUE (docView, FALSE);

    nsCOMPtr<nsIDOMAbstractView> abstractView;
    docView->GetDefaultView (getter_AddRefs (abstractView));
    NS_ENSURE_TRUE (abstractView, FALSE);

    nsCOMPtr<nsIDOMDocumentEvent> docEvent (do_QueryInterface (doc));
    NS_ENSURE_TRUE (docEvent, FALSE);

    nsCOMPtr<nsIDOMEvent> event;
    rv = docEvent->CreateEvent (nsString(kKeyEvents), getter_AddRefs (event));
    NS_ENSURE_SUCCESS (rv, FALSE);

    nsCOMPtr<nsIDOMKeyEvent> keyEvent (do_QueryInterface (event));
    NS_ENSURE_TRUE (keyEvent, FALSE);

    rv = keyEvent->InitKeyEvent (nsString (kKeyPress),
                     PR_TRUE /* bubble */,
                     PR_TRUE /* cancelable */,
                     abstractView,
                     (aMask & GDK_CONTROL_MASK) != 0,
                     (aMask & GDK_MOD1_MASK) != 0 /* Alt */,
                     (aMask & GDK_SHIFT_MASK) != 0,
                     /* FIXME when we upgrade to gtk 2.10 */
                     PR_FALSE /* Meta */,
                     nsIDOMKeyEvent::DOM_VK_RETURN,
                     0);
    NS_ENSURE_SUCCESS (rv, FALSE);

    nsCOMPtr<nsIDOMEventTarget> target (do_QueryInterface (link));
    NS_ENSURE_TRUE (target, FALSE);

    PRBool defaultPrevented = PR_FALSE;
    rv = target->DispatchEvent (event, &defaultPrevented);

    return NS_SUCCEEDED (rv) && defaultPrevented;
}