Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / base / win / open_file_name_win.cc
blob5b78a8e465198fd5376da96af3bcc7b4bd0dc625
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/base/win/open_file_name_win.h"
7 #include "base/files/file_path.h"
8 #include "base/strings/string_util.h"
9 #include "base/win/windows_version.h"
11 namespace ui {
12 namespace win {
14 namespace {
16 // Ensures that the Save As dialog is on-screen.
17 UINT_PTR CALLBACK SaveAsDialogHook(HWND dialog, UINT message,
18 WPARAM wparam, LPARAM lparam) {
19 static const UINT kPrivateMessage = 0x2F3F;
20 switch (message) {
21 case WM_INITDIALOG: {
22 // Do nothing here. Just post a message to defer actual processing.
23 ::PostMessage(dialog, kPrivateMessage, 0, 0);
24 return TRUE;
26 case kPrivateMessage: {
27 // The dialog box is the parent of the current handle.
28 HWND real_dialog = ::GetParent(dialog);
30 // Retrieve the final size.
31 RECT dialog_rect;
32 ::GetWindowRect(real_dialog, &dialog_rect);
34 // Verify that the upper left corner is visible.
35 POINT point = { dialog_rect.left, dialog_rect.top };
36 HMONITOR monitor1 = ::MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
37 point.x = dialog_rect.right;
38 point.y = dialog_rect.bottom;
40 // Verify that the lower right corner is visible.
41 HMONITOR monitor2 = ::MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
42 if (monitor1 && monitor2)
43 return 0;
45 // Some part of the dialog box is not visible, fix it by moving is to the
46 // client rect position of the browser window.
47 HWND parent_window = ::GetParent(real_dialog);
48 if (!parent_window)
49 return 0;
50 WINDOWINFO parent_info;
51 parent_info.cbSize = sizeof(WINDOWINFO);
52 ::GetWindowInfo(parent_window, &parent_info);
53 ::SetWindowPos(
54 real_dialog,
55 NULL,
56 parent_info.rcClient.left,
57 parent_info.rcClient.top,
59 0, // Size.
60 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
62 return 0;
65 return 0;
68 } // namespace
70 OpenFileName::OpenFileName(HWND parent_window, DWORD flags) {
71 ::ZeroMemory(&openfilename_, sizeof(openfilename_));
72 openfilename_.lStructSize = sizeof(openfilename_);
74 // According to http://support.microsoft.com/?scid=kb;en-us;222003&x=8&y=12,
75 // The lpstrFile Buffer MUST be NULL Terminated.
76 filename_buffer_[0] = 0;
77 openfilename_.lpstrFile = filename_buffer_;
78 openfilename_.nMaxFile = arraysize(filename_buffer_);
80 openfilename_.Flags = flags;
81 openfilename_.hwndOwner = parent_window;
84 OpenFileName::~OpenFileName() {
87 void OpenFileName::SetFilters(
88 const std::vector<Tuple2<base::string16, base::string16> >& filters) {
89 openfilename_.lpstrFilter = NULL;
90 filter_buffer_.clear();
91 if (filters.empty())
92 return;
93 for (std::vector<Tuple2<base::string16, base::string16> >::const_iterator
94 it = filters.begin();
95 it != filters.end();
96 ++it) {
97 filter_buffer_.append(it->a);
98 filter_buffer_.push_back(0);
99 filter_buffer_.append(it->b);
100 filter_buffer_.push_back(0);
102 filter_buffer_.push_back(0);
103 openfilename_.lpstrFilter = filter_buffer_.c_str();
106 void OpenFileName::SetInitialSelection(const base::FilePath& initial_directory,
107 const base::FilePath& initial_filename) {
108 // First reset to the default case.
109 // According to http://support.microsoft.com/?scid=kb;en-us;222003&x=8&y=12,
110 // The lpstrFile Buffer MUST be NULL Terminated.
111 filename_buffer_[0] = 0;
112 openfilename_.lpstrFile = filename_buffer_;
113 openfilename_.nMaxFile = arraysize(filename_buffer_);
114 openfilename_.lpstrInitialDir = NULL;
115 initial_directory_buffer_.clear();
117 if (initial_directory.empty())
118 return;
120 initial_directory_buffer_ = initial_directory.value();
121 openfilename_.lpstrInitialDir = initial_directory_buffer_.c_str();
123 if (initial_filename.empty())
124 return;
126 // The filename is ignored if no initial directory is supplied.
127 base::wcslcpy(filename_buffer_,
128 initial_filename.value().c_str(),
129 arraysize(filename_buffer_));
132 void OpenFileName::MaybeInstallWindowPositionHookForSaveAsOnXP() {
133 if (base::win::GetVersion() >= base::win::VERSION_VISTA)
134 return;
136 openfilename_.Flags |= OFN_ENABLEHOOK;
137 DCHECK(!openfilename_.lpfnHook);
138 openfilename_.lpfnHook = &SaveAsDialogHook;
141 base::FilePath OpenFileName::GetSingleResult() {
142 base::FilePath directory;
143 std::vector<base::FilePath> filenames;
144 GetResult(&directory, &filenames);
145 if (filenames.size() != 1)
146 return base::FilePath();
147 return directory.Append(filenames[0]);
150 void OpenFileName::GetResult(base::FilePath* directory,
151 std::vector<base::FilePath>* filenames) {
152 DCHECK(filenames->empty());
153 const wchar_t* selection = openfilename_.lpstrFile;
154 while (*selection) { // Empty string indicates end of list.
155 filenames->push_back(base::FilePath(selection));
156 // Skip over filename and null-terminator.
157 selection += filenames->back().value().length() + 1;
159 if (filenames->size() == 1) {
160 // When there is one file, it contains the path and filename.
161 *directory = (*filenames)[0].DirName();
162 (*filenames)[0] = (*filenames)[0].BaseName();
163 } else if (filenames->size() > 1) {
164 // Otherwise, the first string is the path, and the remainder are
165 // filenames.
166 *directory = (*filenames)[0];
167 filenames->erase(filenames->begin());
171 // static
172 void OpenFileName::SetResult(const base::FilePath& directory,
173 const std::vector<base::FilePath>& filenames,
174 OPENFILENAME* openfilename) {
175 base::string16 filename_value;
176 if (filenames.size() == 1) {
177 filename_value = directory.Append(filenames[0]).value();
178 } else {
179 filename_value = directory.value();
180 filename_value.push_back(0);
181 for (std::vector<base::FilePath>::const_iterator it = filenames.begin();
182 it != filenames.end();
183 ++it) {
184 filename_value.append(it->value());
185 filename_value.push_back(0);
188 if (filename_value.size() + 1 < openfilename->nMaxFile) {
189 // Because the result has embedded nulls, we must memcpy.
190 memcpy(openfilename->lpstrFile,
191 filename_value.c_str(),
192 (filename_value.size() + 1) * sizeof(filename_value[0]));
193 } else if (openfilename->nMaxFile) {
194 openfilename->lpstrFile[0] = 0;
198 // static
199 std::vector<Tuple2<base::string16, base::string16> > OpenFileName::GetFilters(
200 const OPENFILENAME* openfilename) {
201 std::vector<Tuple2<base::string16, base::string16> > filters;
203 const base::char16* display_string = openfilename->lpstrFilter;
204 if (!display_string)
205 return filters;
207 while (*display_string) {
208 const base::char16* display_string_end = display_string;
209 while (*display_string_end)
210 ++display_string_end;
211 const base::char16* pattern = display_string_end + 1;
212 const base::char16* pattern_end = pattern;
213 while (*pattern_end)
214 ++pattern_end;
215 filters.push_back(
216 MakeTuple(base::string16(display_string, display_string_end),
217 base::string16(pattern, pattern_end)));
218 display_string = pattern_end + 1;
221 return filters;
224 } // namespace win
225 } // namespace ui