Home | History | Annotate | Download | only in automation
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/automation/testing_automation_provider.h"
      6 
      7 #include "chrome/browser/automation/automation_browser_tracker.h"
      8 #include "chrome/browser/automation/automation_window_tracker.h"
      9 #include "chrome/browser/ui/browser_window.h"
     10 #include "chrome/browser/ui/views/frame/browser_view.h"
     11 #include "chrome/browser/ui/views/toolbar_view.h"
     12 #include "chrome/common/automation_messages.h"
     13 #include "ui/gfx/point.h"
     14 #include "views/controls/menu/menu_wrapper.h"
     15 #include "views/view.h"
     16 #include "views/widget/native_widget.h"
     17 #include "views/widget/root_view.h"
     18 #include "views/widget/widget.h"
     19 
     20 namespace {
     21 
     22 // Helper class that waits until the focus has changed to a view other
     23 // than the one with the provided view id.
     24 class ViewFocusChangeWaiter : public views::FocusChangeListener {
     25  public:
     26   ViewFocusChangeWaiter(views::FocusManager* focus_manager,
     27                         int previous_view_id,
     28                         AutomationProvider* automation,
     29                         IPC::Message* reply_message)
     30       : focus_manager_(focus_manager),
     31         previous_view_id_(previous_view_id),
     32         automation_(automation),
     33         reply_message_(reply_message),
     34         ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
     35     focus_manager_->AddFocusChangeListener(this);
     36     // Call the focus change notification once in case the focus has
     37     // already changed.
     38     FocusWillChange(NULL, focus_manager_->GetFocusedView());
     39   }
     40 
     41   ~ViewFocusChangeWaiter() {
     42     focus_manager_->RemoveFocusChangeListener(this);
     43   }
     44 
     45   // Inherited from FocusChangeListener
     46   virtual void FocusWillChange(views::View* focused_before,
     47                                views::View* focused_now) {
     48     // This listener is called before focus actually changes. Post a task
     49     // that will get run after focus changes.
     50     MessageLoop::current()->PostTask(
     51         FROM_HERE,
     52         method_factory_.NewRunnableMethod(
     53             &ViewFocusChangeWaiter::FocusChanged,
     54             focused_before,
     55             focused_now));
     56   }
     57 
     58  private:
     59   void FocusChanged(views::View* focused_before,
     60                     views::View* focused_now) {
     61     if (focused_now && focused_now->GetID() != previous_view_id_) {
     62       AutomationMsg_WaitForFocusedViewIDToChange::WriteReplyParams(
     63           reply_message_, true, focused_now->GetID());
     64 
     65       automation_->Send(reply_message_);
     66       delete this;
     67     }
     68   }
     69 
     70   views::FocusManager* focus_manager_;
     71   int previous_view_id_;
     72   AutomationProvider* automation_;
     73   IPC::Message* reply_message_;
     74   ScopedRunnableMethodFactory<ViewFocusChangeWaiter> method_factory_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(ViewFocusChangeWaiter);
     77 };
     78 
     79 }  // namespace
     80 
     81 class TestingAutomationProvider::PopupMenuWaiter : public views::MenuListener {
     82  public:
     83   PopupMenuWaiter(ToolbarView* toolbar_view,
     84                   TestingAutomationProvider* automation)
     85       : toolbar_view_(toolbar_view),
     86         automation_(automation),
     87         reply_message_(NULL) {
     88     toolbar_view_->AddMenuListener(this);
     89   }
     90 
     91   // Implementation of views::MenuListener
     92   virtual void OnMenuOpened() {
     93     toolbar_view_->RemoveMenuListener(this);
     94     automation_->popup_menu_opened_ = true;
     95     automation_->popup_menu_waiter_ = NULL;
     96     if (reply_message_) {
     97       AutomationMsg_WaitForPopupMenuToOpen::WriteReplyParams(
     98           reply_message_, true);
     99       automation_->Send(reply_message_);
    100     }
    101     delete this;
    102   }
    103 
    104   void set_reply_message(IPC::Message* reply_message) {
    105     reply_message_ = reply_message;
    106   }
    107 
    108  private:
    109   ToolbarView* toolbar_view_;
    110   TestingAutomationProvider* automation_;
    111   IPC::Message* reply_message_;
    112 
    113   DISALLOW_COPY_AND_ASSIGN(PopupMenuWaiter);
    114 };
    115 
    116 void TestingAutomationProvider::WindowGetViewBounds(int handle,
    117                                                     int view_id,
    118                                                     bool screen_coordinates,
    119                                                     bool* success,
    120                                                     gfx::Rect* bounds) {
    121   *success = false;
    122 
    123   if (window_tracker_->ContainsHandle(handle)) {
    124     gfx::NativeWindow window = window_tracker_->GetResource(handle);
    125     views::NativeWidget* native_widget =
    126         views::NativeWidget::GetNativeWidgetForNativeWindow(window);
    127     if (native_widget) {
    128       views::View* root_view = native_widget->GetWidget()->GetRootView();
    129       views::View* view = root_view->GetViewByID(view_id);
    130       if (view) {
    131         *success = true;
    132         gfx::Point point;
    133         if (screen_coordinates)
    134           views::View::ConvertPointToScreen(view, &point);
    135         else
    136           views::View::ConvertPointToView(view, root_view, &point);
    137         *bounds = view->GetContentsBounds();
    138         bounds->set_origin(point);
    139       }
    140     }
    141   }
    142 }
    143 
    144 void TestingAutomationProvider::GetFocusedViewID(int handle, int* view_id) {
    145   *view_id = -1;
    146   if (window_tracker_->ContainsHandle(handle)) {
    147     gfx::NativeWindow window = window_tracker_->GetResource(handle);
    148     views::FocusManager* focus_manager =
    149         views::FocusManager::GetFocusManagerForNativeWindow(window);
    150     DCHECK(focus_manager);
    151     views::View* focused_view = focus_manager->GetFocusedView();
    152     if (focused_view)
    153       *view_id = focused_view->GetID();
    154   }
    155 }
    156 
    157 void TestingAutomationProvider::WaitForFocusedViewIDToChange(
    158     int handle, int previous_view_id, IPC::Message* reply_message) {
    159   if (!window_tracker_->ContainsHandle(handle))
    160     return;
    161   gfx::NativeWindow window = window_tracker_->GetResource(handle);
    162   views::FocusManager* focus_manager =
    163       views::FocusManager::GetFocusManagerForNativeWindow(window);
    164 
    165   // The waiter will respond to the IPC and delete itself when done.
    166   new ViewFocusChangeWaiter(focus_manager,
    167                             previous_view_id,
    168                             this,
    169                             reply_message);
    170 }
    171 
    172 void TestingAutomationProvider::StartTrackingPopupMenus(
    173     int browser_handle, bool* success) {
    174   if (browser_tracker_->ContainsHandle(browser_handle)) {
    175     Browser* browser = browser_tracker_->GetResource(browser_handle);
    176     BrowserView* browser_view = reinterpret_cast<BrowserView*>(
    177         browser->window());
    178     ToolbarView* toolbar_view = browser_view->GetToolbarView();
    179     popup_menu_opened_ = false;
    180     popup_menu_waiter_ = new PopupMenuWaiter(toolbar_view, this);
    181     *success = true;
    182   }
    183 }
    184 
    185 void TestingAutomationProvider::WaitForPopupMenuToOpen(
    186     IPC::Message* reply_message) {
    187   // See if the menu already opened and return true if so.
    188   if (popup_menu_opened_) {
    189     AutomationMsg_WaitForPopupMenuToOpen::WriteReplyParams(
    190           reply_message, true);
    191     Send(reply_message);
    192     return;
    193   }
    194 
    195   // Otherwise, register this reply message with the waiter,
    196   // which will handle responding to this IPC when the popup
    197   // menu opens.
    198   popup_menu_waiter_->set_reply_message(reply_message);
    199 }
    200