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
InputWindowDialogGtk(GtkWindow * parent,const std::string & window_title,const std::string & label,const std::string & contents,Delegate * delegate)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
~InputWindowDialogGtk()90 InputWindowDialogGtk::~InputWindowDialogGtk() {
91 }
92
Show()93 void InputWindowDialogGtk::Show() {
94 gtk_util::ShowDialog(dialog_);
95 }
96
Close()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
OnEntryChanged(GtkEditable * entry)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
OnResponse(GtkWidget * dialog,int response_id)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
OnWindowDeleteEvent(GtkWidget * widget,GdkEvent * event)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
OnWindowDestroy(GtkWidget * widget)133 void InputWindowDialogGtk::OnWindowDestroy(GtkWidget* widget) {
134 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
135 }
136
Create(gfx::NativeWindow parent,const std::wstring & window_title,const std::wstring & label,const std::wstring & contents,Delegate * delegate)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