Home | History | Annotate | Download | only in ui
      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/ui/input_window_dialog.h"
      6 
      7 #include <gtk/gtk.h>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop.h"
     11 #include "base/string_piece.h"
     12 #include "base/utf_string_conversions.h"
     13 #include "chrome/browser/ui/gtk/gtk_util.h"
     14 #include "ui/base/gtk/gtk_signal.h"
     15 
     16 class InputWindowDialogGtk : public InputWindowDialog {
     17  public:
     18   // Creates a dialog. Takes ownership of |delegate|.
     19   InputWindowDialogGtk(GtkWindow* parent,
     20                        const std::string& window_title,
     21                        const std::string& label,
     22                        const std::string& contents,
     23                        Delegate* delegate);
     24   virtual ~InputWindowDialogGtk();
     25 
     26   virtual void Show();
     27   virtual void Close();
     28 
     29  private:
     30   CHROMEG_CALLBACK_0(InputWindowDialogGtk, void, OnEntryChanged, GtkEditable*);
     31   CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, void, OnResponse, int);
     32   CHROMEGTK_CALLBACK_1(InputWindowDialogGtk, gboolean,
     33                        OnWindowDeleteEvent, GdkEvent*);
     34   CHROMEGTK_CALLBACK_0(InputWindowDialogGtk, void, OnWindowDestroy);
     35 
     36   // The underlying gtk dialog window.
     37   GtkWidget* dialog_;
     38 
     39   // The GtkEntry in this form.
     40   GtkWidget* input_;
     41 
     42   // Our delegate. Consumes the window's output.
     43   scoped_ptr<InputWindowDialog::Delegate> delegate_;
     44 };
     45 
     46 
     47 InputWindowDialogGtk::InputWindowDialogGtk(GtkWindow* parent,
     48                                            const std::string& window_title,
     49                                            const std::string& label,
     50                                            const std::string& contents,
     51                                            Delegate* delegate)
     52     : dialog_(gtk_dialog_new_with_buttons(
     53                   window_title.c_str(),
     54                   parent,
     55                   GTK_DIALOG_MODAL,
     56                   GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
     57                   GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
     58                   NULL)),
     59       delegate_(delegate) {
     60   gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_ACCEPT);
     61   gtk_dialog_set_has_separator(GTK_DIALOG(dialog_), FALSE);
     62   gtk_window_set_resizable(GTK_WINDOW(dialog_), FALSE);
     63 
     64   GtkWidget* content_area = GTK_DIALOG(dialog_)->vbox;
     65   gtk_box_set_spacing(GTK_BOX(content_area), 18);
     66 
     67   GtkWidget* hbox = gtk_hbox_new(FALSE, 6);
     68   GtkWidget* label_widget = gtk_label_new(label.c_str());
     69   gtk_box_pack_start(GTK_BOX(hbox), label_widget, FALSE, FALSE, 0);
     70 
     71   input_ = gtk_entry_new();
     72   gtk_entry_set_text(GTK_ENTRY(input_), contents.c_str());
     73   g_signal_connect(input_, "changed",
     74                    G_CALLBACK(OnEntryChangedThunk), this);
     75   g_object_set(G_OBJECT(input_), "activates-default", TRUE, NULL);
     76   gtk_box_pack_start(GTK_BOX(hbox), input_, TRUE, TRUE, 0);
     77 
     78   gtk_widget_show_all(hbox);
     79 
     80   gtk_box_pack_start(GTK_BOX(content_area), hbox, FALSE, FALSE, 0);
     81 
     82   g_signal_connect(dialog_, "response",
     83                    G_CALLBACK(OnResponseThunk), this);
     84   g_signal_connect(dialog_, "delete-event",
     85                    G_CALLBACK(OnWindowDeleteEventThunk), this);
     86   g_signal_connect(dialog_, "destroy",
     87                    G_CALLBACK(OnWindowDestroyThunk), this);
     88 }
     89 
     90 InputWindowDialogGtk::~InputWindowDialogGtk() {
     91 }
     92 
     93 void InputWindowDialogGtk::Show() {
     94   gtk_util::ShowDialog(dialog_);
     95 }
     96 
     97 void InputWindowDialogGtk::Close() {
     98   // Under the model that we've inherited from Windows, dialogs can receive
     99   // more than one Close() call inside the current message loop event.
    100   if (dialog_) {
    101     gtk_widget_destroy(dialog_);
    102     dialog_ = NULL;
    103   }
    104 }
    105 
    106 void InputWindowDialogGtk::OnEntryChanged(GtkEditable* entry) {
    107   std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(entry))));
    108   gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog_),
    109                                     GTK_RESPONSE_ACCEPT,
    110                                     delegate_->IsValid(value));
    111 }
    112 
    113 void InputWindowDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
    114   if (response_id == GTK_RESPONSE_ACCEPT) {
    115     std::wstring value(UTF8ToWide(gtk_entry_get_text(GTK_ENTRY(input_))));
    116     delegate_->InputAccepted(value);
    117   } else {
    118     delegate_->InputCanceled();
    119   }
    120   Close();
    121 }
    122 
    123 gboolean InputWindowDialogGtk::OnWindowDeleteEvent(GtkWidget* widget,
    124                                                    GdkEvent* event) {
    125   Close();
    126 
    127   // Return true to prevent the gtk dialog from being destroyed. Close will
    128   // destroy it for us and the default gtk_dialog_delete_event_handler() will
    129   // force the destruction without us being able to stop it.
    130   return TRUE;
    131 }
    132 
    133 void InputWindowDialogGtk::OnWindowDestroy(GtkWidget* widget) {
    134   MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    135 }
    136 
    137 InputWindowDialog* InputWindowDialog::Create(gfx::NativeWindow parent,
    138                                              const std::wstring& window_title,
    139                                              const std::wstring& label,
    140                                              const std::wstring& contents,
    141                                              Delegate* delegate) {
    142   return new InputWindowDialogGtk(parent,
    143                                   WideToUTF8(window_title),
    144                                   WideToUTF8(label),
    145                                   WideToUTF8(contents),
    146                                   delegate);
    147 }
    148