Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/views/about_network_dialog.h" | |
| 6 | |
| 7 #include "base/string_util.h" | |
| 8 #include "base/thread.h" | |
| 9 #include "chrome/browser/browser_process.h" | |
| 10 #include "chrome/browser/views/standard_layout.h" | |
| 11 #include "chrome/views/grid_layout.h" | |
| 12 #include "chrome/views/text_button.h" | |
| 13 #include "chrome/views/text_field.h" | |
| 14 #include "chrome/views/window.h" | |
| 15 #include "net/url_request/url_request.h" | |
| 16 #include "net/url_request/url_request_job.h" | |
| 17 #include "net/url_request/url_request_job_tracker.h" | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 // We don't localize this UI since this is a developer-only feature. | |
| 22 const wchar_t kStartTrackingLabel[] = L"Start tracking"; | |
| 23 const wchar_t kStopTrackingLabel[] = L"Stop tracking"; | |
| 24 const wchar_t KShowCurrentLabel[] = L"Show Current"; | |
|
Ben Goodger (Google)
2009/01/23 23:24:24
K?
| |
| 25 const wchar_t kClearLabel[] = L"Clear"; | |
| 26 | |
| 27 // The singleton dialog box. This is non-NULL when a dialog is active so we | |
| 28 // know not to create a new one. | |
| 29 AboutNetworkDialog* active_dialog = NULL; | |
| 30 | |
| 31 // Returns a string representing the URL, handling the case where the spec | |
| 32 // is invalid. | |
| 33 std::wstring StringForURL(const GURL& url) { | |
| 34 if (url.is_valid()) | |
| 35 return UTF8ToWide(url.spec()); | |
| 36 return UTF8ToWide(url.possibly_invalid_spec()) + L" (invalid)"; | |
| 37 } | |
| 38 | |
| 39 std::wstring URLForJob(URLRequestJob* job) { | |
| 40 URLRequest* request = job->request(); | |
| 41 if (request) | |
| 42 return StringForURL(request->url()); | |
| 43 return std::wstring(L"(orphaned)"); | |
| 44 } | |
| 45 | |
| 46 // JobTracker ------------------------------------------------------------------ | |
| 47 | |
| 48 // A JobTracker is allocated to monitor network jobs running on the IO | |
| 49 // thread. This allows the NetworkStatusView to remain single-threaded. | |
| 50 class JobTracker : public URLRequestJobTracker::JobObserver, | |
| 51 public base::RefCountedThreadSafe<JobTracker> { | |
| 52 public: | |
| 53 JobTracker(AboutNetworkDialog* view); | |
| 54 ~JobTracker(); | |
| 55 | |
| 56 // Called by the NetworkStatusView on the main application thread. | |
| 57 void StartTracking(); | |
| 58 void StopTracking(); | |
| 59 void ReportStatus(); | |
| 60 | |
| 61 // URLRequestJobTracker::JobObserver methods (called on the IO thread): | |
| 62 virtual void OnJobAdded(URLRequestJob* job); | |
| 63 virtual void OnJobRemoved(URLRequestJob* job); | |
| 64 virtual void OnJobDone(URLRequestJob* job, const URLRequestStatus& status); | |
| 65 virtual void OnJobRedirect(URLRequestJob* job, const GURL& location, | |
| 66 int status_code); | |
| 67 virtual void OnBytesRead(URLRequestJob* job, int byte_count); | |
| 68 | |
| 69 // The JobTracker may be deleted after NetworkStatusView is deleted. | |
| 70 void DetachView() { view_ = NULL; } | |
| 71 | |
| 72 private: | |
| 73 void InvokeOnIOThread(void (JobTracker::*method)()); | |
| 74 | |
| 75 // Called on the IO thread | |
| 76 void OnStartTracking(); | |
| 77 void OnStopTracking(); | |
| 78 void OnReportStatus(); | |
| 79 void AppendText(const std::wstring& text); | |
| 80 | |
| 81 // Called on the main thread | |
| 82 void OnAppendText(const std::wstring& text); | |
| 83 | |
| 84 AboutNetworkDialog* view_; | |
| 85 MessageLoop* view_message_loop_; | |
| 86 }; | |
| 87 | |
| 88 // main thread: | |
| 89 JobTracker::JobTracker(AboutNetworkDialog* view) | |
| 90 : view_(view), | |
| 91 view_message_loop_(MessageLoop::current()) { | |
| 92 } | |
| 93 | |
| 94 JobTracker::~JobTracker() { | |
| 95 } | |
| 96 | |
| 97 // main thread: | |
| 98 void JobTracker::InvokeOnIOThread(void (JobTracker::*m)()) { | |
| 99 base::Thread* thread = g_browser_process->io_thread(); | |
| 100 if (!thread) | |
| 101 return; | |
| 102 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, m)); | |
| 103 } | |
| 104 | |
| 105 // main thread: | |
| 106 void JobTracker::StartTracking() { | |
| 107 DCHECK(MessageLoop::current() == view_message_loop_); | |
| 108 DCHECK(view_); | |
| 109 InvokeOnIOThread(&JobTracker::OnStartTracking); | |
| 110 } | |
| 111 | |
| 112 // main thread: | |
| 113 void JobTracker::StopTracking() { | |
| 114 DCHECK(MessageLoop::current() == view_message_loop_); | |
| 115 // The tracker should not be deleted before it is removed from observer | |
| 116 // list. | |
| 117 AddRef(); | |
| 118 InvokeOnIOThread(&JobTracker::OnStopTracking); | |
| 119 } | |
| 120 | |
| 121 // main thread: | |
| 122 void JobTracker::ReportStatus() { | |
| 123 DCHECK(MessageLoop::current() == view_message_loop_); | |
| 124 InvokeOnIOThread(&JobTracker::OnReportStatus); | |
| 125 } | |
| 126 | |
| 127 // main thread: | |
| 128 void JobTracker::OnAppendText(const std::wstring& text) { | |
| 129 DCHECK(MessageLoop::current() == view_message_loop_); | |
| 130 if (view_ && view_->tracking()) | |
| 131 view_->AppendText(text); | |
| 132 } | |
| 133 | |
| 134 // IO thread: | |
| 135 void JobTracker::AppendText(const std::wstring& text) { | |
| 136 DCHECK(MessageLoop::current() != view_message_loop_); | |
| 137 view_message_loop_->PostTask(FROM_HERE, NewRunnableMethod( | |
| 138 this, &JobTracker::OnAppendText, text)); | |
| 139 } | |
| 140 | |
| 141 // IO thread: | |
| 142 void JobTracker::OnStartTracking() { | |
| 143 DCHECK(MessageLoop::current() != view_message_loop_); | |
| 144 g_url_request_job_tracker.AddObserver(this); | |
| 145 } | |
| 146 | |
| 147 // IO thread: | |
| 148 void JobTracker::OnStopTracking() { | |
| 149 DCHECK(MessageLoop::current() != view_message_loop_); | |
| 150 g_url_request_job_tracker.RemoveObserver(this); | |
| 151 // Balance the AddRef() in StopTracking() called in main thread. | |
| 152 Release(); | |
| 153 } | |
| 154 | |
| 155 // IO thread: | |
| 156 void JobTracker::OnReportStatus() { | |
| 157 DCHECK(MessageLoop::current() != view_message_loop_); | |
| 158 | |
| 159 std::wstring text(L"\r\n===== Active Job Summary =====\r\n"); | |
| 160 | |
| 161 URLRequestJobTracker::JobIterator begin_job = | |
| 162 g_url_request_job_tracker.begin(); | |
| 163 URLRequestJobTracker::JobIterator end_job = g_url_request_job_tracker.end(); | |
| 164 int orphaned_count = 0; | |
| 165 int regular_count = 0; | |
| 166 for (URLRequestJobTracker::JobIterator cur = begin_job; | |
| 167 cur != end_job; ++cur) { | |
| 168 URLRequestJob* job = (*cur); | |
| 169 URLRequest* request = job->request(); | |
| 170 if (!request) { | |
| 171 orphaned_count++; | |
| 172 continue; | |
| 173 } | |
| 174 | |
| 175 regular_count++; | |
| 176 | |
| 177 // active state | |
| 178 if (job->is_done()) | |
| 179 text.append(L" Done: "); | |
| 180 else | |
| 181 text.append(L" Active: "); | |
| 182 | |
| 183 // URL | |
| 184 text.append(StringForURL(request->url())); | |
| 185 text.append(L"\r\n"); | |
| 186 } | |
| 187 | |
| 188 if (regular_count == 0) | |
| 189 text.append(L" (No active jobs)\r\n"); | |
| 190 | |
| 191 if (orphaned_count) { | |
| 192 wchar_t buf[64]; | |
| 193 swprintf(buf, arraysize(buf), L" %d orphaned jobs\r\n", orphaned_count); | |
| 194 text.append(buf); | |
| 195 } | |
| 196 | |
| 197 text.append(L"=====\r\n\r\n"); | |
| 198 AppendText(text); | |
| 199 } | |
| 200 | |
| 201 // IO thread: | |
| 202 void JobTracker::OnJobAdded(URLRequestJob* job) { | |
| 203 DCHECK(MessageLoop::current() != view_message_loop_); | |
| 204 | |
| 205 std::wstring text(L"+ New job : "); | |
| 206 text.append(URLForJob(job)); | |
| 207 text.append(L"\r\n"); | |
| 208 AppendText(text); | |
| 209 } | |
| 210 | |
| 211 // IO thread: | |
| 212 void JobTracker::OnJobRemoved(URLRequestJob* job) { | |
| 213 DCHECK(MessageLoop::current() != view_message_loop_); | |
| 214 } | |
| 215 | |
| 216 // IO thread: | |
| 217 void JobTracker::OnJobDone(URLRequestJob* job, | |
| 218 const URLRequestStatus& status) { | |
| 219 DCHECK(MessageLoop::current() != view_message_loop_); | |
| 220 | |
| 221 std::wstring text; | |
| 222 if (status.is_success()) { | |
| 223 text.assign(L"- Complete: "); | |
| 224 } else if (status.status() == URLRequestStatus::CANCELED) { | |
| 225 text.assign(L"- Canceled: "); | |
| 226 } else if (status.status() == URLRequestStatus::HANDLED_EXTERNALLY) { | |
| 227 text.assign(L"- Handled externally: "); | |
| 228 } else { | |
| 229 wchar_t buf[32]; | |
| 230 swprintf(buf, arraysize(buf), L"Failed with %d: ", status.os_error()); | |
| 231 text.assign(buf); | |
| 232 } | |
| 233 | |
| 234 text.append(URLForJob(job)); | |
| 235 text.append(L"\r\n"); | |
| 236 AppendText(text); | |
| 237 } | |
| 238 | |
| 239 // IO thread: | |
| 240 void JobTracker::OnJobRedirect(URLRequestJob* job, | |
| 241 const GURL& location, | |
| 242 int status_code) { | |
| 243 DCHECK(MessageLoop::current() != view_message_loop_); | |
| 244 | |
| 245 std::wstring text(L"- Redirect: "); | |
| 246 text.append(URLForJob(job)); | |
| 247 text.append(L"\r\n "); | |
| 248 | |
| 249 wchar_t buf[16]; | |
| 250 swprintf(buf, arraysize(buf), L"(%d) to: ", status_code); | |
| 251 text.append(buf); | |
| 252 | |
| 253 text.append(StringForURL(location)); | |
| 254 text.append(L"\r\n"); | |
| 255 AppendText(text); | |
| 256 } | |
| 257 | |
| 258 void JobTracker::OnBytesRead(URLRequestJob* job, int byte_count) { | |
| 259 } | |
| 260 | |
| 261 // The singleton job tracker associated with the dialog. | |
| 262 JobTracker* tracker = NULL; | |
| 263 | |
| 264 } // namespace | |
| 265 | |
| 266 // AboutNetworkDialog ---------------------------------------------------------- | |
| 267 | |
| 268 AboutNetworkDialog::AboutNetworkDialog() : tracking_(false) { | |
| 269 SetupControls(); | |
| 270 tracker = new JobTracker(this); | |
| 271 tracker->AddRef(); | |
| 272 } | |
| 273 | |
| 274 AboutNetworkDialog::~AboutNetworkDialog() { | |
| 275 active_dialog = NULL; | |
| 276 tracker->Release(); | |
| 277 tracker = NULL; | |
| 278 } | |
| 279 | |
| 280 // static | |
| 281 void AboutNetworkDialog::RunDialog() { | |
| 282 if (!active_dialog) { | |
| 283 active_dialog = new AboutNetworkDialog; | |
| 284 views::Window::CreateChromeWindow(NULL, gfx::Rect(), active_dialog)->Show(); | |
| 285 } else { | |
| 286 // TOOD(brettw) it would be nice to focus the existing window. | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 void AboutNetworkDialog::AppendText(const std::wstring& text) { | |
| 291 text_field_->AppendText(text); | |
| 292 } | |
| 293 | |
| 294 void AboutNetworkDialog::SetupControls() { | |
| 295 views::GridLayout* layout = CreatePanelGridLayout(this); | |
| 296 SetLayoutManager(layout); | |
| 297 | |
| 298 track_toggle_ = new views::TextButton(kStartTrackingLabel); | |
| 299 track_toggle_->SetListener(this, 1); | |
| 300 show_button_ = new views::TextButton(KShowCurrentLabel); | |
| 301 show_button_->SetListener(this, 2); | |
| 302 clear_button_ = new views::TextButton(kClearLabel); | |
| 303 clear_button_->SetListener(this, 3); | |
| 304 | |
| 305 text_field_ = new views::TextField(static_cast<views::TextField::StyleFlags>( | |
| 306 views::TextField::STYLE_MULTILINE)); | |
| 307 text_field_->SetReadOnly(true); | |
| 308 | |
| 309 // TODO(brettw): We may want to add this in the future. It can't be called | |
| 310 // from here, though, since the hwnd for the field hasn't been created yet. | |
| 311 // | |
| 312 // This raises the maximum number of chars from 32K to some large maximum, | |
| 313 // probably 2GB. 32K is not nearly enough for our use-case. | |
| 314 //SendMessageW(text_field_->GetNativeComponent(), EM_SETLIMITTEXT, 0, 0); | |
| 315 | |
| 316 static const int first_column_set = 1; | |
| 317 views::ColumnSet* column_set = layout->AddColumnSet(first_column_set); | |
| 318 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, | |
| 319 33.33f, views::GridLayout::FIXED, 0, 0); | |
| 320 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, | |
| 321 33.33f, views::GridLayout::FIXED, 0, 0); | |
| 322 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, | |
| 323 33.33f, views::GridLayout::FIXED, 0, 0); | |
| 324 | |
| 325 static const int text_column_set = 2; | |
| 326 column_set = layout->AddColumnSet(text_column_set); | |
| 327 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 100.0f , | |
| 328 views::GridLayout::FIXED, 0, 0); | |
| 329 | |
| 330 layout->StartRow(0, first_column_set); | |
| 331 layout->AddView(track_toggle_); | |
| 332 layout->AddView(show_button_); | |
| 333 layout->AddView(clear_button_); | |
| 334 layout->AddPaddingRow(0, kRelatedControlVerticalSpacing); | |
| 335 layout->StartRow(1.0f, text_column_set); | |
| 336 layout->AddView(text_field_); | |
| 337 } | |
| 338 | |
| 339 gfx::Size AboutNetworkDialog::GetPreferredSize() { | |
| 340 return gfx::Size(800, 400); | |
| 341 } | |
| 342 | |
| 343 views::View* AboutNetworkDialog::GetContentsView() { | |
| 344 return this; | |
| 345 } | |
| 346 | |
| 347 int AboutNetworkDialog::GetDialogButtons() const { | |
| 348 // Don't want OK or Cancel. | |
| 349 return 0; | |
| 350 } | |
| 351 | |
| 352 std::wstring AboutNetworkDialog::GetWindowTitle() const { | |
| 353 return L"about:network"; | |
| 354 } | |
| 355 | |
| 356 void AboutNetworkDialog::Layout() { | |
| 357 GetLayoutManager()->Layout(this); | |
| 358 } | |
| 359 | |
| 360 bool AboutNetworkDialog::CanResize() const { | |
| 361 return true; | |
| 362 } | |
| 363 | |
| 364 void AboutNetworkDialog::ButtonPressed(views::BaseButton* button) { | |
| 365 if (button == track_toggle_) { | |
| 366 if (tracking_) { | |
| 367 track_toggle_->SetText(kStartTrackingLabel); | |
| 368 tracking_ = false; | |
| 369 tracker->StopTracking(); | |
| 370 } else { | |
| 371 track_toggle_->SetText(kStopTrackingLabel); | |
| 372 tracking_ = true; | |
| 373 tracker->StartTracking(); | |
| 374 } | |
| 375 track_toggle_->SchedulePaint(); | |
| 376 } else if (button == show_button_) { | |
| 377 tracker->ReportStatus(); | |
| 378 } else if (button == clear_button_) { | |
| 379 text_field_->SetText(std::wstring()); | |
| 380 } | |
| 381 } | |
| OLD | NEW |