Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(262)

Side by Side Diff: chrome/browser/ui/gtk/create_application_shortcuts_dialog_gtk.cc

Issue 231733005: Delete the GTK+ port of Chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remerge to ToT Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/create_application_shortcuts_dialog_gtk.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/environment.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/shell_integration.h"
14 #include "chrome/browser/shell_integration_linux.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_commands.h"
17 #include "chrome/browser/ui/browser_dialogs.h"
18 #include "chrome/browser/ui/browser_finder.h"
19 #include "chrome/browser/ui/gtk/gtk_util.h"
20 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
21 #include "chrome/browser/web_applications/web_app.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_contents_delegate.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/manifest_handlers/icons_handler.h"
27 #include "grit/chromium_strings.h"
28 #include "grit/generated_resources.h"
29 #include "grit/locale_settings.h"
30 #include "grit/theme_resources.h"
31 #include "ui/base/gtk/gtk_hig_constants.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/gfx/gtk_util.h"
34 #include "ui/gfx/image/image.h"
35 #include "ui/gfx/image/image_family.h"
36 #include "ui/gfx/image/image_skia.h"
37
38 using content::BrowserThread;
39 using extensions::Extension;
40
41 namespace {
42
43 // Size (in pixels) of the icon preview.
44 const int kIconPreviewSizePixels = 32;
45
46 // Minimum width (in pixels) of the shortcut description label.
47 const int kDescriptionLabelMinimumWidthPixels = 200;
48
49 } // namespace
50
51 namespace chrome {
52
53 void ShowCreateWebAppShortcutsDialog(gfx::NativeWindow parent_window,
54 content::WebContents* web_contents) {
55 new CreateWebApplicationShortcutsDialogGtk(parent_window, web_contents);
56 }
57
58 void ShowCreateChromeAppShortcutsDialog(
59 gfx::NativeWindow parent_window,
60 Profile* profile,
61 const extensions::Extension* app,
62 const base::Closure& close_callback) {
63 new CreateChromeApplicationShortcutsDialogGtk(parent_window, profile, app,
64 close_callback);
65 }
66
67 } // namespace chrome
68
69 CreateApplicationShortcutsDialogGtk::CreateApplicationShortcutsDialogGtk(
70 GtkWindow* parent)
71 : parent_(parent),
72 desktop_checkbox_(NULL),
73 menu_checkbox_(NULL),
74 favicon_pixbuf_(NULL),
75 create_dialog_(NULL),
76 error_dialog_(NULL) {
77 DCHECK_CURRENTLY_ON(BrowserThread::UI);
78
79 // Will be balanced by Release later.
80 AddRef();
81 }
82
83 void CreateApplicationShortcutsDialogGtk::CreateIconPixBuf(
84 const gfx::ImageFamily& image) {
85 // Get the icon closest to the desired preview size.
86 const gfx::Image* icon = image.GetBest(kIconPreviewSizePixels,
87 kIconPreviewSizePixels);
88 // There must be at least one icon in the image family.
89 CHECK(icon);
90 GdkPixbuf* pixbuf = icon->CopyGdkPixbuf();
91 // Prepare the icon. Scale it to the correct size to display in the dialog.
92 int pixbuf_width = gdk_pixbuf_get_width(pixbuf);
93 int pixbuf_height = gdk_pixbuf_get_height(pixbuf);
94 if (pixbuf_width == pixbuf_height) {
95 // Only scale the pixbuf if it's a square (for simplicity).
96 // Generally it should be square, if it's a favicon or app icon.
97 // Use the highest quality interpolation.
98 favicon_pixbuf_ = gdk_pixbuf_scale_simple(pixbuf,
99 kIconPreviewSizePixels,
100 kIconPreviewSizePixels,
101 GDK_INTERP_HYPER);
102 g_object_unref(pixbuf);
103 } else {
104 favicon_pixbuf_ = pixbuf;
105 }
106 }
107
108 void CreateApplicationShortcutsDialogGtk::CreateDialogBox(GtkWindow* parent) {
109 // Build the dialog.
110 create_dialog_ = gtk_dialog_new_with_buttons(
111 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_TITLE).c_str(),
112 parent,
113 (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR),
114 NULL);
115 gtk_widget_realize(create_dialog_);
116 gtk_window_set_resizable(GTK_WINDOW(create_dialog_), false);
117 gtk_util::AddButtonToDialog(create_dialog_,
118 l10n_util::GetStringUTF8(IDS_CANCEL).c_str(),
119 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
120 gtk_util::AddButtonToDialog(create_dialog_,
121 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_COMMIT).c_str(),
122 GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT);
123
124 GtkWidget* content_area =
125 gtk_dialog_get_content_area(GTK_DIALOG(create_dialog_));
126 gtk_box_set_spacing(GTK_BOX(content_area), ui::kContentAreaSpacing);
127
128 GtkWidget* vbox = gtk_vbox_new(FALSE, ui::kControlSpacing);
129 gtk_container_add(GTK_CONTAINER(content_area), vbox);
130
131 // Create a box containing basic information about the new shortcut: an image
132 // on the left, and a description on the right.
133 GtkWidget* hbox = gtk_hbox_new(FALSE, ui::kControlSpacing);
134 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
135 gtk_container_set_border_width(GTK_CONTAINER(hbox),
136 ui::kControlSpacing);
137
138 // Put the icon preview in place.
139 GtkWidget* favicon_image = gtk_image_new_from_pixbuf(favicon_pixbuf_);
140 gtk_box_pack_start(GTK_BOX(hbox), favicon_image, FALSE, FALSE, 0);
141
142 // Create the label with application shortcut description.
143 GtkWidget* description_label = gtk_label_new(NULL);
144 gtk_box_pack_start(GTK_BOX(hbox), description_label, FALSE, FALSE, 0);
145 gtk_label_set_line_wrap(GTK_LABEL(description_label), TRUE);
146 gtk_widget_realize(description_label);
147
148 // Set the size request on the label so it knows where to line wrap. The width
149 // is the desired size of the dialog less the space reserved for padding and
150 // the image.
151 int label_width;
152 gtk_util::GetWidgetSizeFromResources(
153 description_label,
154 IDS_CREATE_SHORTCUTS_DIALOG_WIDTH_CHARS, -1, &label_width, NULL);
155 label_width -= ui::kControlSpacing * 3 +
156 gdk_pixbuf_get_width(favicon_pixbuf_);
157 // Enforce a minimum width, so that very large icons do not cause the label
158 // width to shrink to unreadable size, or become negative (which would crash).
159 if (label_width < kDescriptionLabelMinimumWidthPixels)
160 label_width = kDescriptionLabelMinimumWidthPixels;
161 gtk_util::SetLabelWidth(description_label, label_width);
162
163 std::string description(base::UTF16ToUTF8(shortcut_info_.description));
164 std::string title(base::UTF16ToUTF8(shortcut_info_.title));
165 gtk_label_set_text(GTK_LABEL(description_label),
166 (description.empty() ? title : description).c_str());
167
168 // Label on top of the checkboxes.
169 GtkWidget* checkboxes_label = gtk_label_new(
170 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_LABEL).c_str());
171 gtk_misc_set_alignment(GTK_MISC(checkboxes_label), 0, 0);
172 gtk_box_pack_start(GTK_BOX(vbox), checkboxes_label, FALSE, FALSE, 0);
173
174 // Desktop checkbox.
175 desktop_checkbox_ = gtk_check_button_new_with_label(
176 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_DESKTOP_CHKBOX).c_str());
177 gtk_box_pack_start(GTK_BOX(vbox), desktop_checkbox_, FALSE, FALSE, 0);
178 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(desktop_checkbox_), true);
179 g_signal_connect(desktop_checkbox_, "toggled",
180 G_CALLBACK(OnToggleCheckboxThunk), this);
181
182 // Menu checkbox.
183 menu_checkbox_ = gtk_check_button_new_with_label(
184 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_MENU_CHKBOX).c_str());
185 gtk_box_pack_start(GTK_BOX(vbox), menu_checkbox_, FALSE, FALSE, 0);
186 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(menu_checkbox_), false);
187 g_signal_connect(menu_checkbox_, "toggled",
188 G_CALLBACK(OnToggleCheckboxThunk), this);
189
190 g_signal_connect(create_dialog_, "response",
191 G_CALLBACK(OnCreateDialogResponseThunk), this);
192 gtk_widget_show_all(create_dialog_);
193 }
194
195 CreateApplicationShortcutsDialogGtk::~CreateApplicationShortcutsDialogGtk() {
196 DCHECK_CURRENTLY_ON(BrowserThread::UI);
197
198 gtk_widget_destroy(create_dialog_);
199
200 if (error_dialog_)
201 gtk_widget_destroy(error_dialog_);
202
203 g_object_unref(favicon_pixbuf_);
204 }
205
206 void CreateApplicationShortcutsDialogGtk::OnCreateDialogResponse(
207 GtkWidget* widget, int response) {
208 DCHECK_CURRENTLY_ON(BrowserThread::UI);
209
210 if (response == GTK_RESPONSE_ACCEPT) {
211 ShellIntegration::ShortcutLocations creation_locations;
212 creation_locations.on_desktop =
213 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(desktop_checkbox_));
214 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(menu_checkbox_))) {
215 creation_locations.applications_menu_location =
216 create_in_chrome_apps_subdir_ ?
217 ShellIntegration::APP_MENU_LOCATION_SUBDIR_CHROMEAPPS :
218 ShellIntegration::APP_MENU_LOCATION_ROOT;
219 }
220 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
221 base::Bind(&CreateApplicationShortcutsDialogGtk::CreateDesktopShortcut,
222 this, shortcut_info_, creation_locations));
223
224 OnCreatedShortcut();
225 } else {
226 Release();
227 }
228 }
229
230 void CreateApplicationShortcutsDialogGtk::OnErrorDialogResponse(
231 GtkWidget* widget, int response) {
232 Release();
233 }
234
235 void CreateApplicationShortcutsDialogGtk::CreateDesktopShortcut(
236 const ShellIntegration::ShortcutInfo& shortcut_info,
237 const ShellIntegration::ShortcutLocations& creation_locations) {
238 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
239 ShellIntegrationLinux::CreateDesktopShortcut(shortcut_info,
240 creation_locations);
241 Release();
242 }
243
244 void CreateApplicationShortcutsDialogGtk::ShowErrorDialog() {
245 DCHECK_CURRENTLY_ON(BrowserThread::UI);
246
247 // Hide the create dialog so that the user can no longer interact with it.
248 gtk_widget_hide(create_dialog_);
249
250 error_dialog_ = gtk_dialog_new_with_buttons(
251 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_ERROR_TITLE).c_str(),
252 NULL,
253 (GtkDialogFlags) (GTK_DIALOG_NO_SEPARATOR),
254 GTK_STOCK_OK,
255 GTK_RESPONSE_ACCEPT,
256 NULL);
257 gtk_widget_realize(error_dialog_);
258 gtk_util::SetWindowSizeFromResources(
259 GTK_WINDOW(error_dialog_),
260 IDS_CREATE_SHORTCUTS_ERROR_DIALOG_WIDTH_CHARS,
261 IDS_CREATE_SHORTCUTS_ERROR_DIALOG_HEIGHT_LINES,
262 false); // resizable
263 GtkWidget* content_area =
264 gtk_dialog_get_content_area(GTK_DIALOG(error_dialog_));
265 gtk_box_set_spacing(GTK_BOX(content_area), ui::kContentAreaSpacing);
266
267 GtkWidget* vbox = gtk_vbox_new(FALSE, ui::kControlSpacing);
268 gtk_container_add(GTK_CONTAINER(content_area), vbox);
269
270 // Label on top of the checkboxes.
271 GtkWidget* description = gtk_label_new(
272 l10n_util::GetStringUTF8(IDS_CREATE_SHORTCUTS_ERROR_LABEL).c_str());
273 gtk_label_set_line_wrap(GTK_LABEL(description), TRUE);
274 gtk_misc_set_alignment(GTK_MISC(description), 0, 0);
275 gtk_box_pack_start(GTK_BOX(vbox), description, FALSE, FALSE, 0);
276
277 g_signal_connect(error_dialog_, "response",
278 G_CALLBACK(OnErrorDialogResponseThunk), this);
279 gtk_widget_show_all(error_dialog_);
280 }
281
282 void CreateApplicationShortcutsDialogGtk::OnToggleCheckbox(GtkWidget* sender) {
283 gboolean can_accept = FALSE;
284
285 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(desktop_checkbox_)) ||
286 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(menu_checkbox_))) {
287 can_accept = TRUE;
288 }
289
290 gtk_dialog_set_response_sensitive(GTK_DIALOG(create_dialog_),
291 GTK_RESPONSE_ACCEPT,
292 can_accept);
293 }
294
295 CreateWebApplicationShortcutsDialogGtk::CreateWebApplicationShortcutsDialogGtk(
296 GtkWindow* parent,
297 content::WebContents* web_contents)
298 : CreateApplicationShortcutsDialogGtk(parent),
299 web_contents_(web_contents) {
300
301 // Get shortcut information now, it's needed for our UI.
302 web_app::GetShortcutInfoForTab(web_contents, &shortcut_info_);
303 CreateIconPixBuf(shortcut_info_.favicon);
304
305 // Create URL app shortcuts in the top-level menu.
306 create_in_chrome_apps_subdir_ = false;
307
308 CreateDialogBox(parent);
309 }
310
311 void CreateWebApplicationShortcutsDialogGtk::OnCreatedShortcut() {
312 Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
313 if (browser)
314 chrome::ConvertTabToAppWindow(browser, web_contents_);
315 }
316
317 CreateChromeApplicationShortcutsDialogGtk::
318 CreateChromeApplicationShortcutsDialogGtk(
319 GtkWindow* parent,
320 Profile* profile,
321 const Extension* app,
322 const base::Closure& close_callback)
323 : CreateApplicationShortcutsDialogGtk(parent),
324 app_(app),
325 profile_path_(profile->GetPath()),
326 close_callback_(close_callback) {
327
328 // Place Chrome app shortcuts in the "Chrome Apps" submenu.
329 create_in_chrome_apps_subdir_ = true;
330
331 // Get shortcut information and icon now; they are needed for our UI.
332 web_app::UpdateShortcutInfoAndIconForApp(
333 app, profile,
334 base::Bind(
335 &CreateChromeApplicationShortcutsDialogGtk::OnShortcutInfoLoaded,
336 this));
337 }
338
339 CreateChromeApplicationShortcutsDialogGtk::
340 ~CreateChromeApplicationShortcutsDialogGtk() {
341 if (!close_callback_.is_null())
342 close_callback_.Run();
343 }
344
345 // Called when the app's ShortcutInfo (with icon) is loaded.
346 void CreateChromeApplicationShortcutsDialogGtk::OnShortcutInfoLoaded(
347 const ShellIntegration::ShortcutInfo& shortcut_info) {
348 shortcut_info_ = shortcut_info;
349
350 CreateIconPixBuf(shortcut_info_.favicon);
351 CreateDialogBox(parent_);
352 }
353
354 void CreateChromeApplicationShortcutsDialogGtk::CreateDesktopShortcut(
355 const ShellIntegration::ShortcutInfo& shortcut_info,
356 const ShellIntegration::ShortcutLocations& creation_locations) {
357 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
358
359 if (web_app::internals::CreateShortcutsOnFileThread(
360 web_app::SHORTCUT_CREATION_BY_USER,
361 creation_locations,
362 shortcut_info)) {
363 Release();
364 } else {
365 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
366 base::Bind(&CreateChromeApplicationShortcutsDialogGtk::ShowErrorDialog,
367 this));
368 }
369 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698