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

Side by Side Diff: chrome/browser/ui/views/select_file_dialog_win.cc

Issue 9203001: Implement input type=color UI (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: added content::ColorChooser Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/select_file_dialog.h" 5 #include "chrome/browser/ui/select_file_dialog.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <commdlg.h> 8 #include <commdlg.h>
9 #include <shlobj.h> 9 #include <shlobj.h>
10 10
11 #include <algorithm> 11 #include <algorithm>
12 #include <set> 12 #include <set>
13 13
14 #include "base/bind.h" 14 #include "base/bind.h"
15 #include "base/file_path.h" 15 #include "base/file_path.h"
16 #include "base/file_util.h" 16 #include "base/file_util.h"
17 #include "base/i18n/case_conversion.h" 17 #include "base/i18n/case_conversion.h"
18 #include "base/message_loop.h" 18 #include "base/message_loop.h"
19 #include "base/string_split.h" 19 #include "base/string_split.h"
20 #include "base/threading/thread.h" 20 #include "base/threading/thread.h"
21 #include "base/utf_string_conversions.h" 21 #include "base/utf_string_conversions.h"
22 #include "base/win/registry.h" 22 #include "base/win/registry.h"
23 #include "base/win/scoped_comptr.h" 23 #include "base/win/scoped_comptr.h"
24 #include "base/win/windows_version.h" 24 #include "base/win/windows_version.h"
25 #include "chrome/browser/ui/views/base_shell_dialog_win.h"
25 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/browser_thread.h"
26 #include "grit/generated_resources.h" 27 #include "grit/generated_resources.h"
27 #include "grit/ui_strings.h" 28 #include "grit/ui_strings.h"
28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
29 30
30 using content::BrowserThread; 31 using content::BrowserThread;
31 32
32 // This function takes the output of a SaveAs dialog: a filename, a filter and 33 // This function takes the output of a SaveAs dialog: a filename, a filter and
33 // the extension originally suggested to the user (shown in the dialog box) and 34 // the extension originally suggested to the user (shown in the dialog box) and
34 // returns back the filename with the appropriate extension tacked on. If the 35 // returns back the filename with the appropriate extension tacked on. If the
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 suggested_name, 371 suggested_name,
371 filter, 372 filter,
372 L"", 373 L"",
373 false, 374 false,
374 &index, 375 &index,
375 final_name); 376 final_name);
376 } 377 }
377 378
378 } // namespace 379 } // namespace
379 380
380 // Helpers to show certain types of Windows shell dialogs in a way that doesn't
381 // block the UI of the entire app.
382
383 class ShellDialogThread : public base::Thread {
384 public:
385 ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { }
386 ~ShellDialogThread() {
387 Stop();
388 }
389
390 protected:
391 void Init() {
392 // Initializes the COM library on the current thread.
393 CoInitialize(NULL);
394 }
395
396 void CleanUp() {
397 // Closes the COM library on the current thread. CoInitialize must
398 // be balanced by a corresponding call to CoUninitialize.
399 CoUninitialize();
400 }
401
402 private:
403 DISALLOW_COPY_AND_ASSIGN(ShellDialogThread);
404 };
405
406 ///////////////////////////////////////////////////////////////////////////////
407 // A base class for all shell dialog implementations that handles showing a
408 // shell dialog modally on its own thread.
409 class BaseShellDialogImpl {
410 public:
411 BaseShellDialogImpl();
412 virtual ~BaseShellDialogImpl();
413
414 protected:
415 // Represents a run of a dialog.
416 struct RunState {
417 // Owning HWND, may be null.
418 HWND owner;
419
420 // Thread dialog is run on.
421 base::Thread* dialog_thread;
422 };
423
424 // Called at the beginning of a modal dialog run. Disables the owner window
425 // and tracks it. Returns the message loop of the thread that the dialog will
426 // be run on.
427 RunState BeginRun(HWND owner);
428
429 // Cleans up after a dialog run. If the run_state has a valid HWND this makes
430 // sure that the window is enabled. This is essential because BeginRun
431 // aggressively guards against multiple modal dialogs per HWND. Must be called
432 // on the UI thread after the result of the dialog has been determined.
433 //
434 // In addition this deletes the Thread in RunState.
435 void EndRun(RunState run_state);
436
437 // Returns true if a modal shell dialog is currently active for the specified
438 // owner. Must be called on the UI thread.
439 bool IsRunningDialogForOwner(HWND owner) const;
440
441 // Disables the window |owner|. Can be run from either the ui or the dialog
442 // thread. Can be called on either the UI or the dialog thread. This function
443 // is called on the dialog thread after the modal Windows Common dialog
444 // functions return because Windows automatically re-enables the owning
445 // window when those functions return, but we don't actually want them to be
446 // re-enabled until the response of the dialog propagates back to the UI
447 // thread, so we disable the owner manually after the Common dialog function
448 // returns.
449 void DisableOwner(HWND owner);
450
451 private:
452 // Creates a thread to run a shell dialog on. Each dialog requires its own
453 // thread otherwise in some situations where a singleton owns a single
454 // instance of this object we can have a situation where a modal dialog in
455 // one window blocks the appearance of a modal dialog in another.
456 static base::Thread* CreateDialogThread();
457
458 // Enables the window |owner_|. Can only be run from the ui thread.
459 void EnableOwner(HWND owner);
460
461 // A list of windows that currently own active shell dialogs for this
462 // instance. For example, if the DownloadManager owns an instance of this
463 // object and there are two browser windows open both with Save As dialog
464 // boxes active, this list will consist of the two browser windows' HWNDs.
465 // The derived class must call EndRun once the dialog is done showing to
466 // remove the owning HWND from this list.
467 // This object is static since it is maintained for all instances of this
468 // object - i.e. you can't have two file pickers open for the
469 // same owner, even though they might be represented by different instances
470 // of this object.
471 // This set only contains non-null HWNDs. NULL hwnds are not added to this
472 // list.
473 typedef std::set<HWND> Owners;
474 static Owners owners_;
475 static int instance_count_;
476
477 DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl);
478 };
479
480 // static
481 BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_;
482 int BaseShellDialogImpl::instance_count_ = 0;
483
484 BaseShellDialogImpl::BaseShellDialogImpl() {
485 ++instance_count_;
486 }
487
488 BaseShellDialogImpl::~BaseShellDialogImpl() {
489 // All runs should be complete by the time this is called!
490 if (--instance_count_ == 0)
491 DCHECK(owners_.empty());
492 }
493
494 BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
495 // Cannot run a modal shell dialog if one is already running for this owner.
496 DCHECK(!IsRunningDialogForOwner(owner));
497 // The owner must be a top level window, otherwise we could end up with two
498 // entries in our map for the same top level window.
499 DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
500 RunState run_state;
501 run_state.dialog_thread = CreateDialogThread();
502 run_state.owner = owner;
503 if (owner) {
504 owners_.insert(owner);
505 DisableOwner(owner);
506 }
507 return run_state;
508 }
509
510 void BaseShellDialogImpl::EndRun(RunState run_state) {
511 if (run_state.owner) {
512 DCHECK(IsRunningDialogForOwner(run_state.owner));
513 EnableOwner(run_state.owner);
514 DCHECK(owners_.find(run_state.owner) != owners_.end());
515 owners_.erase(run_state.owner);
516 }
517 DCHECK(run_state.dialog_thread);
518 delete run_state.dialog_thread;
519 }
520
521 bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
522 return (owner && owners_.find(owner) != owners_.end());
523 }
524
525 void BaseShellDialogImpl::DisableOwner(HWND owner) {
526 if (IsWindow(owner))
527 EnableWindow(owner, FALSE);
528 }
529
530 // static
531 base::Thread* BaseShellDialogImpl::CreateDialogThread() {
532 base::Thread* thread = new ShellDialogThread;
533 bool started = thread->Start();
534 DCHECK(started);
535 return thread;
536 }
537
538 void BaseShellDialogImpl::EnableOwner(HWND owner) {
539 if (IsWindow(owner))
540 EnableWindow(owner, TRUE);
541 }
542
543 // Implementation of SelectFileDialog that shows a Windows common dialog for 381 // Implementation of SelectFileDialog that shows a Windows common dialog for
544 // choosing a file or folder. 382 // choosing a file or folder.
545 class SelectFileDialogImpl : public SelectFileDialog, 383 class SelectFileDialogImpl : public SelectFileDialog,
546 public BaseShellDialogImpl { 384 public BaseShellDialogImpl {
547 public: 385 public:
548 explicit SelectFileDialogImpl(Listener* listener); 386 explicit SelectFileDialogImpl(Listener* listener);
549 387
550 // BaseShellDialog implementation: 388 // BaseShellDialog implementation:
551 virtual bool IsRunning(HWND owning_hwnd) const OVERRIDE; 389 virtual bool IsRunning(HWND owning_hwnd) const OVERRIDE;
552 virtual void ListenerDestroyed() OVERRIDE; 390 virtual void ListenerDestroyed() OVERRIDE;
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 } 794 }
957 } 795 }
958 } 796 }
959 return success; 797 return success;
960 } 798 }
961 799
962 // static 800 // static
963 SelectFileDialog* SelectFileDialog::Create(Listener* listener) { 801 SelectFileDialog* SelectFileDialog::Create(Listener* listener) {
964 return new SelectFileDialogImpl(listener); 802 return new SelectFileDialogImpl(listener);
965 } 803 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698