summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/file_util.h4
-rw-r--r--base/file_util_posix.cc7
-rw-r--r--base/file_util_win.cc10
-rw-r--r--base/string_util.cc36
-rw-r--r--base/string_util.h8
-rw-r--r--base/string_util_unittest.cc26
-rw-r--r--chrome/app/generated_resources.grd13
-rw-r--r--chrome/app/theme/download_button_right_bottom_no_dd.pngbin0 -> 297 bytes
-rw-r--r--chrome/app/theme/download_button_right_middle_no_dd.pngbin0 -> 123 bytes
-rw-r--r--chrome/app/theme/download_button_right_top_no_dd.pngbin0 -> 356 bytes
-rw-r--r--chrome/app/theme/theme_resources.h602
-rw-r--r--chrome/app/theme/theme_resources.rc3
-rw-r--r--chrome/browser/download/download_exe.cc3
-rw-r--r--chrome/browser/download/download_file.cc6
-rw-r--r--chrome/browser/download/download_file.h3
-rw-r--r--chrome/browser/download/download_manager.cc250
-rw-r--r--chrome/browser/download/download_manager.h79
-rw-r--r--chrome/browser/download/download_util.cc2
-rw-r--r--chrome/browser/download/save_package.cc6
-rw-r--r--chrome/browser/history/download_database.cc14
-rw-r--r--chrome/browser/history/download_database.h3
-rw-r--r--chrome/browser/history/download_types.h7
-rw-r--r--chrome/browser/history/history.cc6
-rw-r--r--chrome/browser/history/history.h4
-rw-r--r--chrome/browser/history/history_backend.cc7
-rw-r--r--chrome/browser/history/history_backend.h1
-rw-r--r--chrome/browser/resource_dispatcher_host.cc1
-rw-r--r--chrome/browser/views/download_item_view.cc369
-rw-r--r--chrome/browser/views/download_item_view.h47
-rw-r--r--chrome/browser/views/download_tab_view.cc190
-rw-r--r--chrome/browser/views/download_tab_view.h30
-rw-r--r--chrome/views/native_button.cc25
-rw-r--r--chrome/views/native_button.h8
33 files changed, 1334 insertions, 436 deletions
diff --git a/base/file_util.h b/base/file_util.h
index 9624e60..150b629 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -224,6 +224,10 @@ bool GetTempDir(std::wstring* path);
// TODO(erikkay): rename this function and track down all of the callers.
bool CreateTemporaryFileName(std::wstring* temp_file);
+// Same as CreateTemporaryFileName but the file is created in |dir|.
+bool CreateTemporaryFileNameInDir(const std::wstring& dir,
+ std::wstring* temp_file);
+
// Create a new directory under TempPath. If prefix is provided, the new
// directory name is in the format of prefixyyyy.
// If success, return true and output the full path of the directory created.
diff --git a/base/file_util_posix.cc b/base/file_util_posix.cc
index edb20c7..e440640 100644
--- a/base/file_util_posix.cc
+++ b/base/file_util_posix.cc
@@ -267,6 +267,13 @@ bool CreateTemporaryFileName(std::wstring* temp_file) {
return true;
}
+bool CreateTemporaryFileNameInDir(const std::wstring& dir,
+ std::wstring* temp_file) {
+ // Not implemented yet.
+ NOTREACHED();
+ return false;
+}
+
bool CreateNewTempDirectory(const std::wstring& prefix,
std::wstring* new_temp_path) {
std::wstring tmpdir;
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
index 8253e53..7be172f 100644
--- a/base/file_util_win.cc
+++ b/base/file_util_win.cc
@@ -383,13 +383,19 @@ bool GetTempDir(std::wstring* path) {
}
bool CreateTemporaryFileName(std::wstring* temp_file) {
- wchar_t temp_name[MAX_PATH + 1];
std::wstring temp_path;
if (!GetTempDir(&temp_path))
return false;
- if (!GetTempFileName(temp_path.c_str(), L"", 0, temp_name))
+ return CreateTemporaryFileNameInDir(temp_path, temp_file);
+}
+
+bool CreateTemporaryFileNameInDir(const std::wstring& dir,
+ std::wstring* temp_file) {
+ wchar_t temp_name[MAX_PATH + 1];
+
+ if (!GetTempFileName(dir.c_str(), L"", 0, temp_name))
return false; // fail!
DWORD path_len = GetLongPathName(temp_name, temp_name, MAX_PATH);
diff --git a/base/string_util.cc b/base/string_util.cc
index 223c485..5fa2f75 100644
--- a/base/string_util.cc
+++ b/base/string_util.cc
@@ -1434,3 +1434,39 @@ size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
return lcpyT<wchar_t>(dst, src, dst_size);
}
+bool ElideString(const std::wstring& input, int max_len, std::wstring* output) {
+ DCHECK(max_len >= 0);
+ if (static_cast<int>(input.length()) <= max_len) {
+ output->assign(input);
+ return false;
+ }
+
+ switch (max_len) {
+ case 0:
+ output->clear();
+ break;
+ case 1:
+ output->assign(input.substr(0, 1));
+ break;
+ case 2:
+ output->assign(input.substr(0, 2));
+ break;
+ case 3:
+ output->assign(input.substr(0, 1) + L"." +
+ input.substr(input.length() - 1));
+ break;
+ case 4:
+ output->assign(input.substr(0, 1) + L".." +
+ input.substr(input.length() - 1));
+ break;
+ default: {
+ int rstr_len = (max_len - 3) / 2;
+ int lstr_len = rstr_len + ((max_len - 3) % 2);
+ output->assign(input.substr(0, lstr_len) + L"..." +
+ input.substr(input.length() - rstr_len));
+ break;
+ }
+ }
+
+ return true;
+}
diff --git a/base/string_util.h b/base/string_util.h
index a9f08c4..981cd30 100644
--- a/base/string_util.h
+++ b/base/string_util.h
@@ -508,6 +508,14 @@ std::wstring ReplaceStringPlaceholders(const std::wstring& format_string,
const std::wstring& d,
std::vector<size_t>* offsets);
+// If the size of |input| is more than |max_len|, this function returns true and
+// |input| is shortened into |output| by removing chars in the middle (they are
+// replaced with up to 3 dots, as size permits).
+// Ex: ElideString(L"Hello", 10, &str) puts Hello in str and returns false.
+// ElideString(L"Hello my name is Tom", 10, &str) puts "Hell...Tom" in str and
+// returns true.
+bool ElideString(const std::wstring& input, int max_len, std::wstring* output);
+
// Returns true if the string passed in matches the pattern. The pattern
// string can contain wildcards like * and ?
// TODO(iyengar) This function may not work correctly for CJK strings as
diff --git a/base/string_util_unittest.cc b/base/string_util_unittest.cc
index e438ebb..25f43c6 100644
--- a/base/string_util_unittest.cc
+++ b/base/string_util_unittest.cc
@@ -1380,3 +1380,29 @@ TEST(StringUtilTest, WprintfFormatPortabilityTest) {
}
}
+TEST(StringUtilTest, ElideString) {
+ struct TestData {
+ const wchar_t* input;
+ int max_len;
+ bool result;
+ const wchar_t* output;
+ } cases[] = {
+ { L"Hello", 0, true, L"" },
+ { L"", 0, false, L"" },
+ { L"Hello, my name is Tom", 1, true, L"H" },
+ { L"Hello, my name is Tom", 2, true, L"He" },
+ { L"Hello, my name is Tom", 3, true, L"H.m" },
+ { L"Hello, my name is Tom", 4, true, L"H..m" },
+ { L"Hello, my name is Tom", 5, true, L"H...m" },
+ { L"Hello, my name is Tom", 6, true, L"He...m" },
+ { L"Hello, my name is Tom", 7, true, L"He...om" },
+ { L"Hello, my name is Tom", 10, true, L"Hell...Tom" },
+ { L"Hello, my name is Tom", 100, false, L"Hello, my name is Tom" }
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ std::wstring output;
+ EXPECT_EQ(cases[i].result,
+ ElideString(cases[i].input, cases[i].max_len, &output));
+ EXPECT_TRUE(output == cases[i].output);
+ }
+}
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 4ac4e2c..d9a3c38 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1145,6 +1145,19 @@ each locale. -->
Cancel
</message>
+ <message name="IDS_PROMPT_DANGEROUS_DOWNLOAD"
+ desc="Message shown to the user to validate the download of a dangerous file.">
+ This type of file can harm your computer. Are you sure you want to download <ph name="FILE_NAME">$1<ex>malware.exe</ex></ph>?
+ </message>
+ <message name="IDS_SAVE_DOWNLOAD"
+ desc="Text for the button used to validate the downloading of a dangerous download.">
+ Save
+ </message>
+ <message name="IDS_DISCARD_DOWNLOAD"
+ desc="Text for the button used to stop a dangerous download.">
+ Discard
+ </message>
+
<!-- Download Tab Items -->
<message name="IDS_DOWNLOAD_LINK_PAUSE"
desc="In the download view, 'Pause' link text">
diff --git a/chrome/app/theme/download_button_right_bottom_no_dd.png b/chrome/app/theme/download_button_right_bottom_no_dd.png
new file mode 100644
index 0000000..4c9d3db
--- /dev/null
+++ b/chrome/app/theme/download_button_right_bottom_no_dd.png
Binary files differ
diff --git a/chrome/app/theme/download_button_right_middle_no_dd.png b/chrome/app/theme/download_button_right_middle_no_dd.png
new file mode 100644
index 0000000..df2cf9e
--- /dev/null
+++ b/chrome/app/theme/download_button_right_middle_no_dd.png
Binary files differ
diff --git a/chrome/app/theme/download_button_right_top_no_dd.png b/chrome/app/theme/download_button_right_top_no_dd.png
new file mode 100644
index 0000000..f57fd85
--- /dev/null
+++ b/chrome/app/theme/download_button_right_top_no_dd.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.h b/chrome/app/theme/theme_resources.h
index 242bf45..a4cba37 100644
--- a/chrome/app/theme/theme_resources.h
+++ b/chrome/app/theme/theme_resources.h
@@ -12,303 +12,305 @@
#define IDR_CLOSE 9004
#define IDR_CLOSE_H 9005
#define IDR_CLOSE_P 9006
-#define IDR_CONTENT_BOTTOM_CENTER 9009
-#define IDR_CONTENT_BOTTOM_LEFT_CORNER 9010
-#define IDR_CONTENT_BOTTOM_RIGHT_CORNER 9011
-#define IDR_CONTENT_LEFT_SIDE 9012
-#define IDR_CONTENT_RIGHT_SIDE 9013
-#define IDR_CONTENT_TOP_CENTER 9014
-#define IDR_CONTENT_TOP_LEFT_CORNER 9015
-#define IDR_CONTENT_TOP_RIGHT_CORNER 9016
-#define IDR_DEFAULT_FAVICON 9017
-#define IDR_DROP 9018
-#define IDR_DROP_H 9019
-#define IDR_DROP_P 9020
-#define IDR_FORWARD 9021
-#define IDR_FORWARD_D 9022
-#define IDR_FORWARD_H 9023
-#define IDR_FORWARD_P 9024
-#define IDR_GO 9025
-#define IDR_GO_H 9026
-#define IDR_GO_P 9027
-#define IDR_INFO_BUBBLE_CLOSE 9028
-#define IDR_LOCATIONBG 9029
-#define IDR_MAXIMIZE 9030
-#define IDR_MAXIMIZE_H 9031
-#define IDR_MAXIMIZE_P 9032
-#define IDR_MENUITEM_CENTER_A 9033
-#define IDR_MENUITEM_CENTER_H 9034
-#define IDR_MENUITEM_LEFT_A 9035
-#define IDR_MENUITEM_LEFT_H 9036
-#define IDR_MENUITEM_RIGHT_A 9037
-#define IDR_MENUITEM_RIGHT_H 9038
-#define IDR_MINIMIZE 9039
-#define IDR_MINIMIZE_H 9040
-#define IDR_MINIMIZE_P 9041
-#define IDR_PLUGIN 9042
-#define IDR_RELOAD 9043
-#define IDR_RELOAD_H 9044
-#define IDR_RELOAD_P 9045
-#define IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_C 9046
-#define IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_L 9047
-#define IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_R 9048
-#define IDR_STAR 9076
-#define IDR_STAR_D 9077
-#define IDR_STAR_H 9078
-#define IDR_STAR_P 9079
-#define IDR_STARRED 9080
-#define IDR_STARRED_H 9081
-#define IDR_STARRED_P 9082
-#define IDR_TAB_ACTIVE_CENTER 9086
-#define IDR_TAB_ACTIVE_LEFT 9087
-#define IDR_TAB_ACTIVE_RIGHT 9088
-#define IDR_TAB_CLOSE 9089
-#define IDR_TAB_CLOSE_H 9090
-#define IDR_TAB_CLOSE_P 9091
-#define IDR_TAB_INACTIVE_CENTER 9092
-#define IDR_TAB_INACTIVE_LEFT 9093
-#define IDR_TAB_INACTIVE_RIGHT 9094
-#define IDR_THROBBER 9095
-#define IDR_TOOLBAR_TOGGLE_KNOB 9096
-#define IDR_TOOLBAR_TOGGLE_TRACK 9097
-#define IDR_WINDOW_BOTTOM_CENTER 9098
-#define IDR_WINDOW_BOTTOM_LEFT_CORNER 9099
-#define IDR_WINDOW_BOTTOM_RIGHT_CORNER 9100
-#define IDR_WINDOW_LEFT_SIDE 9101
-#define IDR_WINDOW_RIGHT_SIDE 9102
-#define IDR_WINDOW_TOP_CENTER 9103
-#define IDR_WINDOW_TOP_LEFT_CORNER 9104
-#define IDR_WINDOW_TOP_RIGHT_CORNER 9105
-#define IDR_WINDOW_BOTTOM_CENTER_OTR 9106
-#define IDR_WINDOW_BOTTOM_LEFT_CORNER_OTR 9107
-#define IDR_WINDOW_BOTTOM_RIGHT_CORNER_OTR 9108
-#define IDR_WINDOW_LEFT_SIDE_OTR 9109
-#define IDR_WINDOW_RIGHT_SIDE_OTR 9110
-#define IDR_WINDOW_TOP_CENTER_OTR 9111
-#define IDR_WINDOW_TOP_LEFT_CORNER_OTR 9112
-#define IDR_WINDOW_TOP_RIGHT_CORNER_OTR 9113
-#define IDR_TAB_INACTIVE_CENTER_V 9114
-#define IDR_TAB_INACTIVE_LEFT_V 9115
-#define IDR_TAB_INACTIVE_RIGHT_V 9116
-#define IDR_RESTORE 9117
-#define IDR_RESTORE_H 9118
-#define IDR_RESTORE_P 9119
-#define IDR_DEWINDOW_BOTTOM_CENTER 9120
-#define IDR_DEWINDOW_BOTTOM_LEFT_CORNER 9121
-#define IDR_DEWINDOW_BOTTOM_RIGHT_CORNER 9122
-#define IDR_DEWINDOW_LEFT_SIDE 9123
-#define IDR_DEWINDOW_RIGHT_SIDE 9124
-#define IDR_DEWINDOW_TOP_CENTER 9125
-#define IDR_DEWINDOW_TOP_LEFT_CORNER 9126
-#define IDR_DEWINDOW_TOP_RIGHT_CORNER 9127
-#define IDR_DEWINDOW_BOTTOM_CENTER_OTR 9128
-#define IDR_DEWINDOW_BOTTOM_LEFT_CORNER_OTR 9129
-#define IDR_DEWINDOW_BOTTOM_RIGHT_CORNER_OTR 9130
-#define IDR_DEWINDOW_LEFT_SIDE_OTR 9131
-#define IDR_DEWINDOW_RIGHT_SIDE_OTR 9132
-#define IDR_DEWINDOW_TOP_CENTER_OTR 9133
-#define IDR_DEWINDOW_TOP_LEFT_CORNER_OTR 9134
-#define IDR_DEWINDOW_TOP_RIGHT_CORNER_OTR 9135
-#define IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM 9137
-#define IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_H 9138
-#define IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_P 9139
-#define IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE 9140
-#define IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_H 9141
-#define IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_P 9142
-#define IDR_DOWNLOAD_BUTTON_CENTER_TOP 9143
-#define IDR_DOWNLOAD_BUTTON_CENTER_TOP_H 9144
-#define IDR_DOWNLOAD_BUTTON_CENTER_TOP_P 9145
-#define IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM 9146
-#define IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_H 9147
-#define IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_P 9148
-#define IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE 9149
-#define IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_H 9150
-#define IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_P 9151
-#define IDR_DOWNLOAD_BUTTON_LEFT_TOP 9152
-#define IDR_DOWNLOAD_BUTTON_LEFT_TOP_H 9153
-#define IDR_DOWNLOAD_BUTTON_LEFT_TOP_P 9154
-#define IDR_DOWNLOAD_BUTTON_MENU_BOTTOM 9155
-#define IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_H 9156
-#define IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_P 9157
-#define IDR_DOWNLOAD_BUTTON_MENU_MIDDLE 9158
-#define IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_H 9159
-#define IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_P 9160
-#define IDR_DOWNLOAD_BUTTON_MENU_TOP 9161
-#define IDR_DOWNLOAD_BUTTON_MENU_TOP_H 9162
-#define IDR_DOWNLOAD_BUTTON_MENU_TOP_P 9163
-#define IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM 9164
-#define IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_H 9165
-#define IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_P 9166
-#define IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE 9167
-#define IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_H 9168
-#define IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_P 9169
-#define IDR_DOWNLOAD_BUTTON_RIGHT_TOP 9170
-#define IDR_DOWNLOAD_BUTTON_RIGHT_TOP_H 9171
-#define IDR_DOWNLOAD_BUTTON_RIGHT_TOP_P 9172
-#define IDR_DOWNLOAD_PROGRESS_BACKGROUND_16 9173
-#define IDR_DOWNLOAD_PROGRESS_FOREGROUND_16 9174
-#define IDR_DOWNLOAD_PROGRESS_BACKGROUND_32 9175
-#define IDR_DOWNLOAD_PROGRESS_FOREGROUND_32 9176
-#define IDR_DOWNLOAD_ICON 9177
-#define IDR_COOKIE_ICON 9178
-#define IDR_SAD_FAVICON 9179
-#define IDR_TAB_DROP_UP 9180
-#define IDR_TAB_DROP_DOWN 9181
-#define IDR_CONSTRAINED_BOTTOM_CENTER 9182
-#define IDR_CONSTRAINED_BOTTOM_LEFT_CORNER 9183
-#define IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER 9184
-#define IDR_CONSTRAINED_LEFT_SIDE 9185
-#define IDR_CONSTRAINED_RIGHT_SIDE 9186
-#define IDR_CONSTRAINED_TOP_CENTER 9187
-#define IDR_CONSTRAINED_TOP_LEFT_CORNER 9188
-#define IDR_CONSTRAINED_TOP_RIGHT_CORNER 9189
-#define IDR_FIND_BOX_BACKGROUND 9190
-#define IDR_FIND_BOX_BACKGROUND_LEFT 9191
-#define IDR_LOCK 9192
-#define IDR_WARNING 9193
-#define IDR_BOOKMARK_BAR_RECENTLY_BOOKMARKED_ICON 9195
-#define IDR_STOP 9197
-#define IDR_STOP_H 9198
-#define IDR_STOP_P 9199
-#define IDR_FIND_DLG_LEFT_BACKGROUND 9200
-#define IDR_FIND_DLG_RIGHT_BACKGROUND 9201
-#define IDR_FIND_DLG_MIDDLE_BACKGROUND 9202
-#define IDR_APP_TOP_RIGHT 9203
-#define IDR_APP_TOP_CENTER 9204
-#define IDR_APP_TOP_LEFT 9205
-#define IDR_APP_DROPARROW 9206
-#define IDR_THROBBER_01 9207
-#define IDR_THROBBER_02 9208
-#define IDR_THROBBER_03 9209
-#define IDR_THROBBER_04 9210
-#define IDR_THROBBER_05 9211
-#define IDR_THROBBER_06 9212
-#define IDR_THROBBER_07 9213
-#define IDR_THROBBER_08 9214
-#define IDR_THROBBER_09 9215
-#define IDR_THROBBER_10 9216
-#define IDR_THROBBER_11 9217
-#define IDR_THROBBER_12 9218
-#define IDR_THROBBER_13 9219
-#define IDR_THROBBER_14 9220
-#define IDR_THROBBER_15 9221
-#define IDR_THROBBER_16 9222
-#define IDR_THROBBER_17 9223
-#define IDR_THROBBER_18 9224
-#define IDR_THROBBER_19 9225
-#define IDR_THROBBER_20 9226
-#define IDR_THROBBER_21 9227
-#define IDR_THROBBER_22 9228
-#define IDR_THROBBER_23 9229
-#define IDR_THROBBER_24 9230
-#define IDR_PAGEINFO_GOOD 9231
-#define IDR_PAGEINFO_BAD 9232
-#define IDR_NEWTAB_BUTTON 9233
-#define IDR_NEWTAB_BUTTON_H 9234
-#define IDR_NEWTAB_BUTTON_P 9235
-#define IDR_ARROW_RIGHT 9236
-#define IDR_TEXTBUTTON_TOP_LEFT_H 9270
-#define IDR_TEXTBUTTON_TOP_H 9271
-#define IDR_TEXTBUTTON_TOP_RIGHT_H 9272
-#define IDR_TEXTBUTTON_LEFT_H 9273
-#define IDR_TEXTBUTTON_CENTER_H 9274
-#define IDR_TEXTBUTTON_RIGHT_H 9275
-#define IDR_TEXTBUTTON_BOTTOM_LEFT_H 9276
-#define IDR_TEXTBUTTON_BOTTOM_H 9277
-#define IDR_TEXTBUTTON_BOTTOM_RIGHT_H 9278
-#define IDR_TEXTBUTTON_TOP_LEFT_P 9279
-#define IDR_TEXTBUTTON_TOP_P 9280
-#define IDR_TEXTBUTTON_TOP_RIGHT_P 9281
-#define IDR_TEXTBUTTON_LEFT_P 9282
-#define IDR_TEXTBUTTON_CENTER_P 9283
-#define IDR_TEXTBUTTON_RIGHT_P 9284
-#define IDR_TEXTBUTTON_BOTTOM_LEFT_P 9285
-#define IDR_TEXTBUTTON_BOTTOM_P 9286
-#define IDR_TEXTBUTTON_BOTTOM_RIGHT_P 9287
-#define IDR_SAD_TAB 9288
-#define IDR_FOLDER_OPEN 9289
-#define IDR_FOLDER_CLOSED 9290
-#define IDR_OTR_ICON 9291
-#define IDR_TAB_INACTIVE_LEFT_OTR 9292
-#define IDR_TAB_INACTIVE_CENTER_OTR 9293
-#define IDR_TAB_INACTIVE_RIGHT_OTR 9294
-#define IDR_BOOKMARK_BAR_CHEVRONS 9295
-#define IDR_CONSTRAINED_BOTTOM_CENTER_V 9296
-#define IDR_CONSTRAINED_BOTTOM_LEFT_CORNER_V 9297
-#define IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER_V 9298
-#define IDR_CONSTRAINED_LEFT_SIDE_V 9299
-#define IDR_CONSTRAINED_RIGHT_SIDE_V 9300
-#define IDR_CONSTRAINED_TOP_CENTER_V 9301
-#define IDR_CONSTRAINED_TOP_LEFT_CORNER_V 9302
-#define IDR_CONSTRAINED_TOP_RIGHT_CORNER_V 9303
-#define IDR_CONTENT_STAR_D 9304
-#define IDR_CONTENT_STAR_OFF 9305
-#define IDR_CONTENT_STAR_ON 9306
-#define IDR_LOCATION_BAR_KEYWORD_HINT_TAB 9307
-#define IDR_ABOUT_BACKGROUND 9310
-#define IDR_FINDINPAGE_PREV 9312
-#define IDR_FINDINPAGE_PREV_H 9313
-#define IDR_FINDINPAGE_PREV_P 9314
-#define IDR_FINDINPAGE_NEXT 9315
-#define IDR_FINDINPAGE_NEXT_H 9316
-#define IDR_FINDINPAGE_NEXT_P 9317
-#define IDR_INFOBAR_RESTORE_SESSION 9322
-#define IDR_INFOBAR_SAVE_PASSWORD 9323
-#define IDR_INFOBAR_SSL_WARNING 9324
-#define IDR_INFOBAR_ALT_NAV_URL 9325
-#define IDR_INFOBAR_PLUGIN_INSTALL 9326
-#define IDR_INFO_BUBBLE_CORNER_TOP_LEFT 9327
-#define IDR_INFO_BUBBLE_CORNER_TOP_RIGHT 9328
-#define IDR_INFO_BUBBLE_CORNER_BOTTOM_LEFT 9329
-#define IDR_INFO_BUBBLE_CORNER_BOTTOM_RIGHT 9330
-#define IDR_WIZARD_ICON 9331
-#define IDR_MENU_MARKER 9332
-#define IDR_FROZEN_TAB_ICON 9333
-#define IDR_FROZEN_PLUGIN_ICON 9334
-#define IDR_UPDATE_AVAILABLE 9335
-#define IDR_MENU_PAGE 9336
-#define IDR_MENU_CHROME 9337
-#define IDR_ABOUT_BACKGROUND_RTL 9339
-#define IDR_WIZARD_ICON_RTL 9340
-#define IDR_LOCATIONBG_POPUPMODE_LEFT 9341
-#define IDR_LOCATIONBG_POPUPMODE_CENTER 9342
-#define IDR_LOCATIONBG_POPUPMODE_RIGHT 9343
-#define IDR_CLOSE_SA 9344
-#define IDR_CLOSE_SA_H 9345
-#define IDR_CLOSE_SA_P 9346
-#define IDR_HISTORY_SECTION 9347
-#define IDR_DOWNLOADS_SECTION 9348
-#define IDR_DEFAULT_THUMBNAIL 9349
-#define IDR_THROBBER_WAITING 9350
-#define IDR_INFOBAR_PLUGIN_CRASHED 9351
-#define IDR_UPDATE_UPTODATE 9353
-#define IDR_UPDATE_FAIL 9354
-#define IDR_CLOSE_BAR 9355
-#define IDR_CLOSE_BAR_H 9356
-#define IDR_CLOSE_BAR_P 9357
-#define IDR_HOME 9358
-#define IDR_HOME_H 9359
-#define IDR_HOME_P 9360
-#define IDR_FIND_BOX_BACKGROUND_LEFT_RTL 9361
-#define IDR_INPUT_GOOD 9362
-// 9363 is unused.
-#define IDR_INPUT_ALERT 9364
-#define IDR_HISTORY_FAVICON 9365
-#define IDR_DOWNLOADS_FAVICON 9366
-#define IDR_MENU_PAGE_RTL 9367
-#define IDR_MENU_CHROME_RTL 9368
-#define IDR_DOWNLOAD_ANIMATION_BEGIN 9369
-#define IDR_TAB_HOVER_LEFT 9370
-#define IDR_TAB_HOVER_CENTER 9371
-#define IDR_TAB_HOVER_RIGHT 9372
-#define IDR_FOLDER_CLOSED_RTL 9373
-#define IDR_FOLDER_OPEN_RTL 9374
-#define IDR_BOOKMARK_BAR_FOLDER 9375
-#define IDR_FIND_DLG_LEFT_BB_BACKGROUND 9376
-#define IDR_FIND_DLG_RIGHT_BB_BACKGROUND 9377
-#define IDR_FIND_DLG_MIDDLE_BB_BACKGROUND 9378
-#define IDR_THROBBER_LIGHT 9379
-#define IDR_OTR_ICON_STANDALONE 9380
-#define IDR_PRODUCT_LOGO 9381
-#define IDR_DISTRIBUTOR_LOGO 9382
-#define IDR_DISTRIBUTOR_LOGO_LIGHT 9383
+#define IDR_CONTENT_BOTTOM_CENTER 9007
+#define IDR_CONTENT_BOTTOM_LEFT_CORNER 9008
+#define IDR_CONTENT_BOTTOM_RIGHT_CORNER 9009
+#define IDR_CONTENT_LEFT_SIDE 9010
+#define IDR_CONTENT_RIGHT_SIDE 9011
+#define IDR_CONTENT_TOP_CENTER 9012
+#define IDR_CONTENT_TOP_LEFT_CORNER 9013
+#define IDR_CONTENT_TOP_RIGHT_CORNER 9014
+#define IDR_DEFAULT_FAVICON 9015
+#define IDR_DROP 9016
+#define IDR_DROP_H 9017
+#define IDR_DROP_P 9018
+#define IDR_FORWARD 9019
+#define IDR_FORWARD_D 9020
+#define IDR_FORWARD_H 9021
+#define IDR_FORWARD_P 9022
+#define IDR_GO 9023
+#define IDR_GO_H 9024
+#define IDR_GO_P 9025
+#define IDR_INFO_BUBBLE_CLOSE 9026
+#define IDR_LOCATIONBG 9027
+#define IDR_MAXIMIZE 9028
+#define IDR_MAXIMIZE_H 9029
+#define IDR_MAXIMIZE_P 9030
+#define IDR_MENUITEM_CENTER_A 9031
+#define IDR_MENUITEM_CENTER_H 9032
+#define IDR_MENUITEM_LEFT_A 9033
+#define IDR_MENUITEM_LEFT_H 9034
+#define IDR_MENUITEM_RIGHT_A 9035
+#define IDR_MENUITEM_RIGHT_H 9036
+#define IDR_MINIMIZE 9037
+#define IDR_MINIMIZE_H 9038
+#define IDR_MINIMIZE_P 9039
+#define IDR_PLUGIN 9040
+#define IDR_RELOAD 9041
+#define IDR_RELOAD_H 9042
+#define IDR_RELOAD_P 9043
+#define IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_C 9044
+#define IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_L 9045
+#define IDR_LOCATION_BAR_SELECTED_KEYWORD_BACKGROUND_R 9046
+#define IDR_STAR 9047
+#define IDR_STAR_D 9048
+#define IDR_STAR_H 9049
+#define IDR_STAR_P 9050
+#define IDR_STARRED 9051
+#define IDR_STARRED_H 9052
+#define IDR_STARRED_P 9053
+#define IDR_TAB_ACTIVE_CENTER 9054
+#define IDR_TAB_ACTIVE_LEFT 9055
+#define IDR_TAB_ACTIVE_RIGHT 9056
+#define IDR_TAB_CLOSE 9057
+#define IDR_TAB_CLOSE_H 9058
+#define IDR_TAB_CLOSE_P 9059
+#define IDR_TAB_INACTIVE_CENTER 9060
+#define IDR_TAB_INACTIVE_LEFT 9061
+#define IDR_TAB_INACTIVE_RIGHT 9062
+#define IDR_THROBBER 9063
+#define IDR_TOOLBAR_TOGGLE_KNOB 9064
+#define IDR_TOOLBAR_TOGGLE_TRACK 9065
+#define IDR_WINDOW_BOTTOM_CENTER 9066
+#define IDR_WINDOW_BOTTOM_LEFT_CORNER 9067
+#define IDR_WINDOW_BOTTOM_RIGHT_CORNER 9068
+#define IDR_WINDOW_LEFT_SIDE 9069
+#define IDR_WINDOW_RIGHT_SIDE 9070
+#define IDR_WINDOW_TOP_CENTER 9071
+#define IDR_WINDOW_TOP_LEFT_CORNER 9072
+#define IDR_WINDOW_TOP_RIGHT_CORNER 9073
+#define IDR_WINDOW_BOTTOM_CENTER_OTR 9074
+#define IDR_WINDOW_BOTTOM_LEFT_CORNER_OTR 9075
+#define IDR_WINDOW_BOTTOM_RIGHT_CORNER_OTR 9076
+#define IDR_WINDOW_LEFT_SIDE_OTR 9077
+#define IDR_WINDOW_RIGHT_SIDE_OTR 9078
+#define IDR_WINDOW_TOP_CENTER_OTR 9079
+#define IDR_WINDOW_TOP_LEFT_CORNER_OTR 9080
+#define IDR_WINDOW_TOP_RIGHT_CORNER_OTR 9081
+#define IDR_TAB_INACTIVE_CENTER_V 9082
+#define IDR_TAB_INACTIVE_LEFT_V 9083
+#define IDR_TAB_INACTIVE_RIGHT_V 9084
+#define IDR_RESTORE 9085
+#define IDR_RESTORE_H 9086
+#define IDR_RESTORE_P 9087
+#define IDR_DEWINDOW_BOTTOM_CENTER 9088
+#define IDR_DEWINDOW_BOTTOM_LEFT_CORNER 9089
+#define IDR_DEWINDOW_BOTTOM_RIGHT_CORNER 9090
+#define IDR_DEWINDOW_LEFT_SIDE 9091
+#define IDR_DEWINDOW_RIGHT_SIDE 9092
+#define IDR_DEWINDOW_TOP_CENTER 9093
+#define IDR_DEWINDOW_TOP_LEFT_CORNER 9094
+#define IDR_DEWINDOW_TOP_RIGHT_CORNER 9095
+#define IDR_DEWINDOW_BOTTOM_CENTER_OTR 9096
+#define IDR_DEWINDOW_BOTTOM_LEFT_CORNER_OTR 9097
+#define IDR_DEWINDOW_BOTTOM_RIGHT_CORNER_OTR 9098
+#define IDR_DEWINDOW_LEFT_SIDE_OTR 9099
+#define IDR_DEWINDOW_RIGHT_SIDE_OTR 9100
+#define IDR_DEWINDOW_TOP_CENTER_OTR 9101
+#define IDR_DEWINDOW_TOP_LEFT_CORNER_OTR 9102
+#define IDR_DEWINDOW_TOP_RIGHT_CORNER_OTR 9103
+#define IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM 9104
+#define IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_H 9105
+#define IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM_P 9106
+#define IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE 9107
+#define IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_H 9108
+#define IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE_P 9109
+#define IDR_DOWNLOAD_BUTTON_CENTER_TOP 9110
+#define IDR_DOWNLOAD_BUTTON_CENTER_TOP_H 9111
+#define IDR_DOWNLOAD_BUTTON_CENTER_TOP_P 9112
+#define IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM 9113
+#define IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_H 9114
+#define IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM_P 9115
+#define IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE 9116
+#define IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_H 9117
+#define IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE_P 9118
+#define IDR_DOWNLOAD_BUTTON_LEFT_TOP 9119
+#define IDR_DOWNLOAD_BUTTON_LEFT_TOP_H 9120
+#define IDR_DOWNLOAD_BUTTON_LEFT_TOP_P 9121
+#define IDR_DOWNLOAD_BUTTON_MENU_BOTTOM 9122
+#define IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_H 9123
+#define IDR_DOWNLOAD_BUTTON_MENU_BOTTOM_P 9124
+#define IDR_DOWNLOAD_BUTTON_MENU_MIDDLE 9125
+#define IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_H 9126
+#define IDR_DOWNLOAD_BUTTON_MENU_MIDDLE_P 9127
+#define IDR_DOWNLOAD_BUTTON_MENU_TOP 9128
+#define IDR_DOWNLOAD_BUTTON_MENU_TOP_H 9129
+#define IDR_DOWNLOAD_BUTTON_MENU_TOP_P 9130
+#define IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM 9131
+#define IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_H 9132
+#define IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_P 9133
+#define IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_NO_DD 9134
+#define IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE 9135
+#define IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_H 9136
+#define IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_P 9137
+#define IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_NO_DD 9138
+#define IDR_DOWNLOAD_BUTTON_RIGHT_TOP 9139
+#define IDR_DOWNLOAD_BUTTON_RIGHT_TOP_H 9140
+#define IDR_DOWNLOAD_BUTTON_RIGHT_TOP_P 9141
+#define IDR_DOWNLOAD_BUTTON_RIGHT_TOP_NO_DD 9142
+#define IDR_DOWNLOAD_PROGRESS_BACKGROUND_16 9143
+#define IDR_DOWNLOAD_PROGRESS_FOREGROUND_16 9144
+#define IDR_DOWNLOAD_PROGRESS_BACKGROUND_32 9145
+#define IDR_DOWNLOAD_PROGRESS_FOREGROUND_32 9146
+#define IDR_DOWNLOAD_ICON 9147
+#define IDR_COOKIE_ICON 9148
+#define IDR_SAD_FAVICON 9149
+#define IDR_TAB_DROP_UP 9150
+#define IDR_TAB_DROP_DOWN 9151
+#define IDR_CONSTRAINED_BOTTOM_CENTER 9152
+#define IDR_CONSTRAINED_BOTTOM_LEFT_CORNER 9153
+#define IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER 9154
+#define IDR_CONSTRAINED_LEFT_SIDE 9155
+#define IDR_CONSTRAINED_RIGHT_SIDE 9156
+#define IDR_CONSTRAINED_TOP_CENTER 9157
+#define IDR_CONSTRAINED_TOP_LEFT_CORNER 9158
+#define IDR_CONSTRAINED_TOP_RIGHT_CORNER 9159
+#define IDR_FIND_BOX_BACKGROUND 9160
+#define IDR_FIND_BOX_BACKGROUND_LEFT 9161
+#define IDR_LOCK 9162
+#define IDR_WARNING 9163
+#define IDR_BOOKMARK_BAR_RECENTLY_BOOKMARKED_ICON 9164
+#define IDR_STOP 9165
+#define IDR_STOP_H 9166
+#define IDR_STOP_P 9167
+#define IDR_FIND_DLG_LEFT_BACKGROUND 9168
+#define IDR_FIND_DLG_RIGHT_BACKGROUND 9169
+#define IDR_FIND_DLG_MIDDLE_BACKGROUND 9170
+#define IDR_APP_TOP_RIGHT 9171
+#define IDR_APP_TOP_CENTER 9172
+#define IDR_APP_TOP_LEFT 9173
+#define IDR_APP_DROPARROW 9174
+#define IDR_THROBBER_01 9175
+#define IDR_THROBBER_02 9176
+#define IDR_THROBBER_03 9177
+#define IDR_THROBBER_04 9178
+#define IDR_THROBBER_05 9179
+#define IDR_THROBBER_06 9180
+#define IDR_THROBBER_07 9181
+#define IDR_THROBBER_08 9182
+#define IDR_THROBBER_09 9183
+#define IDR_THROBBER_10 9184
+#define IDR_THROBBER_11 9185
+#define IDR_THROBBER_12 9186
+#define IDR_THROBBER_13 9187
+#define IDR_THROBBER_14 9188
+#define IDR_THROBBER_15 9189
+#define IDR_THROBBER_16 9190
+#define IDR_THROBBER_17 9191
+#define IDR_THROBBER_18 9192
+#define IDR_THROBBER_19 9193
+#define IDR_THROBBER_20 9194
+#define IDR_THROBBER_21 9195
+#define IDR_THROBBER_22 9196
+#define IDR_THROBBER_23 9197
+#define IDR_THROBBER_24 9198
+#define IDR_PAGEINFO_GOOD 9199
+#define IDR_PAGEINFO_BAD 9200
+#define IDR_NEWTAB_BUTTON 9201
+#define IDR_NEWTAB_BUTTON_H 9202
+#define IDR_NEWTAB_BUTTON_P 9203
+#define IDR_ARROW_RIGHT 9204
+#define IDR_TEXTBUTTON_TOP_LEFT_H 9205
+#define IDR_TEXTBUTTON_TOP_H 9206
+#define IDR_TEXTBUTTON_TOP_RIGHT_H 9207
+#define IDR_TEXTBUTTON_LEFT_H 9208
+#define IDR_TEXTBUTTON_CENTER_H 9209
+#define IDR_TEXTBUTTON_RIGHT_H 9210
+#define IDR_TEXTBUTTON_BOTTOM_LEFT_H 9211
+#define IDR_TEXTBUTTON_BOTTOM_H 9212
+#define IDR_TEXTBUTTON_BOTTOM_RIGHT_H 9213
+#define IDR_TEXTBUTTON_TOP_LEFT_P 9214
+#define IDR_TEXTBUTTON_TOP_P 9215
+#define IDR_TEXTBUTTON_TOP_RIGHT_P 9216
+#define IDR_TEXTBUTTON_LEFT_P 9217
+#define IDR_TEXTBUTTON_CENTER_P 9218
+#define IDR_TEXTBUTTON_RIGHT_P 9219
+#define IDR_TEXTBUTTON_BOTTOM_LEFT_P 9220
+#define IDR_TEXTBUTTON_BOTTOM_P 9221
+#define IDR_TEXTBUTTON_BOTTOM_RIGHT_P 9222
+#define IDR_SAD_TAB 9223
+#define IDR_FOLDER_OPEN 9224
+#define IDR_FOLDER_CLOSED 9225
+#define IDR_OTR_ICON 9226
+#define IDR_TAB_INACTIVE_LEFT_OTR 9227
+#define IDR_TAB_INACTIVE_CENTER_OTR 9228
+#define IDR_TAB_INACTIVE_RIGHT_OTR 9229
+#define IDR_BOOKMARK_BAR_CHEVRONS 9230
+#define IDR_CONSTRAINED_BOTTOM_CENTER_V 9231
+#define IDR_CONSTRAINED_BOTTOM_LEFT_CORNER_V 9232
+#define IDR_CONSTRAINED_BOTTOM_RIGHT_CORNER_V 9233
+#define IDR_CONSTRAINED_LEFT_SIDE_V 9234
+#define IDR_CONSTRAINED_RIGHT_SIDE_V 9235
+#define IDR_CONSTRAINED_TOP_CENTER_V 9236
+#define IDR_CONSTRAINED_TOP_LEFT_CORNER_V 9237
+#define IDR_CONSTRAINED_TOP_RIGHT_CORNER_V 9238
+#define IDR_CONTENT_STAR_D 9239
+#define IDR_CONTENT_STAR_OFF 9240
+#define IDR_CONTENT_STAR_ON 9241
+#define IDR_LOCATION_BAR_KEYWORD_HINT_TAB 9242
+#define IDR_ABOUT_BACKGROUND 9243
+#define IDR_FINDINPAGE_PREV 9244
+#define IDR_FINDINPAGE_PREV_H 9245
+#define IDR_FINDINPAGE_PREV_P 9246
+#define IDR_FINDINPAGE_NEXT 9247
+#define IDR_FINDINPAGE_NEXT_H 9248
+#define IDR_FINDINPAGE_NEXT_P 9249
+#define IDR_INFOBAR_RESTORE_SESSION 9250
+#define IDR_INFOBAR_SAVE_PASSWORD 9251
+#define IDR_INFOBAR_SSL_WARNING 9252
+#define IDR_INFOBAR_ALT_NAV_URL 9253
+#define IDR_INFOBAR_PLUGIN_INSTALL 9254
+#define IDR_INFO_BUBBLE_CORNER_TOP_LEFT 9255
+#define IDR_INFO_BUBBLE_CORNER_TOP_RIGHT 9256
+#define IDR_INFO_BUBBLE_CORNER_BOTTOM_LEFT 9257
+#define IDR_INFO_BUBBLE_CORNER_BOTTOM_RIGHT 9258
+#define IDR_WIZARD_ICON 9259
+#define IDR_MENU_MARKER 9260
+#define IDR_FROZEN_TAB_ICON 9261
+#define IDR_FROZEN_PLUGIN_ICON 9262
+#define IDR_UPDATE_AVAILABLE 9263
+#define IDR_MENU_PAGE 9264
+#define IDR_MENU_CHROME 9265
+#define IDR_ABOUT_BACKGROUND_RTL 9266
+#define IDR_WIZARD_ICON_RTL 9267
+#define IDR_LOCATIONBG_POPUPMODE_LEFT 9268
+#define IDR_LOCATIONBG_POPUPMODE_CENTER 9269
+#define IDR_LOCATIONBG_POPUPMODE_RIGHT 9270
+#define IDR_CLOSE_SA 9271
+#define IDR_CLOSE_SA_H 9272
+#define IDR_CLOSE_SA_P 9273
+#define IDR_HISTORY_SECTION 9274
+#define IDR_DOWNLOADS_SECTION 9275
+#define IDR_DEFAULT_THUMBNAIL 9276
+#define IDR_THROBBER_WAITING 9277
+#define IDR_INFOBAR_PLUGIN_CRASHED 9278
+#define IDR_UPDATE_UPTODATE 9279
+#define IDR_UPDATE_FAIL 9280
+#define IDR_CLOSE_BAR 9281
+#define IDR_CLOSE_BAR_H 9282
+#define IDR_CLOSE_BAR_P 9283
+#define IDR_HOME 9284
+#define IDR_HOME_H 9285
+#define IDR_HOME_P 9286
+#define IDR_FIND_BOX_BACKGROUND_LEFT_RTL 9287
+#define IDR_INPUT_GOOD 9288
+#define IDR_INPUT_ALERT 9289
+#define IDR_HISTORY_FAVICON 9290
+#define IDR_DOWNLOADS_FAVICON 9291
+#define IDR_MENU_PAGE_RTL 9292
+#define IDR_MENU_CHROME_RTL 9293
+#define IDR_DOWNLOAD_ANIMATION_BEGIN 9294
+#define IDR_TAB_HOVER_LEFT 9295
+#define IDR_TAB_HOVER_CENTER 9296
+#define IDR_TAB_HOVER_RIGHT 9297
+#define IDR_FOLDER_CLOSED_RTL 9298
+#define IDR_FOLDER_OPEN_RTL 9299
+#define IDR_BOOKMARK_BAR_FOLDER 9300
+#define IDR_FIND_DLG_LEFT_BB_BACKGROUND 9301
+#define IDR_FIND_DLG_RIGHT_BB_BACKGROUND 9302
+#define IDR_FIND_DLG_MIDDLE_BB_BACKGROUND 9303
+#define IDR_THROBBER_LIGHT 9304
+#define IDR_OTR_ICON_STANDALONE 9305
+#define IDR_PRODUCT_LOGO 9306
+#define IDR_DISTRIBUTOR_LOGO 9307
+#define IDR_DISTRIBUTOR_LOGO_LIGHT 9308
diff --git a/chrome/app/theme/theme_resources.rc b/chrome/app/theme/theme_resources.rc
index 8f78a69..58c3e8b 100644
--- a/chrome/app/theme/theme_resources.rc
+++ b/chrome/app/theme/theme_resources.rc
@@ -145,12 +145,15 @@ IDR_DOWNLOAD_BUTTON_MENU_TOP_P BINDATA "download_button_menu_top_p.png"
IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM BINDATA "download_button_right_bottom.png"
IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_H BINDATA "download_button_right_bottom_h.png"
IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_P BINDATA "download_button_right_bottom_p.png"
+IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_NO_DD BINDATA "download_button_right_bottom_no_dd.png"
IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE BINDATA "download_button_right_middle.png"
IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_H BINDATA "download_button_right_middle_h.png"
IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_P BINDATA "download_button_right_middle_p.png"
+IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_NO_DD BINDATA "download_button_right_middle_no_dd.png"
IDR_DOWNLOAD_BUTTON_RIGHT_TOP BINDATA "download_button_right_top.png"
IDR_DOWNLOAD_BUTTON_RIGHT_TOP_H BINDATA "download_button_right_top_h.png"
IDR_DOWNLOAD_BUTTON_RIGHT_TOP_P BINDATA "download_button_right_top_p.png"
+IDR_DOWNLOAD_BUTTON_RIGHT_TOP_NO_DD BINDATA "download_button_right_top_no_dd.png"
IDR_DOWNLOAD_PROGRESS_BACKGROUND_16 BINDATA "download_progress_background16.png"
IDR_DOWNLOAD_PROGRESS_FOREGROUND_16 BINDATA "download_progress_foreground16.png"
IDR_DOWNLOAD_PROGRESS_BACKGROUND_32 BINDATA "download_progress_background32.png"
diff --git a/chrome/browser/download/download_exe.cc b/chrome/browser/download/download_exe.cc
index c9fdc4d..ce33781 100644
--- a/chrome/browser/download/download_exe.cc
+++ b/chrome/browser/download/download_exe.cc
@@ -59,6 +59,7 @@ static const wchar_t* const g_executables[] = {
L"app",
L"application",
L"asp",
+ L"asx",
L"bas",
L"bat",
L"chm",
@@ -66,6 +67,7 @@ static const wchar_t* const g_executables[] = {
L"com",
L"cpl",
L"crt",
+ L"dll",
L"exe",
L"fxp",
L"hlp",
@@ -73,6 +75,7 @@ static const wchar_t* const g_executables[] = {
L"inf",
L"ins",
L"isp",
+ L"jar",
L"js",
L"jse",
L"lnk",
diff --git a/chrome/browser/download/download_file.cc b/chrome/browser/download/download_file.cc
index 4fa3637..6b0fba4 100644
--- a/chrome/browser/download/download_file.cc
+++ b/chrome/browser/download/download_file.cc
@@ -578,3 +578,9 @@ void DownloadFileManager::CreateDirectory(const std::wstring& directory) {
if (!file_util::PathExists(directory))
file_util::CreateDirectory(directory);
}
+
+void DownloadFileManager::DeleteFile(const std::wstring& path) {
+ // Make sure we only delete files.
+ if (file_util::PathExists(path) && !file_util::DirectoryExists(path))
+ file_util::Delete(path, false);
+}
diff --git a/chrome/browser/download/download_file.h b/chrome/browser/download/download_file.h
index 5dc5d63..cce6398 100644
--- a/chrome/browser/download/download_file.h
+++ b/chrome/browser/download/download_file.h
@@ -210,6 +210,9 @@ class DownloadFileManager
// download directory exists.
void CreateDirectory(const std::wstring& directory);
+ // Called by the donwload manager to delete non validated dangerous downloads.
+ void DeleteFile(const std::wstring& path);
+
private:
// Timer helpers for updating the UI about the current progress of a download.
void StartUpdateTimer();
diff --git a/chrome/browser/download/download_manager.cc b/chrome/browser/download/download_manager.cc
index d83ddc2..cff6935 100644
--- a/chrome/browser/download/download_manager.cc
+++ b/chrome/browser/download/download_manager.cc
@@ -15,6 +15,7 @@
#include "base/task.h"
#include "base/thread.h"
#include "base/timer.h"
+#include "base/rand_util.h"
#include "base/win_util.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
@@ -97,6 +98,7 @@ static bool DownloadPathIsDangerous(const std::wstring& download_path) {
DownloadItem::DownloadItem(const DownloadCreateInfo& info)
: id_(-1),
full_path_(info.path),
+ original_name_(info.original_name),
url_(info.url),
total_bytes_(info.total_bytes),
received_bytes_(info.received_bytes),
@@ -105,6 +107,7 @@ DownloadItem::DownloadItem(const DownloadCreateInfo& info)
start_time_(info.start_time),
db_handle_(info.db_handle),
manager_(NULL),
+ safety_state_(SAFE),
is_paused_(false),
open_when_complete_(false),
render_process_id_(-1),
@@ -118,13 +121,16 @@ DownloadItem::DownloadItem(const DownloadCreateInfo& info)
DownloadItem::DownloadItem(int32 download_id,
const std::wstring& path,
const std::wstring& url,
+ const std::wstring& original_name,
const Time start_time,
int64 download_size,
int render_process_id,
- int request_id)
+ int request_id,
+ bool is_dangerous)
: id_(download_id),
full_path_(path),
url_(url),
+ original_name_(original_name),
total_bytes_(download_size),
received_bytes_(0),
start_tick_(GetTickCount()),
@@ -132,6 +138,7 @@ DownloadItem::DownloadItem(int32 download_id,
start_time_(start_time),
db_handle_(kUninitializedHandle),
manager_(NULL),
+ safety_state_(is_dangerous ? DANGEROUS : SAFE),
is_paused_(false),
open_when_complete_(false),
render_process_id_(render_process_id),
@@ -198,14 +205,16 @@ void DownloadItem::Cancel(bool update_history) {
void DownloadItem::Finished(int64 size) {
state_ = COMPLETE;
UpdateSize(size);
- UpdateObservers();
StopProgressTimer();
}
-void DownloadItem::Remove() {
+void DownloadItem::Remove(bool delete_on_disk) {
Cancel(true);
state_ = REMOVING;
+ if (delete_on_disk)
+ manager_->DeleteDownload(full_path_);
manager_->RemoveDownload(db_handle_);
+ // We are now deleted.
}
void DownloadItem::StartProgressTimer() {
@@ -255,6 +264,12 @@ void DownloadItem::TogglePause() {
UpdateObservers();
}
+std::wstring DownloadItem::GetFileName() const {
+ if (safety_state_ == DownloadItem::SAFE)
+ return file_name_;
+ return original_name_;
+}
+
// DownloadManager implementation ----------------------------------------------
// static
@@ -313,12 +328,19 @@ void DownloadManager::Shutdown() {
// 'in_progress_' may contain DownloadItems that have not finished the start
// complete (from the history service) and thus aren't in downloads_.
DownloadMap::iterator it = in_progress_.begin();
+ std::set<DownloadItem*> to_remove;
for (; it != in_progress_.end(); ++it) {
DownloadItem* download = it->second;
- if (download->state() == DownloadItem::IN_PROGRESS) {
- download->Cancel(false);
- UpdateHistoryForDownload(download);
+ if (download->safety_state() == DownloadItem::DANGEROUS) {
+ // Forget about any download that the user did not approve.
+ // Note that we cannot call download->Remove() this would invalidate our
+ // iterator.
+ to_remove.insert(download);
+ continue;
}
+ DCHECK_EQ(DownloadItem::IN_PROGRESS, download->state());
+ download->Cancel(false);
+ UpdateHistoryForDownload(download);
if (download->db_handle() == kUninitializedHandle) {
// An invalid handle means that 'download' does not yet exist in
// 'downloads_', so we have to delete it here.
@@ -326,7 +348,25 @@ void DownloadManager::Shutdown() {
}
}
+ // 'dangerous_finished_' contains all complete downloads that have not been
+ // approved. They should be removed.
+ it = dangerous_finished_.begin();
+ for (; it != dangerous_finished_.end(); ++it)
+ to_remove.insert(it->second);
+
+ // Remove the dangerous download that are not approved.
+ for (std::set<DownloadItem*>::const_iterator rm_it = to_remove.begin();
+ rm_it != to_remove.end(); ++rm_it) {
+ DownloadItem* download = *rm_it;
+ download->Remove(true);
+ // Same as above, delete the download if it is not in 'downloads_'.
+ if (download->db_handle() == kUninitializedHandle)
+ delete download;
+ }
+ to_remove.clear();
+
in_progress_.clear();
+ dangerous_finished_.clear();
STLDeleteValues(&downloads_);
file_manager_ = NULL;
@@ -486,17 +526,36 @@ void DownloadManager::CheckIfSuggestedPathExists(DownloadCreateInfo* info) {
// Check writability of the suggested path. If we can't write to it, default
// to the user's "My Documents" directory. We'll prompt them in this case.
- std::wstring path = file_util::GetDirectoryFromPath(info->suggested_path);
- if (!file_util::PathIsWritable(path)) {
+ std::wstring dir = file_util::GetDirectoryFromPath(info->suggested_path);
+ const std::wstring filename =
+ file_util::GetFilenameFromPath(info->suggested_path);
+ if (!file_util::PathIsWritable(dir)) {
info->save_as = true;
- const std::wstring filename =
- file_util::GetFilenameFromPath(info->suggested_path);
PathService::Get(chrome::DIR_USER_DOCUMENTS, &info->suggested_path);
file_util::AppendToPath(&info->suggested_path, filename);
}
info->suggested_path_exists = !UniquifyPath(&info->suggested_path);
+ // If the download is deemmed dangerous, we'll use a temporary name for it.
+ if (!info->save_as && IsDangerous(filename)) {
+ info->original_name = file_util::GetFilenameFromPath(info->suggested_path);
+ // Create a temporary file to hold the file until the user approves its
+ // download.
+ std::wstring file_name;
+ std::wstring path;
+ while (path.empty()) {
+ SStringPrintf(&file_name, L"dangerous_download_%d.download",
+ base::RandInt(0, 100000));
+ path = dir;
+ file_util::AppendToPath(&path, file_name);
+ if (file_util::PathExists(path))
+ path.clear();
+ }
+ info->suggested_path = path;
+ info->is_dangerous = true;
+ }
+
// Now we return to the UI thread.
ui_loop_->PostTask(FROM_HERE,
NewRunnableMethod(this,
@@ -537,10 +596,12 @@ void DownloadManager::ContinueStartDownload(DownloadCreateInfo* info,
download = new DownloadItem(info->download_id,
info->path,
info->url,
+ info->original_name,
info->start_time,
info->total_bytes,
info->render_process_id,
- info->request_id);
+ info->request_id,
+ info->is_dangerous);
download->set_manager(this);
in_progress_[info->download_id] = download;
} else {
@@ -628,30 +689,7 @@ void DownloadManager::UpdateDownload(int32 download_id, int64 size) {
void DownloadManager::DownloadFinished(int32 download_id, int64 size) {
DownloadMap::iterator it = in_progress_.find(download_id);
- if (it != in_progress_.end()) {
- // Remove the id from the list of pending ids.
- PendingFinishedMap::iterator erase_it =
- pending_finished_downloads_.find(download_id);
- if (erase_it != pending_finished_downloads_.end())
- pending_finished_downloads_.erase(erase_it);
-
- DownloadItem* download = it->second;
- download->Finished(size);
-
- // Open the download if the user or user prefs indicate it should be.
- const std::wstring extension =
- file_util::GetFileExtensionFromPath(download->full_path());
- if (download->open_when_complete() || ShouldOpenFileExtension(extension))
- OpenDownloadInShell(download, NULL);
-
- // Clean up will happen when the history system create callback runs if we
- // don't have a valid db_handle yet.
- if (download->db_handle() != kUninitializedHandle) {
- in_progress_.erase(it);
- NotifyAboutDownloadStop();
- UpdateHistoryForDownload(download);
- }
- } else {
+ if (it == in_progress_.end()) {
// The download is done, but the user hasn't selected a final location for
// it yet (the Save As dialog box is probably still showing), so just keep
// track of the fact that this download id is complete, when the
@@ -660,7 +698,102 @@ void DownloadManager::DownloadFinished(int32 download_id, int64 size) {
pending_finished_downloads_.find(download_id);
DCHECK(erase_it == pending_finished_downloads_.end());
pending_finished_downloads_[download_id] = size;
+ return;
+ }
+
+ // Remove the id from the list of pending ids.
+ PendingFinishedMap::iterator erase_it =
+ pending_finished_downloads_.find(download_id);
+ if (erase_it != pending_finished_downloads_.end())
+ pending_finished_downloads_.erase(erase_it);
+
+ DownloadItem* download = it->second;
+ download->Finished(size);
+
+ // Clean up will happen when the history system create callback runs if we
+ // don't have a valid db_handle yet.
+ if (download->db_handle() != kUninitializedHandle) {
+ in_progress_.erase(it);
+ NotifyAboutDownloadStop();
+ UpdateHistoryForDownload(download);
+ }
+
+ // If this a dangerous download not yet validated by the user, don't do
+ // anything. When the user notifies us, it will trigger a call to
+ // ProceedWithFinishedDangerousDownload.
+ if (download->safety_state() == DownloadItem::DANGEROUS) {
+ dangerous_finished_[download_id] = download;
+ return;
+ }
+
+ if (download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) {
+ // We first need to rename the donwloaded file from its temporary name to
+ // its final name before we can continue.
+ file_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(
+ this, &DownloadManager::ProceedWithFinishedDangerousDownload,
+ download->db_handle(),
+ download->full_path(), download->original_name()));
+ return;
}
+ ContinueDownloadFinished(download);
+}
+
+void DownloadManager::ContinueDownloadFinished(DownloadItem* download) {
+ // If this was a dangerous download, it has now been approved and must be
+ // removed from dangerous_finished_ so it does not get deleted on shutdown.
+ DownloadMap::iterator it = dangerous_finished_.find(download->id());
+ if (it != dangerous_finished_.end())
+ dangerous_finished_.erase(it);
+
+ // Notify our observers that we are complete (the call to Finished() set the
+ // state to complete but did not notify).
+ download->UpdateObservers();
+
+ // Open the download if the user or user prefs indicate it should be.
+ const std::wstring extension =
+ file_util::GetFileExtensionFromPath(download->full_path());
+ if (download->open_when_complete() || ShouldOpenFileExtension(extension))
+ OpenDownloadInShell(download, NULL);
+}
+
+// Called on the file thread. Renames the downloaded file to its original name.
+void DownloadManager::ProceedWithFinishedDangerousDownload(
+ int64 download_handle,
+ const std::wstring& path,
+ const std::wstring& original_name) {
+ bool success = false;
+ std::wstring new_path = path;
+ if (file_util::PathExists(path)) {
+ new_path = file_util::GetDirectoryFromPath(new_path);
+ file_util::AppendToPath(&new_path, original_name);
+ success = file_util::Move(path, new_path);
+ } else {
+ NOTREACHED();
+ }
+
+ ui_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &DownloadManager::DangerousDownloadRenamed,
+ download_handle, success, new_path));
+}
+
+// Call from the file thread when the finished dangerous download was renamed.
+void DownloadManager::DangerousDownloadRenamed(int64 download_handle,
+ bool success,
+ const std::wstring& new_path) {
+ DownloadMap::iterator it = downloads_.find(download_handle);
+ if (it == downloads_.end()) {
+ NOTREACHED();
+ return;
+ }
+
+ DownloadItem* download = it->second;
+ // If we failed to rename the file, we'll just keep the name as is.
+ if (success)
+ RenameDownload(download, new_path);
+
+ // Continue the download finished sequence.
+ ContinueDownloadFinished(download);
}
// static
@@ -741,6 +874,27 @@ void DownloadManager::OnPauseDownloadRequest(ResourceDispatcherHost* rdh,
rdh->PauseRequest(render_process_id, request_id, pause);
}
+bool DownloadManager::IsDangerous(const std::wstring& file_name) {
+ // TODO(jcampan): Improve me.
+ return IsExecutable(file_util::GetFileExtensionFromPath(file_name));
+}
+
+void DownloadManager::RenameDownload(DownloadItem* download,
+ const std::wstring& new_path) {
+ download->Rename(new_path);
+
+ // Update the history.
+
+ // No update necessary if the download was initiated while in incognito mode.
+ if (download->db_handle() <= kUninitializedHandle)
+ return;
+
+ // FIXME(acw|paulg) see bug 958058. EXPLICIT_ACCESS below is wrong.
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs)
+ hs->UpdateDownloadPath(new_path, download->db_handle());
+}
+
void DownloadManager::RemoveDownload(int64 download_handle) {
DownloadMap::iterator it = downloads_.find(download_handle);
if (it == downloads_.end())
@@ -752,6 +906,9 @@ void DownloadManager::RemoveDownload(int64 download_handle) {
// Remove from our tables and delete.
downloads_.erase(it);
+ it = dangerous_finished_.find(download->id());
+ if (it != dangerous_finished_.end())
+ dangerous_finished_.erase(it);
delete download;
// Tell observers to refresh their views.
@@ -1014,6 +1171,29 @@ void DownloadManager::FileSelectionCanceled(void* params) {
info->download_id));
}
+void DownloadManager::DeleteDownload(const std::wstring& path) {
+ file_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ file_manager_, &DownloadFileManager::DeleteFile, path));
+}
+
+
+void DownloadManager::DangerousDownloadValidated(DownloadItem* download) {
+ DCHECK_EQ(DownloadItem::DANGEROUS, download->safety_state());
+ download->set_safety_state(DownloadItem::DANGEROUS_BUT_VALIDATED);
+ download->UpdateObservers();
+
+ // If the download is not complete, nothing to do. The required
+ // post-processing will be performed when it does complete.
+ if (download->state() != DownloadItem::COMPLETE)
+ return;
+
+ file_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &DownloadManager::ProceedWithFinishedDangerousDownload,
+ download->db_handle(), download->full_path(),
+ download->original_name()));
+}
+
// Operations posted to us from the history service ----------------------------
// The history service has retrieved all download entries. 'entries' contains
diff --git a/chrome/browser/download/download_manager.h b/chrome/browser/download/download_manager.h
index 0ab3dc1..6e78fb6 100644
--- a/chrome/browser/download/download_manager.h
+++ b/chrome/browser/download/download_manager.h
@@ -80,6 +80,12 @@ class DownloadItem {
REMOVING
};
+ enum SafetyState {
+ SAFE = 0,
+ DANGEROUS,
+ DANGEROUS_BUT_VALIDATED // Dangerous but the user confirmed the download.
+ };
+
// Interface that observers of a particular download must implement in order
// to receive updates to the download's status.
class Observer {
@@ -94,10 +100,12 @@ class DownloadItem {
DownloadItem(int32 download_id,
const std::wstring& path,
const std::wstring& url,
+ const std::wstring& original_name,
const Time start_time,
int64 download_size,
int render_process_id,
- int request_id);
+ int request_id,
+ bool is_dangerous);
~DownloadItem();
@@ -125,12 +133,12 @@ class DownloadItem {
// when resuming a download (assuming the server supports byte ranges).
void Cancel(bool update_history);
- // Download operation completed
+ // Download operation completed.
void Finished(int64 size);
- // The user wants to remove the download from the views and history. This
- // operation does not delete the file on the disk.
- void Remove();
+ // The user wants to remove the download from the views and history. If
+ // |delete_file| is true, the file is deleted on the disk.
+ void Remove(bool delete_file);
// Start/stop sending periodic updates to our observers
void StartProgressTimer();
@@ -158,8 +166,10 @@ class DownloadItem {
// Accessors
DownloadState state() const { return state_; }
- std::wstring full_path() const { return full_path_; }
std::wstring file_name() const { return file_name_; }
+ void set_file_name(const std::wstring& name) { file_name_ = name; }
+ std::wstring full_path() const { return full_path_; }
+ void set_full_path(const std::wstring& path) { full_path_ = path; }
std::wstring url() const { return url_; }
int64 total_bytes() const { return total_bytes_; }
void set_total_bytes(int64 total_bytes) { total_bytes_ = total_bytes; }
@@ -176,6 +186,16 @@ class DownloadItem {
void set_open_when_complete(bool open) { open_when_complete_ = open; }
int render_process_id() const { return render_process_id_; }
int request_id() const { return request_id_; }
+ SafetyState safety_state() const { return safety_state_; }
+ void set_safety_state(SafetyState safety_state) {
+ safety_state_ = safety_state;
+ }
+ std::wstring original_name() const { return original_name_; }
+ void set_original_name(const std::wstring& name) { original_name_ = name; }
+
+ // Returns the file-name that should be reported to the user, which is
+ // file_name_ for safe downloads and original_name_ for dangerous ones.
+ std::wstring GetFileName() const;
private:
// Internal helper for maintaining consistent received and total sizes.
@@ -226,6 +246,14 @@ class DownloadItem {
// A flag for indicating if the download should be opened at completion.
bool open_when_complete_;
+ // Whether the download is considered potentially safe or dangerous
+ // (executable files are typically considered dangerous).
+ SafetyState safety_state_;
+
+ // Dangerous download are given temporary names until the user approves them.
+ // This stores their original name.
+ std::wstring original_name_;
+
// For canceling or pausing requests.
int render_process_id_;
int request_id_;
@@ -354,6 +382,12 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
virtual void FileSelected(const std::wstring& path, void* params);
virtual void FileSelectionCanceled(void* params);
+ // Deletes the specified path on the file thread.
+ void DeleteDownload(const std::wstring& path);
+
+ // Called when the user has validated the donwload of a dangerous file.
+ void DangerousDownloadValidated(DownloadItem* download);
+
private:
// Shutdown the download manager. This call is needed only after Init.
void Shutdown();
@@ -405,6 +439,32 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
int request_id,
bool pause);
+ // Performs the last steps required when a download has been completed.
+ // It is necessary to break down the flow when a download is finished as
+ // dangerous downloads are downloaded to temporary files that need to be
+ // renamed on the file thread first.
+ // Invoked on the UI thread.
+ void ContinueDownloadFinished(DownloadItem* download);
+
+ // Renames a finished dangerous download from its temporary file name to its
+ // real file name.
+ // Invoked on the file thread.
+ void ProceedWithFinishedDangerousDownload(int64 download_handle,
+ const std::wstring& path,
+ const std::wstring& original_name);
+
+ // Invoked on the UI thread when a dangerous downloaded file has been renamed.
+ void DangerousDownloadRenamed(int64 download_handle,
+ bool success,
+ const std::wstring& new_path);
+
+ // Checks whether a file represents a risk if downloaded.
+ bool IsDangerous(const std::wstring& file_name);
+
+ // Changes the paths and file name of the specified |download|, propagating
+ // the change to the history system.
+ void RenameDownload(DownloadItem* download, const std::wstring& new_path);
+
// 'downloads_' is map of all downloads in this profile. The key is the handle
// returned by the history system, which is unique across sessions. This map
// owns all the DownloadItems once they have been created in the history
@@ -415,6 +475,12 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
// ResourceDispatcherHost, which is unique for the current session. This map
// does not own the DownloadItems.
//
+ // 'dangerous_finished_' is a map of dangerous download that have finished
+ // but were not yet approved by the user. Similarly to in_progress_, the key
+ // is the ID assigned by the ResourceDispatcherHost and the map does not own
+ // the DownloadItems. It is used on shutdown to delete completed downloads
+ // that have not been approved.
+ //
// When a download is created through a user action, the corresponding
// DownloadItem* is placed in 'in_progress_' and remains there until it has
// received a valid handle from the history system. Once it has a valid
@@ -426,6 +492,7 @@ class DownloadManager : public base::RefCountedThreadSafe<DownloadManager>,
typedef base::hash_map<int64, DownloadItem*> DownloadMap;
DownloadMap downloads_;
DownloadMap in_progress_;
+ DownloadMap dangerous_finished_;
// True if the download manager has been initialized and requires a shutdown.
bool shutdown_needed_;
diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc
index 530eade..96de46c 100644
--- a/chrome/browser/download/download_util.cc
+++ b/chrome/browser/download/download_util.cc
@@ -133,7 +133,7 @@ void BaseContextMenu::ExecuteCommand(int id) {
break;
}
case REMOVE_ITEM:
- download_->Remove();
+ download_->Remove(false);
break;
case CANCEL:
download_->Cancel(true);
diff --git a/chrome/browser/download/save_package.cc b/chrome/browser/download/save_package.cc
index 127fa53..ff56be2 100644
--- a/chrome/browser/download/save_package.cc
+++ b/chrome/browser/download/save_package.cc
@@ -126,7 +126,7 @@ SavePackage::~SavePackage() {
// We call this to remove the view from the shelf. It will invoke
// DownloadManager::RemoveDownload, but since the fake DownloadItem is not
// owned by DownloadManager, it will do nothing to our fake item.
- download_->Remove();
+ download_->Remove(false);
delete download_;
download_ = NULL;
}
@@ -174,8 +174,8 @@ bool SavePackage::Init() {
}
// Create the fake DownloadItem and display the view.
- download_ = new DownloadItem(1, saved_main_file_path_,
- page_url_, Time::Now(), 0, -1, -1);
+ download_ = new DownloadItem(1, saved_main_file_path_, page_url_,
+ std::wstring(), Time::Now(), 0, -1, -1, false);
download_->set_manager(web_contents_->profile()->GetDownloadManager());
DownloadShelfView* shelf = web_contents_->GetDownloadShelfView();
shelf->AddDownloadView(new DownloadItemView(
diff --git a/chrome/browser/history/download_database.cc b/chrome/browser/history/download_database.cc
index 1baf976..e604e5d 100644
--- a/chrome/browser/history/download_database.cc
+++ b/chrome/browser/history/download_database.cc
@@ -93,6 +93,20 @@ bool DownloadDatabase::UpdateDownload(int64 received_bytes,
return statement->step() == SQLITE_DONE;
}
+bool DownloadDatabase::UpdateDownloadPath(const std::wstring& path,
+ DownloadID db_handle) {
+ DCHECK(db_handle > 0);
+ SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
+ "UPDATE downloads "
+ "SET full_path=? WHERE id=?");
+ if (!statement.is_valid())
+ return false;
+
+ statement->bind_wstring(0, path);
+ statement->bind_int64(1, db_handle);
+ return statement->step() == SQLITE_DONE;
+}
+
int64 DownloadDatabase::CreateDownload(const DownloadCreateInfo& info) {
SQLITE_UNIQUE_STATEMENT(statement, GetStatementCache(),
"INSERT INTO downloads "
diff --git a/chrome/browser/history/download_database.h b/chrome/browser/history/download_database.h
index 1fc9812..d733546 100644
--- a/chrome/browser/history/download_database.h
+++ b/chrome/browser/history/download_database.h
@@ -27,6 +27,9 @@ class DownloadDatabase {
// Update the state of one download. Returns true if successful.
bool UpdateDownload(int64 received_bytes, int32 state, DownloadID db_handle);
+ // Update the path of one download. Returns true if successful.
+ bool UpdateDownloadPath(const std::wstring& path, DownloadID db_handle);
+
// Create a new database entry for one download and return its primary db id.
int64 CreateDownload(const DownloadCreateInfo& info);
diff --git a/chrome/browser/history/download_types.h b/chrome/browser/history/download_types.h
index 16f3ad7..5b6e5b4 100644
--- a/chrome/browser/history/download_types.h
+++ b/chrome/browser/history/download_types.h
@@ -37,7 +37,8 @@ struct DownloadCreateInfo {
render_view_id(-1),
request_id(-1),
db_handle(0),
- save_as(false) {
+ save_as(false),
+ is_dangerous(false) {
}
DownloadCreateInfo() : download_id(-1) {}
@@ -59,6 +60,10 @@ struct DownloadCreateInfo {
std::string content_disposition;
std::string mime_type;
bool save_as;
+ // Whether this download is potentially dangerous (ex: exe, dll, ...).
+ bool is_dangerous;
+ // The original name for a dangerous download.
+ std::wstring original_name;
};
#endif // CHROME_BROWSER_DOWNLOAD_TYPES_H__
diff --git a/chrome/browser/history/history.cc b/chrome/browser/history/history.cc
index db04446..92bea22 100644
--- a/chrome/browser/history/history.cc
+++ b/chrome/browser/history/history.cc
@@ -469,6 +469,12 @@ void HistoryService::UpdateDownload(int64 received_bytes,
received_bytes, state, db_handle);
}
+void HistoryService::UpdateDownloadPath(const std::wstring& path,
+ int64 db_handle) {
+ ScheduleAndForget(PRIORITY_NORMAL, &HistoryBackend::UpdateDownloadPath,
+ path, db_handle);
+}
+
void HistoryService::RemoveDownload(int64 db_handle) {
ScheduleAndForget(PRIORITY_NORMAL,
&HistoryBackend::RemoveDownload, db_handle);
diff --git a/chrome/browser/history/history.h b/chrome/browser/history/history.h
index 74ef67b..2aee029 100644
--- a/chrome/browser/history/history.h
+++ b/chrome/browser/history/history.h
@@ -421,6 +421,10 @@ class HistoryService : public CancelableRequestProvider,
// the database with no need for a callback.
void UpdateDownload(int64 received_bytes, int32 state, int64 db_handle);
+ // Called to update the history service about the path of a download.
+ // This is a 'fire and forget' query.
+ void UpdateDownloadPath(const std::wstring& path, int64 db_handle);
+
// Permanently remove a download from the history system. This is a 'fire and
// forget' operation.
void RemoveDownload(int64 db_handle);
diff --git a/chrome/browser/history/history_backend.cc b/chrome/browser/history/history_backend.cc
index 21f77fb..f8e6449 100644
--- a/chrome/browser/history/history_backend.cc
+++ b/chrome/browser/history/history_backend.cc
@@ -934,6 +934,13 @@ void HistoryBackend::UpdateDownload(int64 received_bytes,
db_->UpdateDownload(received_bytes, state, db_handle);
}
+// Update the path of a particular download entry.
+void HistoryBackend::UpdateDownloadPath(const std::wstring& path,
+ int64 db_handle) {
+ if (db_.get())
+ db_->UpdateDownloadPath(path, db_handle);
+}
+
// Create a new download entry and pass back the db_handle to it.
void HistoryBackend::CreateDownload(
scoped_refptr<DownloadCreateRequest> request,
diff --git a/chrome/browser/history/history_backend.h b/chrome/browser/history/history_backend.h
index dd37c3e..e646570 100644
--- a/chrome/browser/history/history_backend.h
+++ b/chrome/browser/history/history_backend.h
@@ -193,6 +193,7 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
void QueryDownloads(scoped_refptr<DownloadQueryRequest> request);
void UpdateDownload(int64 received_bytes, int32 state, int64 db_handle);
+ void UpdateDownloadPath(const std::wstring& path, int64 db_handle);
void CreateDownload(scoped_refptr<DownloadCreateRequest> request,
const DownloadCreateInfo& info);
void RemoveDownload(int64 db_handle);
diff --git a/chrome/browser/resource_dispatcher_host.cc b/chrome/browser/resource_dispatcher_host.cc
index e6035f8..4b0f37c 100644
--- a/chrome/browser/resource_dispatcher_host.cc
+++ b/chrome/browser/resource_dispatcher_host.cc
@@ -302,6 +302,7 @@ class ResourceDispatcherHost::DownloadEventHandler
info->content_disposition = content_disposition_;
info->mime_type = response->response_head.mime_type;
info->save_as = save_as_;
+ info->is_dangerous = false;
download_manager_->file_loop()->PostTask(FROM_HERE,
NewRunnableMethod(download_manager_,
&DownloadFileManager::StartDownload,
diff --git a/chrome/browser/views/download_item_view.cc b/chrome/browser/views/download_item_view.cc
index 2dcba5a..6d0af1e3 100644
--- a/chrome/browser/views/download_item_view.cc
+++ b/chrome/browser/views/download_item_view.cc
@@ -6,6 +6,8 @@
#include <vector>
+#include "base/file_util.h"
+#include "base/string_util.h"
#include "chrome/app/theme/theme_resources.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_util.h"
@@ -14,6 +16,7 @@
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/common/win_util.h"
+#include "chrome/views/native_button.h"
#include "chrome/views/root_view.h"
#include "chrome/views/view_container.h"
@@ -23,15 +26,27 @@
// animation is added, and also possibly to take into account
// different screen resolutions.
static const int kTextWidth = 140; // Pixels
+static const int kDangerousTextWidth = 200; // Pixels
static const int kHorizontalTextPadding = 2; // Pixels
static const int kVerticalPadding = 3; // Pixels
static const int kVerticalTextSpacer = 2; // Pixels
static const int kVerticalTextPadding = 2; // Pixels
+// The maximum number of characters we show in a file name when displaying the
+// dangerous download message.
+static const int kFileNameMaxLength = 20;
+
// We add some padding before the left image so that the progress animation icon
// hides the corners of the left image.
static const int kLeftPadding = 0; // Pixels.
+// The space between the Save and Discard buttons when prompting for a dangerous
+// donwload.
+static const int kButtonPadding = 5; // Pixels.
+
+// The space on the left and right side of the dangerous donwload label.
+static const int kLabelPadding = 4; // Pixels.
+
static const SkColor kFileNameColor = SkColorSetRGB(87, 108, 149);
static const SkColor kStatusColor = SkColorSetRGB(123, 141, 174);
@@ -50,11 +65,16 @@ DownloadItemView::DownloadItemView(DownloadItem* download,
body_state_(NORMAL),
drop_down_state_(NORMAL),
drop_down_pressed_(false),
- file_name_(download_->file_name()),
status_text_(l10n_util::GetString(IDS_DOWNLOAD_STATUS_STARTING)),
show_status_text_(true),
dragging_(false),
- starting_drag_(false) {
+ starting_drag_(false),
+ warning_icon_(NULL),
+ save_button_(NULL),
+ discard_button_(NULL),
+ dangerous_download_label_(NULL),
+ dangerous_download_label_sized_(false),
+ cached_button_size_(0, 0) {
// TODO(idana) Bug# 1163334
//
// We currently do not mirror each download item on the download shelf (even
@@ -131,6 +151,19 @@ DownloadItemView::DownloadItemView(DownloadItem* download,
};
pushed_drop_down_image_set_ = pushed_drop_down_image_set;
+ BodyImageSet dangerous_mode_body_image_set = {
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_TOP),
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_MIDDLE),
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_LEFT_BOTTOM),
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_TOP),
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_MIDDLE),
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_CENTER_BOTTOM),
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_TOP_NO_DD),
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_MIDDLE_NO_DD),
+ rb.GetBitmapNamed(IDR_DOWNLOAD_BUTTON_RIGHT_BOTTOM_NO_DD)
+ };
+ dangerous_mode_body_image_set_ = dangerous_mode_body_image_set;
+
LoadIcon();
font_ = ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
@@ -152,6 +185,33 @@ DownloadItemView::DownloadItemView(DownloadItem* download,
body_hover_animation_.reset(new SlideAnimation(this));
drop_hover_animation_.reset(new SlideAnimation(this));
+ if (download->safety_state() == DownloadItem::DANGEROUS) {
+ body_state_ = DANGEROUS;
+ drop_down_state_ = DANGEROUS;
+
+ warning_icon_ = rb.GetBitmapNamed(IDR_WARNING);
+ save_button_ = new ChromeViews::NativeButton(
+ l10n_util::GetString(IDS_SAVE_DOWNLOAD));
+ save_button_->set_enforce_dlu_min_size(false);
+ save_button_->SetListener(this);
+ discard_button_ = new ChromeViews::NativeButton(
+ l10n_util::GetString(IDS_DISCARD_DOWNLOAD));
+ discard_button_->SetListener(this);
+ discard_button_->set_enforce_dlu_min_size(false);
+ AddChildView(save_button_);
+ AddChildView(discard_button_);
+ std::wstring file_name = download->original_name();
+ // Ensure the file name is not too long.
+ ElideString(file_name, kFileNameMaxLength, &file_name);
+ dangerous_download_label_ = new ChromeViews::Label(
+ l10n_util::GetStringF(IDS_PROMPT_DANGEROUS_DOWNLOAD, file_name));
+ dangerous_download_label_->SetMultiLine(true);
+ dangerous_download_label_->SetHorizontalAlignment(
+ ChromeViews::Label::ALIGN_LEFT);
+ dangerous_download_label_->SetColor(kFileNameColor);
+ AddChildView(dangerous_download_label_);
+ }
+
// Set up our animation
StartDownloadProgress();
}
@@ -190,6 +250,12 @@ void DownloadItemView::StopDownloadProgress() {
void DownloadItemView::OnDownloadUpdated(DownloadItem* download) {
DCHECK(download == download_);
+ if (body_state_ == DANGEROUS &&
+ download->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED) {
+ // We have been approved.
+ ClearDangerousMode();
+ }
+
std::wstring status_text = model_->GetStatusText();
switch (download_->state()) {
case DownloadItem::IN_PROGRESS:
@@ -227,18 +293,46 @@ void DownloadItemView::OnDownloadUpdated(DownloadItem* download) {
// View overrides
+// In dangerous mode we have to layout our buttons.
+void DownloadItemView::Layout() {
+ if (IsDangerousMode()) {
+ SizeLabelToMinWidth();
+ int x = kLeftPadding + dangerous_mode_body_image_set_.top_left->width() +
+ warning_icon_->width() + kLabelPadding;
+ int y = (height() - dangerous_download_label_->height()) / 2;
+ dangerous_download_label_->SetBounds(x, y,
+ dangerous_download_label_->width(),
+ dangerous_download_label_->height());
+ CSize button_size;
+ GetButtonSize(&button_size);
+ x += dangerous_download_label_->width() + kLabelPadding;
+ y = (height() - button_size.cy) / 2;
+ save_button_->SetBounds(x, y, button_size.cx, button_size.cy);
+ x += button_size.cx + kButtonPadding;
+ discard_button_->SetBounds(x, y, button_size.cx, button_size.cy);
+ }
+}
+
+void DownloadItemView::DidChangeBounds(const CRect& previous,
+ const CRect& current) {
+ Layout();
+}
+
+void DownloadItemView::ButtonPressed(ChromeViews::NativeButton* sender) {
+ if (sender == discard_button_) {
+ if (download_->state() == DownloadItem::IN_PROGRESS)
+ download_->Cancel(true);
+ download_->Remove(true);
+ // WARNING: we are deleted at this point. Don't access 'this'.
+ } else if (sender == save_button_) {
+ // This will change the state and notify us.
+ download_->manager()->DangerousDownloadValidated(download_);
+ }
+}
+
// Load an icon for the file type we're downloading, and animate any in progress
// download state.
void DownloadItemView::Paint(ChromeCanvas* canvas) {
- int center_width = width() - kLeftPadding -
- normal_body_image_set_.left->width() -
- normal_body_image_set_.right->width() -
- normal_drop_down_image_set_.center->width();
-
- // May be caused by animation.
- if (center_width <= 0)
- return;
-
BodyImageSet* body_image_set;
switch (body_state_) {
case NORMAL:
@@ -248,6 +342,9 @@ void DownloadItemView::Paint(ChromeCanvas* canvas) {
case PUSHED:
body_image_set = &pushed_body_image_set_;
break;
+ case DANGEROUS:
+ body_image_set = &dangerous_mode_body_image_set_;
+ break;
default:
NOTREACHED();
}
@@ -260,10 +357,24 @@ void DownloadItemView::Paint(ChromeCanvas* canvas) {
case PUSHED:
drop_down_image_set = &pushed_drop_down_image_set_;
break;
+ case DANGEROUS:
+ drop_down_image_set = NULL; // No drop-down in dangerous mode.
+ break;
default:
NOTREACHED();
}
+ int center_width = width() - kLeftPadding -
+ body_image_set->left->width() -
+ body_image_set->right->width() -
+ (drop_down_image_set ?
+ normal_drop_down_image_set_.center->width() :
+ 0);
+
+ // May be caused by animation.
+ if (center_width <= 0)
+ return;
+
// Paint the background images.
int x = kLeftPadding;
PaintBitmaps(canvas,
@@ -302,65 +413,76 @@ void DownloadItemView::Paint(ChromeCanvas* canvas) {
PaintBitmaps(canvas,
hot_body_image_set_.top_right, hot_body_image_set_.right,
hot_body_image_set_.bottom_right,
- x, box_y_, box_height_, hot_body_image_set_.top_right->width());
+ x, box_y_, box_height_,
+ hot_body_image_set_.top_right->width());
canvas->restore();
}
x += body_image_set->top_right->width();
- PaintBitmaps(canvas,
- drop_down_image_set->top, drop_down_image_set->center,
- drop_down_image_set->bottom,
- x, box_y_, box_height_, drop_down_image_set->top->width());
-
- // Overlay our drop-down hot state.
- if (drop_hover_animation_->GetCurrentValue() > 0) {
- canvas->saveLayerAlpha(NULL,
- static_cast<int>(drop_hover_animation_->GetCurrentValue() * 255),
- SkCanvas::kARGB_NoClipLayer_SaveFlag);
- canvas->drawARGB(0, 255, 255, 255, SkPorterDuff::kClear_Mode);
+ // Paint the drop-down.
+ if (drop_down_image_set) {
PaintBitmaps(canvas,
drop_down_image_set->top, drop_down_image_set->center,
drop_down_image_set->bottom,
x, box_y_, box_height_, drop_down_image_set->top->width());
- canvas->restore();
+ // Overlay our drop-down hot state.
+ if (drop_hover_animation_->GetCurrentValue() > 0) {
+ canvas->saveLayerAlpha(NULL,
+ static_cast<int>(drop_hover_animation_->GetCurrentValue() * 255),
+ SkCanvas::kARGB_NoClipLayer_SaveFlag);
+ canvas->drawARGB(0, 255, 255, 255, SkPorterDuff::kClear_Mode);
+
+ PaintBitmaps(canvas,
+ drop_down_image_set->top, drop_down_image_set->center,
+ drop_down_image_set->bottom,
+ x, box_y_, box_height_, drop_down_image_set->top->width());
+
+ canvas->restore();
+ }
}
// Print the text, left aligned.
// Last value of x was the end of the right image, just before the button.
- if (show_status_text_) {
- int y = box_y_ + kVerticalPadding;
- canvas->DrawStringInt(file_name_, font_, kFileNameColor,
- download_util::kSmallProgressIconSize, y,
- kTextWidth, font_.height());
- y += font_.height() + kVerticalTextPadding;
-
- canvas->DrawStringInt(status_text_, font_, kStatusColor,
- download_util::kSmallProgressIconSize, y,
- kTextWidth, font_.height());
- } else {
- int y = box_y_ + (box_height_ - font_.height()) / 2;
- canvas->DrawStringInt(file_name_, font_, kFileNameColor,
- download_util::kSmallProgressIconSize, y,
- kTextWidth, font_.height());
+ // Note that in dangerous mode we use a label (as the text is multi-line).
+ if (!IsDangerousMode()) {
+ if (show_status_text_) {
+ int y = box_y_ + kVerticalPadding;
+ canvas->DrawStringInt(download_->GetFileName(), font_, kFileNameColor,
+ download_util::kSmallProgressIconSize, y,
+ kTextWidth, font_.height());
+ y += font_.height() + kVerticalTextPadding;
+
+ canvas->DrawStringInt(status_text_, font_, kStatusColor,
+ download_util::kSmallProgressIconSize, y,
+ kTextWidth, font_.height());
+ } else {
+ int y = box_y_ + (box_height_ - font_.height()) / 2;
+ canvas->DrawStringInt(download_->GetFileName(), font_, kFileNameColor,
+ download_util::kSmallProgressIconSize, y,
+ kTextWidth, font_.height());
+ }
}
// Paint the icon.
IconManager* im = g_browser_process->icon_manager();
- SkBitmap* icon = im->LookupIcon(download_->full_path(), IconLoader::SMALL);
+ SkBitmap* icon = IsDangerousMode() ? warning_icon_ :
+ im->LookupIcon(download_->full_path(), IconLoader::SMALL);
if (icon) {
- if (download_->state() == DownloadItem::IN_PROGRESS) {
- download_util::PaintDownloadProgress(canvas, this, 0, 0,
- progress_angle_,
- download_->PercentComplete(),
- download_util::SMALL);
- } else if (download_->state() == DownloadItem::COMPLETE &&
- complete_animation_->IsAnimating()) {
- download_util::PaintDownloadComplete(canvas, this, 0, 0,
- complete_animation_->GetCurrentValue(),
- download_util::SMALL);
+ if (!IsDangerousMode()) {
+ if (download_->state() == DownloadItem::IN_PROGRESS) {
+ download_util::PaintDownloadProgress(canvas, this, 0, 0,
+ progress_angle_,
+ download_->PercentComplete(),
+ download_util::SMALL);
+ } else if (download_->state() == DownloadItem::COMPLETE &&
+ complete_animation_->IsAnimating()) {
+ download_util::PaintDownloadComplete(canvas, this, 0, 0,
+ complete_animation_->GetCurrentValue(),
+ download_util::SMALL);
+ }
}
// Draw the icon image
@@ -401,20 +523,65 @@ void DownloadItemView::SetState(State body_state, State drop_down_state) {
SchedulePaint();
}
-void DownloadItemView::GetPreferredSize(CSize* out) {
- int width = kLeftPadding + normal_body_image_set_.top_left->width();
- width += download_util::kSmallProgressIconSize;
- width += kTextWidth;
- width += normal_body_image_set_.top_right->width();
- width += normal_drop_down_image_set_.top->width();
+void DownloadItemView::ClearDangerousMode() {
+ DCHECK(download_->safety_state() == DownloadItem::DANGEROUS_BUT_VALIDATED &&
+ body_state_ == DANGEROUS && drop_down_state_ == DANGEROUS);
+
+ body_state_ = NORMAL;
+ drop_down_state_ = NORMAL;
+
+ // Remove the views used by the dangerours mode.
+ RemoveChildView(save_button_);
+ delete save_button_;
+ save_button_ = NULL;
+ RemoveChildView(discard_button_);
+ delete discard_button_;
+ discard_button_ = NULL;
+ RemoveChildView(dangerous_download_label_);
+ delete dangerous_download_label_;
+ dangerous_download_label_ = NULL;
+
+ // We need to load the icon now that the download_ has the real path.
+ LoadIcon();
+
+ // Force the shelf to layout again as our size has changed.
+ parent_->Layout();
+ parent_->SchedulePaint();
+}
+void DownloadItemView::GetPreferredSize(CSize* out) {
+ int width, height;
+ if (IsDangerousMode()) {
+ width = kLeftPadding + dangerous_mode_body_image_set_.top_left->width();
+ width += warning_icon_->width() + kLabelPadding;
+ width += dangerous_download_label_->width() + kLabelPadding;
+ CSize button_size;
+ GetButtonSize(&button_size);
+ width += button_size.cx * 2 + kButtonPadding;
+ width += dangerous_mode_body_image_set_.top_right->width();
+ height = std::max<int>(2 * kVerticalPadding + 2 * font_.height() +
+ kVerticalTextPadding,
+ 2 * kVerticalPadding + warning_icon_->height());
+ height = std::max<int>(height, 2 * kVerticalPadding + button_size.cy);
+ } else {
+ width = kLeftPadding + normal_body_image_set_.top_left->width();
+ width += download_util::kSmallProgressIconSize;
+ width += kTextWidth;
+ width += normal_body_image_set_.top_right->width();
+ width += normal_drop_down_image_set_.top->width();
+ height = std::max<int>(2 * kVerticalPadding + 2 * font_.height() +
+ kVerticalTextPadding,
+ download_util::kSmallProgressIconSize);
+ }
out->cx = width;
- out->cy = std::max<int>(
- 2 * kVerticalPadding + 2 * font_.height() + kVerticalTextPadding,
- download_util::kSmallProgressIconSize);
+ out->cy = height;
}
void DownloadItemView::OnMouseExited(const ChromeViews::MouseEvent& event) {
+ // Mouse should not activate us in dangerous mode.
+ if (IsDangerousMode())
+ return;
+
SetState(NORMAL, drop_down_pressed_ ? PUSHED : NORMAL);
body_hover_animation_->Hide();
drop_hover_animation_->Hide();
@@ -422,6 +589,10 @@ void DownloadItemView::OnMouseExited(const ChromeViews::MouseEvent& event) {
// Display the context menu for this item.
bool DownloadItemView::OnMousePressed(const ChromeViews::MouseEvent& event) {
+ // Mouse should not activate us in dangerous mode.
+ if (IsDangerousMode())
+ return true;
+
// Stop any completion animation.
if (complete_animation_.get() && complete_animation_->IsAnimating())
complete_animation_->End();
@@ -472,6 +643,10 @@ bool DownloadItemView::OnMousePressed(const ChromeViews::MouseEvent& event) {
}
void DownloadItemView::OnMouseMoved(const ChromeViews::MouseEvent& event) {
+ // Mouse should not activate us in dangerous mode.
+ if (IsDangerousMode())
+ return;
+
bool on_body = event.x() < drop_down_x_;
SetState(on_body ? HOT : NORMAL, on_body ? NORMAL : HOT);
if (on_body) {
@@ -485,6 +660,10 @@ void DownloadItemView::OnMouseMoved(const ChromeViews::MouseEvent& event) {
void DownloadItemView::OnMouseReleased(const ChromeViews::MouseEvent& event,
bool canceled) {
+ // Mouse should not activate us in dangerous mode.
+ if (IsDangerousMode())
+ return;
+
if (dragging_) {
// Starting a drag results in a MouseReleased, we need to ignore it.
dragging_ = false;
@@ -499,6 +678,10 @@ void DownloadItemView::OnMouseReleased(const ChromeViews::MouseEvent& event,
// Handle drag (file copy) operations.
bool DownloadItemView::OnMouseDragged(const ChromeViews::MouseEvent& event) {
+ // Mouse should not activate us in dangerous mode.
+ if (IsDangerousMode())
+ return true;
+
if (!starting_drag_) {
starting_drag_ = true;
drag_start_point_ = event.location();
@@ -544,3 +727,71 @@ void DownloadItemView::LoadIcon() {
NewCallback(this, &DownloadItemView::OnExtractIconComplete));
}
+void DownloadItemView::GetButtonSize(CSize* size) {
+ DCHECK(save_button_ && discard_button_);
+ // We cache the size when successfully retrieved, not for performance reasons
+ // but because if this DownloadItemView is being animated while the tab is
+ // not showing, the native buttons are not parented and their preferred size
+ // is 0, messing-up the layout.
+ if (cached_button_size_.cx != 0) {
+ *size = cached_button_size_;
+ }
+
+ CSize tmp_size;
+ save_button_->GetMinimumSize(size);
+ discard_button_->GetMinimumSize(&tmp_size);
+
+ size->cx = std::max(size->cx, tmp_size.cx);
+ size->cy = std::max(size->cy, tmp_size.cy);
+
+ if (size->cx != 0) {
+ cached_button_size_.cx = size->cx;
+ cached_button_size_.cy = size->cy;
+ }
+}
+
+// This method computes the miminum width of the label for diplaying its text
+// on 2 lines. It just breaks the string in 2 lines on the spaces and keeps the
+// configuration with minimum width.
+void DownloadItemView::SizeLabelToMinWidth() {
+ if (dangerous_download_label_sized_)
+ return;
+
+ std::wstring text = dangerous_download_label_->GetText();
+ TrimWhitespace(text, TRIM_ALL, &text);
+ DCHECK_EQ(std::wstring::npos, text.find(L"\n"));
+
+ // Make the label big so that GetPreferredSize() is not constrained by the
+ // current width.
+ dangerous_download_label_->SetBounds(0, 0, 1000, 1000);
+
+ CSize size(0, 0);
+ int min_width = -1;
+ int sp_index = text.find(L" ");
+ while (sp_index != std::wstring::npos) {
+ text.replace(sp_index, 1, L"\n");
+ dangerous_download_label_->SetText(text);
+ dangerous_download_label_->GetPreferredSize(&size);
+
+ if (min_width == -1)
+ min_width = size.cx;
+
+ // If thw width is growing again, it means we passed the optimal width spot.
+ if (size.cx > min_width)
+ break;
+ else
+ min_width = size.cx;
+
+ // Restore the string.
+ text.replace(sp_index, 1, L" ");
+
+ sp_index = text.find(L" ", sp_index + 1);
+ }
+
+ // If we have a line with no space, we won't cut it.
+ if (min_width == -1)
+ dangerous_download_label_->GetPreferredSize(&size);
+
+ dangerous_download_label_->SetBounds(0, 0, size.cx, size.cy);
+ dangerous_download_label_sized_ = true;
+} \ No newline at end of file
diff --git a/chrome/browser/views/download_item_view.h b/chrome/browser/views/download_item_view.h
index 69adcc4..c29a154 100644
--- a/chrome/browser/views/download_item_view.h
+++ b/chrome/browser/views/download_item_view.h
@@ -26,13 +26,17 @@
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/icon_manager.h"
#include "chrome/views/event.h"
+#include "chrome/views/native_button.h"
#include "chrome/views/view.h"
-#include "chrome/views/label.h"
+namespace ChromeViews {
+ class Label;
+}
class DownloadShelfView;
class SkBitmap;
-class DownloadItemView : public ChromeViews::View,
+class DownloadItemView : public ChromeViews::NativeButton::Listener,
+ public ChromeViews::View,
public DownloadItem::Observer,
public AnimationDelegate {
public:
@@ -56,6 +60,7 @@ class DownloadItemView : public ChromeViews::View,
virtual void OnDownloadUpdated(DownloadItem* download);
// View overrides
+ virtual void Layout();
virtual void Paint(ChromeCanvas* canvas);
virtual void GetPreferredSize(CSize *out);
virtual void OnMouseExited(const ChromeViews::MouseEvent& event);
@@ -64,6 +69,10 @@ class DownloadItemView : public ChromeViews::View,
virtual void OnMouseReleased(const ChromeViews::MouseEvent& event,
bool canceled);
virtual bool OnMouseDragged(const ChromeViews::MouseEvent& event);
+ virtual void DidChangeBounds(const CRect& previous, const CRect& current);
+
+ // NativeButton::Listener implementation.
+ virtual void ButtonPressed(ChromeViews::NativeButton* sender);
// AnimationDelegate implementation.
virtual void AnimationProgressed(const Animation* animation);
@@ -81,6 +90,7 @@ class DownloadItemView : public ChromeViews::View,
NORMAL = 0,
HOT,
PUSHED,
+ DANGEROUS
};
// The image set associated with the part containing the icon and text.
@@ -121,14 +131,33 @@ class DownloadItemView : public ChromeViews::View,
// Sets the state and triggers a repaint.
void SetState(State body_state, State drop_down_state);
+ // Whether we are in the dangerous mode.
+ bool IsDangerousMode() { return body_state_ == DANGEROUS; }
+
+ // Reverts from dangerous mode to normal download mode.
+ void ClearDangerousMode();
+
+ // Sets |size| with the size of the Save and Discard buttons (they have the
+ // same size).
+ void GetButtonSize(CSize* size);
+
+ // Sizes the dangerous download label to a minimum width available using 2
+ // lines. The size is computed only the first time this method is invoked
+ // and simply returned on subsequent calls.
+ void SizeLabelToMinWidth();
+
// The different images used for the background.
BodyImageSet normal_body_image_set_;
BodyImageSet hot_body_image_set_;
BodyImageSet pushed_body_image_set_;
+ BodyImageSet dangerous_mode_body_image_set_;
DropDownImageSet normal_drop_down_image_set_;
DropDownImageSet hot_drop_down_image_set_;
DropDownImageSet pushed_drop_down_image_set_;
+ // The warning icon showns for dangerous downloads.
+ SkBitmap* warning_icon_;
+
// The model we query for display information
DownloadItem* download_;
@@ -136,7 +165,6 @@ class DownloadItemView : public ChromeViews::View,
DownloadShelfView* parent_;
// Elements of our particular download
- std::wstring file_name_;
std::wstring status_text_;
bool show_status_text_;
@@ -189,6 +217,19 @@ class DownloadItemView : public ChromeViews::View,
// Progress animation
base::RepeatingTimer<DownloadItemView> progress_timer_;
+ // Dangerous mode buttons.
+ ChromeViews::NativeButton* save_button_;
+ ChromeViews::NativeButton* discard_button_;
+
+ // Dangerous mode label.
+ ChromeViews::Label* dangerous_download_label_;
+
+ // Whether the dangerous mode label has been sized yet.
+ bool dangerous_download_label_sized_;
+
+ // The size of the buttons. Cached so animation works when hidden.
+ CSize cached_button_size_;
+
DISALLOW_EVIL_CONSTRUCTORS(DownloadItemView);
};
diff --git a/chrome/browser/views/download_tab_view.cc b/chrome/browser/views/download_tab_view.cc
index 62e5668..679aa54 100644
--- a/chrome/browser/views/download_tab_view.cc
+++ b/chrome/browser/views/download_tab_view.cc
@@ -30,7 +30,8 @@
// Approximate spacing, in pixels, taken from initial UI mock up screens
static const int kVerticalPadding = 5;
-static const int kHorizontalButtonPadding = 15;
+static const int kHorizontalLinkPadding = 15;
+static const int kHorizontalButtonPadding = 8;
// For vertical and horizontal element spacing
static const int kSpacer = 20;
@@ -65,12 +66,19 @@ static const SkColor kUrlColor = SkColorSetRGB(0, 128, 0);
// Paused download indicator (red)
static const SkColor kPauseColor = SkColorSetRGB(128, 0, 0);
+// Warning label color (blue)
+static const SkColor kWarningColor = SkColorSetRGB(87, 108, 149);
+
// Selected item background color
static const SkColor kSelectedItemColor = SkColorSetRGB(215, 232, 255);
// State key used to identify search text.
static const wchar_t kSearchTextKey[] = L"st";
+// The maximum number of characters we show in a file name when displaying the
+// dangerous download message.
+static const int kFileNameMaxLength = 20;
+
// Sorting functor for DownloadItem --------------------------------------------
// Sort DownloadItems into ascending order by their start time.
@@ -87,7 +95,8 @@ class DownloadItemSorter : public std::binary_function<DownloadItem*,
// DownloadItemTabView implementation ------------------------------------------
DownloadItemTabView::DownloadItemTabView()
: model_(NULL),
- parent_(NULL) {
+ parent_(NULL),
+ is_floating_view_renderer_(false) {
// Create our element views using empty strings for now,
// set them based on the model's state in Layout().
since_ = new ChromeViews::Label(L"");
@@ -111,6 +120,29 @@ DownloadItemTabView::DownloadItemTabView()
file_name_->SetFont(font);
AddChildView(file_name_);
+ // dangerous_download_warning_ is enabled when a dangerous download has been
+ // initiated.
+ dangerous_download_warning_ = new ChromeViews::Label();
+ dangerous_download_warning_ ->SetMultiLine(true);
+ dangerous_download_warning_->SetColor(kWarningColor);
+ dangerous_download_warning_->SetHorizontalAlignment(
+ ChromeViews::Label::ALIGN_LEFT);
+ dangerous_download_warning_->SetFont(font);
+ AddChildView(dangerous_download_warning_);
+
+ // The save and discard buttons are shown to prompt the user when a dangerous
+ // download was started.
+ save_button_ = new ChromeViews::NativeButton(
+ l10n_util::GetString(IDS_SAVE_DOWNLOAD));
+ save_button_->set_enforce_dlu_min_size(false);
+ save_button_->SetListener(this);
+ discard_button_ = new ChromeViews::NativeButton(
+ l10n_util::GetString(IDS_DISCARD_DOWNLOAD));
+ discard_button_->SetListener(this);
+ discard_button_->set_enforce_dlu_min_size(false);
+ AddChildView(save_button_);
+ AddChildView(discard_button_);
+
// Set our URL name
download_url_ = new ChromeViews::Label(L"");
download_url_->SetColor(kUrlColor);
@@ -172,9 +204,9 @@ void DownloadItemTabView::GetPreferredSize(CSize* out) {
out->cx = download_util::kBigProgressIconSize +
2 * kSpacer +
- kHorizontalButtonPadding +
+ kHorizontalLinkPadding +
kFilenameSize +
- std::max(pause_size.cx + cancel_size.cx + kHorizontalButtonPadding,
+ std::max(pause_size.cx + cancel_size.cx + kHorizontalLinkPadding,
show_size.cx);
out->cy = download_util::kBigProgressIconSize;
@@ -188,13 +220,19 @@ void DownloadItemTabView::Layout() {
DCHECK(model_);
switch (model_->state()) {
case DownloadItem::COMPLETE:
- LayoutComplete();
+ if (model_->safety_state() == DownloadItem::DANGEROUS)
+ LayoutPromptDangerousDownload();
+ else
+ LayoutComplete();
break;
case DownloadItem::CANCELLED:
LayoutCancelled();
break;
case DownloadItem::IN_PROGRESS:
- LayoutInProgress();
+ if (model_->safety_state() == DownloadItem::DANGEROUS)
+ LayoutPromptDangerousDownload();
+ else
+ LayoutInProgress();
break;
case DownloadItem::REMOVING:
break;
@@ -238,6 +276,11 @@ void DownloadItemTabView::LayoutComplete() {
cancel_->SetEnabled(false);
time_remaining_->SetVisible(false);
download_progress_->SetVisible(false);
+ dangerous_download_warning_->SetVisible(false);
+ save_button_->SetVisible(false);
+ save_button_->SetEnabled(false);
+ discard_button_->SetVisible(false);
+ discard_button_->SetEnabled(false);
LayoutDate();
int dx = kDownloadIconOffset - download_util::kBigProgressIconOffset +
@@ -286,6 +329,11 @@ void DownloadItemTabView::LayoutCancelled() {
pause_->SetEnabled(false);
cancel_->SetVisible(false);
cancel_->SetEnabled(false);
+ dangerous_download_warning_->SetVisible(false);
+ save_button_->SetVisible(false);
+ save_button_->SetEnabled(false);
+ discard_button_->SetVisible(false);
+ discard_button_->SetEnabled(false);
LayoutDate();
int dx = kDownloadIconOffset - download_util::kBigProgressIconOffset +
@@ -372,6 +420,11 @@ void DownloadItemTabView::LayoutInProgress() {
// Hide unused UI elements
show_->SetVisible(false);
show_->SetEnabled(false);
+ dangerous_download_warning_->SetVisible(false);
+ save_button_->SetVisible(false);
+ save_button_->SetEnabled(false);
+ discard_button_->SetVisible(false);
+ discard_button_->SetEnabled(false);
LayoutDate();
int dx = kDownloadIconOffset - download_util::kBigProgressIconOffset +
@@ -380,7 +433,7 @@ void DownloadItemTabView::LayoutInProgress() {
// File name and URL, truncated to show progress status
CSize file_name_size;
- file_name_->SetText(model_->file_name());
+ file_name_->SetText(model_->GetFileName());
file_name_->GetPreferredSize(&file_name_size);
file_name_->SetBounds(dx, download_util::kBigProgressIconOffset,
kFilenameSize - kProgressSize - kSpacer,
@@ -514,7 +567,7 @@ void DownloadItemTabView::LayoutInProgress() {
pause_->GetPreferredSize(&pause_size);
pause_->SetBounds(dx, y_pos, pause_size.cx, pause_size.cy);
- dx += pause_size.cx + kHorizontalButtonPadding;
+ dx += pause_size.cx + kHorizontalLinkPadding;
CSize cancel_size;
cancel_->GetPreferredSize(&cancel_size);
@@ -523,10 +576,69 @@ void DownloadItemTabView::LayoutInProgress() {
cancel_->SetEnabled(true);
}
+void DownloadItemTabView::LayoutPromptDangerousDownload() {
+ // Hide unused UI elements
+ show_->SetVisible(false);
+ show_->SetEnabled(false);
+ file_name_->SetVisible(false);
+ file_name_->SetEnabled(false);
+ pause_->SetVisible(false);
+ pause_->SetEnabled(false);
+ cancel_->SetVisible(false);
+ cancel_->SetEnabled(false);
+ time_remaining_->SetVisible(false);
+ download_progress_->SetVisible(false);
+
+ LayoutDate();
+ int dx = kDownloadIconOffset - download_util::kBigProgressIconOffset +
+ download_util::kBigProgressIconSize +
+ kInfoPadding;
+
+ // Warning message and URL.
+ CSize warning_size;
+ std::wstring file_name;
+ ElideString(model_->original_name(), kFileNameMaxLength, &file_name);
+ dangerous_download_warning_->SetText(
+ l10n_util::GetStringF(IDS_PROMPT_DANGEROUS_DOWNLOAD, file_name));
+ dangerous_download_warning_->GetPreferredSize(&warning_size);
+ dangerous_download_warning_->SetBounds(dx, 0,
+ kFilenameSize, warning_size.cy);
+ dangerous_download_warning_->SetVisible(true);
+
+ GURL url(model_->url());
+ download_url_->SetURL(url);
+ CSize url_size;
+ download_url_->GetPreferredSize(&url_size);
+ download_url_->SetBounds(dx, height() - url_size.cy,
+ std::min(kFilenameSize - kSpacer,
+ static_cast<int>(width() - dx)),
+ url_size.cy);
+ download_url_->SetVisible(true);
+
+ dx += kFilenameSize + kSpacer;
+
+ // Save/Discard buttons.
+ CSize button_size;
+ save_button_->GetPreferredSize(&button_size);
+ save_button_->SetBounds(dx, (height() - button_size.cy) / 2,
+ button_size.cx, button_size.cy);
+ save_button_->SetVisible(true);
+ save_button_->SetEnabled(true);
+
+ dx += button_size.cx + kHorizontalButtonPadding;
+
+ discard_button_->GetPreferredSize(&button_size);
+ discard_button_->SetBounds(dx, (height() - button_size.cy) / 2,
+ button_size.cx, button_size.cy);
+ discard_button_->SetVisible(true);
+ discard_button_->SetEnabled(true);
+}
+
void DownloadItemTabView::Paint(ChromeCanvas* canvas) {
PaintBackground(canvas);
- if (model_->state() == DownloadItem::IN_PROGRESS) {
+ if (model_->state() == DownloadItem::IN_PROGRESS &&
+ model_->safety_state() != DownloadItem::DANGEROUS) {
download_util::PaintDownloadProgress(canvas,
this,
kDownloadIconOffset -
@@ -605,7 +717,10 @@ bool DownloadItemTabView::OnMousePressed(const ChromeViews::MouseEvent& event) {
if (select_rect.PtInRect(point)) {
parent_->ItemBecameSelected(model_);
- if (event.IsRightMouseButton()) {
+ // Don't show the right-click menu if we are prompting the user for a
+ // dangerous download.
+ if (event.IsRightMouseButton() &&
+ model_->safety_state() != DownloadItem::DANGEROUS) {
ChromeViews::View::ConvertPointToScreen(this, &point);
download_util::DownloadDestinationContextMenu menu(
@@ -620,7 +735,8 @@ bool DownloadItemTabView::OnMousePressed(const ChromeViews::MouseEvent& event) {
// Handle drag (file copy) operations.
bool DownloadItemTabView::OnMouseDragged(const ChromeViews::MouseEvent& event) {
- if (model_->state() != DownloadItem::COMPLETE)
+ if (model_->state() != DownloadItem::COMPLETE ||
+ model_->safety_state() == DownloadItem::DANGEROUS)
return false;
CPoint point(event.x(), event.y());
@@ -665,6 +781,18 @@ void DownloadItemTabView::LinkActivated(ChromeViews::Link* source,
parent_->ItemBecameSelected(model_);
}
+void DownloadItemTabView::ButtonPressed(ChromeViews::NativeButton* sender) {
+ if (sender == save_button_) {
+ parent_->model()->DangerousDownloadValidated(model_);
+ // Relayout and repaint to display the right mode (complete or in progress).
+ Layout();
+ SchedulePaint();
+ } else if (sender == discard_button_) {
+ model_->Remove(true);
+ } else {
+ NOTREACHED();
+ }
+}
// DownloadTabView implementation ----------------------------------------------
@@ -683,6 +811,7 @@ DownloadTabView::~DownloadTabView() {
// DownloadManager owns the contents.
downloads_.clear();
ClearDownloadInProgress();
+ ClearDangerousDownloads();
icon_consumer_.CancelAllRequests();
}
@@ -720,6 +849,21 @@ void DownloadTabView::DidChangeBounds(const CRect& previous,
void DownloadTabView::Layout() {
CRect r;
DetachAllFloatingViews();
+ // Dangerous downloads items use NativeButtons, so they need to be attached
+ // as NativeControls are not supported yet in floating views.
+ gfx::Rect visible_bounds = GetVisibleBounds();
+ int row_start = (visible_bounds.y() - kSpacer) /
+ (download_util::kBigProgressIconSize + kSpacer);
+ int row_stop = (visible_bounds.y() - kSpacer + visible_bounds.height()) /
+ (download_util::kBigProgressIconSize + kSpacer);
+ row_stop = std::min(row_stop, static_cast<int>(downloads_.size()) - 1);
+ for (int i = row_start; i <= row_stop; ++i) {
+ // The DownloadManager stores downloads earliest first, but this view
+ // displays latest first, so adjust the index:
+ int index = static_cast<int>(downloads_.size()) - 1 - i;
+ if (downloads_[index]->safety_state() == DownloadItem::DANGEROUS)
+ ValidateFloatingViewForID(index);
+ }
View* v = GetParent();
if (v) {
v->GetLocalBounds(&r, true);
@@ -790,12 +934,15 @@ ChromeViews::View* DownloadTabView::CreateFloatingViewForIndex(int index) {
}
DownloadItemTabView* dl = new DownloadItemTabView();
+ // We attach the view before layout as the Save/Discard buttons are native
+ // and need to be in the tree hierarchy to compute their preferred size
+ // correctly.
+ AttachFloatingView(dl, index);
dl->SetModel(downloads_[index], this);
int row = static_cast<int>(downloads_.size()) - 1 - index;
int y_pos = row * (download_util::kBigProgressIconSize + kSpacer) + kSpacer;
dl->SetBounds(0, y_pos, width(), download_util::kBigProgressIconSize);
dl->Layout();
- AttachFloatingView(dl, index);
return dl;
}
@@ -817,7 +964,10 @@ void DownloadTabView::OnDownloadUpdated(DownloadItem* download) {
case DownloadItem::CANCELLED: {
base::hash_set<DownloadItem*>::iterator d = in_progress_.find(download);
if (d != in_progress_.end()) {
- (*d)->RemoveObserver(this);
+ // If this is a dangerous download not yet validated by the user, we
+ // still need to be notified when the validation happens.
+ if (download->safety_state() != DownloadItem::DANGEROUS)
+ (*d)->RemoveObserver(this);
in_progress_.erase(d);
}
if (in_progress_.empty())
@@ -877,6 +1027,7 @@ void DownloadTabView::OnDownloadUpdated(DownloadItem* download) {
void DownloadTabView::ModelChanged() {
downloads_.clear();
ClearDownloadInProgress();
+ ClearDangerousDownloads();
DetachAllFloatingViews();
// Issue the query.
@@ -890,6 +1041,7 @@ void DownloadTabView::SetDownloads(std::vector<DownloadItem*>& downloads) {
// Clear out old state and remove self as observer for each download.
downloads_.clear();
ClearDownloadInProgress();
+ ClearDangerousDownloads();
// Swap new downloads in.
downloads_.swap(downloads);
@@ -902,6 +1054,10 @@ void DownloadTabView::SetDownloads(std::vector<DownloadItem*>& downloads) {
if (download->state() == DownloadItem::IN_PROGRESS) {
download->AddObserver(this);
in_progress_.insert(download);
+ } else if (download->safety_state() == DownloadItem::DANGEROUS) {
+ // We need to be notified when the user validates the dangerous download.
+ download->AddObserver(this);
+ dangerous_downloads_.insert(download);
}
}
@@ -949,6 +1105,14 @@ void DownloadTabView::ClearDownloadInProgress() {
in_progress_.clear();
}
+void DownloadTabView::ClearDangerousDownloads() {
+ base::hash_set<DownloadItem*>::const_iterator it;
+ for (it = dangerous_downloads_.begin();
+ it != dangerous_downloads_.end(); ++it)
+ (*it)->RemoveObserver(this);
+ dangerous_downloads_.clear();
+}
+
// Check to see if the download is the latest download on a given day.
// We use this to determine when to draw the date next to a particular
// download view: if the DownloadItem is the latest download on a given
diff --git a/chrome/browser/views/download_tab_view.h b/chrome/browser/views/download_tab_view.h
index 5c1b2ec..f78ee4a 100644
--- a/chrome/browser/views/download_tab_view.h
+++ b/chrome/browser/views/download_tab_view.h
@@ -25,7 +25,8 @@ class Timer;
}
class DownloadItemTabView : public ChromeViews::View,
- public ChromeViews::LinkController {
+ public ChromeViews::LinkController,
+ public ChromeViews::NativeButton::Listener {
public:
DownloadItemTabView();
virtual ~DownloadItemTabView();
@@ -44,10 +45,14 @@ class DownloadItemTabView : public ChromeViews::View,
void LayoutComplete();
void LayoutCancelled();
void LayoutInProgress();
+ void LayoutPromptDangerousDownload();
// LinkController overrides
virtual void LinkActivated(ChromeViews::Link* source, int event_flags);
+ // NativeButton Listener overrides.
+ virtual void ButtonPressed(ChromeViews::NativeButton* sender);
+
// Used to set our model temporarily during layout and paint operations
void SetModel(DownloadItem* model, DownloadTabView* parent);
@@ -58,6 +63,9 @@ private:
// Containing view.
DownloadTabView* parent_;
+ // Whether we are the renderer for floating views.
+ bool is_floating_view_renderer_;
+
// Time display.
ChromeViews::Label* since_;
ChromeViews::Label* date_;
@@ -72,11 +80,19 @@ private:
ChromeViews::Label* time_remaining_;
ChromeViews::Label* download_progress_;
+ // The message warning of a dangerous download.
+ ChromeViews::Label* dangerous_download_warning_;
+
// Actions that can be initiated.
ChromeViews::Link* pause_;
ChromeViews::Link* cancel_;
ChromeViews::Link* show_;
+ // The buttons used to prompt the user when a dangerous download has been
+ // initiated.
+ ChromeViews::NativeButton* save_button_;
+ ChromeViews::NativeButton* discard_button_;
+
DISALLOW_EVIL_CONSTRUCTORS(DownloadItemTabView);
};
@@ -154,10 +170,14 @@ class DownloadTabView : public ChromeViews::View,
// Initiates an asynchronous icon extraction.
void LoadIcon(DownloadItem* download);
- // Clears the list of "in progress" downloads and removes the this
- // DownloadTabView from their observer list.
+ // Clears the list of "in progress" downloads and removes this DownloadTabView
+ // from their observer list.
void ClearDownloadInProgress();
+ // Clears the list of dangerous downloads and removes this DownloadTabView
+ // from their observer list.
+ void ClearDangerousDownloads();
+
// Our model
DownloadManager* model_;
@@ -178,6 +198,10 @@ class DownloadTabView : public ChromeViews::View,
// does not own the DownloadItems.
base::hash_set<DownloadItem*> in_progress_;
+ // Keeps track of the downloads we are an observer for as a consequence of
+ // being a dangerous download.
+ base::hash_set<DownloadItem*> dangerous_downloads_;
+
// Provide a start position for downloads with no known size.
int start_angle_;
diff --git a/chrome/views/native_button.cc b/chrome/views/native_button.cc
index 2db380b..55323c6 100644
--- a/chrome/views/native_button.cc
+++ b/chrome/views/native_button.cc
@@ -5,17 +5,20 @@
#include "chrome/views/native_button.h"
#include "base/logging.h"
+#include "chrome/common/gfx/chrome_canvas.h"
#include "chrome/common/l10n_util.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/views/background.h"
namespace ChromeViews {
-NativeButton::NativeButton(const std::wstring& label) {
+NativeButton::NativeButton(const std::wstring& label)
+ : enforce_dlu_min_size_(true) {
Init(label, false);
}
-NativeButton::NativeButton(const std::wstring& label, bool is_default) {
+NativeButton::NativeButton(const std::wstring& label, bool is_default)
+ : enforce_dlu_min_size_(true) {
Init(label, is_default);
}
@@ -41,13 +44,16 @@ void NativeButton::GetPreferredSize(CSize *out) {
sz.cx += 2 * padding_.cx;
sz.cy += 2 * padding_.cy;
- if (min_dlu_size_.width())
- sz.cx = std::max(static_cast<int>(sz.cx),
- font_.horizontal_dlus_to_pixels(min_dlu_size_.width()));
- if (min_dlu_size_.height())
- sz.cy = std::max(static_cast<int>(sz.cy),
- font_.vertical_dlus_to_pixels(min_dlu_size_.height()));
-
+ if (enforce_dlu_min_size_) {
+ if (min_dlu_size_.width()) {
+ sz.cx =
+ std::max(static_cast<int>(sz.cx),
+ font_.horizontal_dlus_to_pixels(min_dlu_size_.width()));
+ }
+ if (min_dlu_size_.height())
+ sz.cy = std::max(static_cast<int>(sz.cy),
+ font_.vertical_dlus_to_pixels(min_dlu_size_.height()));
+ }
*out = sz;
}
}
@@ -186,4 +192,3 @@ bool NativeButton::OnKeyDown(int virtual_key_code) {
}
}
-
diff --git a/chrome/views/native_button.h b/chrome/views/native_button.h
index 9a42439..935349f 100644
--- a/chrome/views/native_button.h
+++ b/chrome/views/native_button.h
@@ -80,6 +80,10 @@ class NativeButton : public NativeControl {
// Assigns an accessible string name.
void SetAccessibleName(const std::wstring& name);
+ // Sets whether the min size of this button should follow the Windows
+ // guidelines. Default is true. Set this to false if you want slim buttons.
+ void set_enforce_dlu_min_size(bool value) { enforce_dlu_min_size_ = value; }
+
protected:
virtual HWND CreateNativeControl(HWND parent_container);
@@ -106,6 +110,10 @@ class NativeButton : public NativeControl {
void Clicked();
+ // Whether the button preferred size should follow the Microsoft layout
+ // guidelines. Default is true.
+ bool enforce_dlu_min_size_;
+
std::wstring label_;
ChromeFont font_;
Listener* listener_;