Home | History | Annotate | Download | only in gtk
      1 // Copyright (c) 2012 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/ui/gtk/javascript_app_modal_dialog_gtk.h"
      6 
      7 #include <gtk/gtk.h>
      8 
      9 #include "base/logging.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
     12 #include "chrome/browser/ui/gtk/gtk_util.h"
     13 #include "grit/generated_resources.h"
     14 #include "grit/locale_settings.h"
     15 #include "ui/base/l10n/l10n_util.h"
     16 #include "ui/base/ui_base_types.h"
     17 
     18 namespace {
     19 
     20 // We stash pointers to widgets on the gtk_dialog so we can refer to them
     21 // after dialog creation.
     22 const char kPromptTextId[] = "chrome_prompt_text";
     23 const char kSuppressCheckboxId[] = "chrome_suppress_checkbox";
     24 
     25 // If there's a text entry in the dialog, get the text from the first one and
     26 // return it.
     27 string16 GetPromptText(GtkDialog* dialog) {
     28   GtkWidget* widget = static_cast<GtkWidget*>(
     29       g_object_get_data(G_OBJECT(dialog), kPromptTextId));
     30   if (widget)
     31     return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(widget)));
     32   return string16();
     33 }
     34 
     35 // If there's a toggle button in the dialog, return the toggled state.
     36 // Otherwise, return false.
     37 bool ShouldSuppressJSDialogs(GtkDialog* dialog) {
     38   GtkWidget* widget = static_cast<GtkWidget*>(
     39       g_object_get_data(G_OBJECT(dialog), kSuppressCheckboxId));
     40   if (widget)
     41     return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
     42   return false;
     43 }
     44 
     45 }  // namespace
     46 
     47 ////////////////////////////////////////////////////////////////////////////////
     48 // JavaScriptAppModalDialogGtk, public:
     49 
     50 JavaScriptAppModalDialogGtk::JavaScriptAppModalDialogGtk(
     51     JavaScriptAppModalDialog* dialog,
     52     gfx::NativeWindow parent_window)
     53     : dialog_(dialog) {
     54   GtkButtonsType buttons = GTK_BUTTONS_NONE;
     55   GtkMessageType message_type = GTK_MESSAGE_OTHER;
     56 
     57   // We add in the OK button manually later because we want to focus it
     58   // explicitly.
     59   switch (dialog_->javascript_message_type()) {
     60     case content::JAVASCRIPT_MESSAGE_TYPE_ALERT:
     61       buttons = GTK_BUTTONS_NONE;
     62       message_type = GTK_MESSAGE_WARNING;
     63       break;
     64 
     65     case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
     66       if (dialog_->is_before_unload_dialog()) {
     67         // onbeforeunload also uses a confirm prompt, it just has custom
     68         // buttons.  We add the buttons using gtk_dialog_add_button below.
     69         buttons = GTK_BUTTONS_NONE;
     70       } else {
     71         buttons = GTK_BUTTONS_CANCEL;
     72       }
     73       message_type = GTK_MESSAGE_QUESTION;
     74       break;
     75 
     76     case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT:
     77       buttons = GTK_BUTTONS_CANCEL;
     78       message_type = GTK_MESSAGE_QUESTION;
     79       break;
     80 
     81     default:
     82       NOTREACHED();
     83   }
     84 
     85   // We want the alert to be app modal so put all the browser windows into the
     86   // same window group.
     87   gtk_util::MakeAppModalWindowGroup();
     88 
     89   gtk_dialog_ = gtk_message_dialog_new(parent_window,
     90       GTK_DIALOG_MODAL, message_type, buttons, "%s",
     91       UTF16ToUTF8(dialog_->message_text()).c_str());
     92   g_signal_connect(gtk_dialog_, "delete-event",
     93                    G_CALLBACK(gtk_widget_hide_on_delete), NULL);
     94   gtk_util::ApplyMessageDialogQuirks(gtk_dialog_);
     95   gtk_window_set_title(GTK_WINDOW(gtk_dialog_),
     96                        UTF16ToUTF8(dialog_->title()).c_str());
     97 
     98   // Adjust content area as needed.  Set up the prompt text entry or
     99   // suppression check box.
    100   if (dialog_->javascript_message_type() ==
    101           content::JAVASCRIPT_MESSAGE_TYPE_PROMPT) {
    102     GtkWidget* content_area =
    103         gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_));
    104     GtkWidget* text_box = gtk_entry_new();
    105     gtk_entry_set_text(GTK_ENTRY(text_box),
    106         UTF16ToUTF8(dialog_->default_prompt_text()).c_str());
    107     gtk_box_pack_start(GTK_BOX(content_area), text_box, TRUE, TRUE, 0);
    108     g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box);
    109     gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE);
    110   }
    111 
    112   if (dialog_->display_suppress_checkbox()) {
    113     GtkWidget* content_area =
    114         gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_));
    115     GtkWidget* check_box = gtk_check_button_new_with_label(
    116         l10n_util::GetStringUTF8(
    117         IDS_JAVASCRIPT_MESSAGEBOX_SUPPRESS_OPTION).c_str());
    118     gtk_box_pack_start(GTK_BOX(content_area), check_box, TRUE, TRUE, 0);
    119     g_object_set_data(G_OBJECT(gtk_dialog_), kSuppressCheckboxId, check_box);
    120   }
    121 
    122   // Adjust buttons/action area as needed.
    123   if (dialog_->is_before_unload_dialog()) {
    124     std::string button_text = l10n_util::GetStringUTF8(
    125         dialog_->is_reload() ?
    126         IDS_BEFORERELOAD_MESSAGEBOX_OK_BUTTON_LABEL :
    127         IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL);
    128     gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), button_text.c_str(),
    129         GTK_RESPONSE_OK);
    130 
    131     button_text = l10n_util::GetStringUTF8(
    132         dialog_->is_reload() ?
    133         IDS_BEFORERELOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL :
    134         IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL);
    135     gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), button_text.c_str(),
    136         GTK_RESPONSE_CANCEL);
    137   } else {
    138     // Add the OK button and focus it.
    139     GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_),
    140         GTK_STOCK_OK, GTK_RESPONSE_OK);
    141     if (dialog_->javascript_message_type() !=
    142             content::JAVASCRIPT_MESSAGE_TYPE_PROMPT)
    143       gtk_widget_grab_focus(ok_button);
    144   }
    145 
    146   gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK);
    147   g_signal_connect(gtk_dialog_, "response", G_CALLBACK(OnResponseThunk), this);
    148 }
    149 
    150 JavaScriptAppModalDialogGtk::~JavaScriptAppModalDialogGtk() {
    151 }
    152 
    153 ////////////////////////////////////////////////////////////////////////////////
    154 // JavaScriptAppModalDialogGtk, NativeAppModalDialog implementation:
    155 
    156 int JavaScriptAppModalDialogGtk::GetAppModalDialogButtons() const {
    157   switch (dialog_->javascript_message_type()) {
    158     case content::JAVASCRIPT_MESSAGE_TYPE_ALERT:
    159       return ui::DIALOG_BUTTON_OK;
    160 
    161     case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
    162       return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
    163 
    164     case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT:
    165       return ui::DIALOG_BUTTON_OK;
    166 
    167     default:
    168       NOTREACHED();
    169       return 0;
    170   }
    171 }
    172 
    173 void JavaScriptAppModalDialogGtk::ShowAppModalDialog() {
    174   gtk_util::ShowDialogWithMinLocalizedWidth(GTK_WIDGET(gtk_dialog_),
    175       IDS_ALERT_DIALOG_WIDTH_CHARS);
    176 }
    177 
    178 void JavaScriptAppModalDialogGtk::ActivateAppModalDialog() {
    179   DCHECK(gtk_dialog_);
    180   gtk_window_present(GTK_WINDOW(gtk_dialog_));
    181 }
    182 
    183 void JavaScriptAppModalDialogGtk::CloseAppModalDialog() {
    184   DCHECK(gtk_dialog_);
    185   OnResponse(gtk_dialog_, GTK_RESPONSE_DELETE_EVENT);
    186 }
    187 
    188 void JavaScriptAppModalDialogGtk::AcceptAppModalDialog() {
    189   OnResponse(gtk_dialog_, GTK_RESPONSE_OK);
    190 }
    191 
    192 void JavaScriptAppModalDialogGtk::CancelAppModalDialog() {
    193   OnResponse(gtk_dialog_, GTK_RESPONSE_CANCEL);
    194 }
    195 
    196 ////////////////////////////////////////////////////////////////////////////////
    197 // JavaScriptAppModalDialogGtk, private:
    198 
    199 void JavaScriptAppModalDialogGtk::OnResponse(GtkWidget* dialog,
    200                                              int response_id) {
    201   switch (response_id) {
    202     case GTK_RESPONSE_OK:
    203       // The first arg is the prompt text and the second is true if we want to
    204       // suppress additional popups from the page.
    205       dialog_->OnAccept(GetPromptText(GTK_DIALOG(dialog)),
    206                         ShouldSuppressJSDialogs(GTK_DIALOG(dialog)));
    207       break;
    208 
    209     case GTK_RESPONSE_CANCEL:
    210     case GTK_RESPONSE_DELETE_EVENT:   // User hit the X on the dialog.
    211       dialog_->OnCancel(ShouldSuppressJSDialogs(GTK_DIALOG(dialog)));
    212       break;
    213 
    214     default:
    215       NOTREACHED();
    216   }
    217   gtk_widget_destroy(dialog);
    218 
    219   // Now that the dialog is gone, we can put all the  windows into separate
    220   // window groups so other dialogs are no longer app modal.
    221   gtk_util::AppModalDismissedUngroupWindows();
    222   delete this;
    223 }
    224 
    225 ////////////////////////////////////////////////////////////////////////////////
    226 // NativeAppModalDialog, public:
    227 
    228 // static
    229 NativeAppModalDialog* NativeAppModalDialog::CreateNativeJavaScriptPrompt(
    230     JavaScriptAppModalDialog* dialog,
    231     gfx::NativeWindow parent_window) {
    232   return new JavaScriptAppModalDialogGtk(dialog, parent_window);
    233 }
    234