summaryrefslogtreecommitdiffstats
path: root/chrome/browser/user_data_manager.cc
diff options
context:
space:
mode:
authormunjal@chromium.org <munjal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-03 23:52:03 +0000
committermunjal@chromium.org <munjal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-12-03 23:52:03 +0000
commitf253006b157f9c917fba21a7312290aaa2e889e7 (patch)
tree377183f9511bed141b5fd7a706c3407a122540d9 /chrome/browser/user_data_manager.cc
parentdadacf06556b4f63a62ec3cea91d7fc5abccd67c (diff)
downloadchromium_src-f253006b157f9c917fba21a7312290aaa2e889e7.zip
chromium_src-f253006b157f9c917fba21a7312290aaa2e889e7.tar.gz
chromium_src-f253006b157f9c917fba21a7312290aaa2e889e7.tar.bz2
Chromium-MultiProfile-Prototype
Summary ======= Implement a prototype of multiple profiles in Chrome by utilizing the functionality of user-data-dir command line flag that already exists. A profile in this case is an umbrella for all user data including cookies, history, bookmarks, settings, etc. Each profile gives the user a separation of all these data elements. User Interface ============== - Wrench > "New window in profile" menu item, with sub-menu items. This new menu item has sub menu items for each existing profile, for up to 9 profiles, and one more sub menu item to launch a window in a new profile. The 9 sub-menu items also have the accelerators like CTRL + SHIFT + 1, CTRL + SHIFT + 2, etc. If there are more than 9 profiles, we will also show an extra sub-menu item, "Other...". - New Profile dialog box This dialog box is shown to the use when (s)he clicks Wrench > New window in profile > <New Profile>. It lets the user specify a profile name, and also shows a checkbox to create a desktop shortcut to launch Chrome in that profile. - Choose profile dialog box This dialog box lets the user select a profile from a drop down to open a new window in. It also has an item <New Profile> in the drop down, selecting which will show the new profile dialog box mentioned above. CTRL + M shortcut also launches this dialog box. Code Organization ================= chrome\browser\user_data_dir_profile_manager.h/.cc: This class provides an abstraction of profiles on top of the user data dir command line flag. chrome\browser\views\user_data_dir_new_profile_dialog.h/.cc New profile dialog box code. chrome\browser\views\user_data_dir_profiles_dialog.h/.cc Choose profile dialog box code. Review URL: http://codereview.chromium.org/12895 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6333 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/user_data_manager.cc')
-rw-r--r--chrome/browser/user_data_manager.cc307
1 files changed, 307 insertions, 0 deletions
diff --git a/chrome/browser/user_data_manager.cc b/chrome/browser/user_data_manager.cc
new file mode 100644
index 0000000..33bdf00
--- /dev/null
+++ b/chrome/browser/user_data_manager.cc
@@ -0,0 +1,307 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/user_data_manager.h"
+
+#include <windows.h>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "chrome/browser/chrome_thread.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/l10n_util.h"
+#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/shell_util.h"
+
+#include "chromium_strings.h"
+
+namespace {
+
+// Helper to start chrome for a given profile index. The helper takes care of
+// enumerating profiles on the file thread and then it launches Chrome for the
+// appropriate profile on the original thread.
+// An instance of this class should always be created on the heap, and it will
+// delete itself when the launch is done.
+class LaunchChromeForProfileIndexHelper : GetProfilesHelper::Delegate {
+ public:
+ // Creates an instance with the given data manager and to launch chrome for
+ // the profile with the given index.
+ LaunchChromeForProfileIndexHelper(const UserDataManager* manager, int index);
+ virtual ~LaunchChromeForProfileIndexHelper();
+
+ // Starts the asynchronous launch.
+ void StartLaunch();
+
+ // GetProfilesHelper::Delegate method.
+ void OnGetProfilesDone(const std::vector<std::wstring>& profiles);
+
+ private:
+ int index_;
+ const UserDataManager* manager_;
+ scoped_refptr<GetProfilesHelper> profiles_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(LaunchChromeForProfileIndexHelper);
+};
+
+} // namespace
+
+LaunchChromeForProfileIndexHelper::LaunchChromeForProfileIndexHelper(
+ const UserDataManager* manager,
+ int index)
+ : manager_(manager),
+ index_(index),
+// Don't complain about using "this" in initializer list.
+MSVC_PUSH_DISABLE_WARNING(4355)
+ profiles_helper_(new GetProfilesHelper(this)) {
+MSVC_POP_WARNING()
+ DCHECK(manager);
+}
+
+LaunchChromeForProfileIndexHelper::~LaunchChromeForProfileIndexHelper() {
+ profiles_helper_->OnDelegateDeleted();
+}
+
+void LaunchChromeForProfileIndexHelper::StartLaunch() {
+ profiles_helper_->GetProfiles(NULL);
+}
+
+void LaunchChromeForProfileIndexHelper::OnGetProfilesDone(
+ const std::vector<std::wstring>& profiles) {
+ if (index_ >= 0 && index_ < static_cast<int>(profiles.size()))
+ manager_->LaunchChromeForProfile(profiles[index_]);
+
+ // We are done, delete ourselves.
+ delete this;
+}
+
+// Separator used in folder names between the prefix and the profile name.
+// For e.g. a folder for the profile "Joe" would be named "User Data-Joe".
+static const wchar_t kProfileFolderSeparator[] = L"-";
+
+// static
+UserDataManager* UserDataManager::instance_ = NULL;
+
+// static
+void UserDataManager::Create() {
+ DCHECK(!instance_);
+ std::wstring user_data;
+ PathService::Get(chrome::DIR_USER_DATA, &user_data);
+ instance_ = new UserDataManager(user_data);
+}
+
+// static
+UserDataManager* UserDataManager::Get() {
+ DCHECK(instance_);
+ return instance_;
+}
+
+UserDataManager::UserDataManager(const std::wstring& user_data_root)
+ : user_data_root_(user_data_root) {
+ // Determine current profile name and current folder name.
+ current_folder_name_ = file_util::GetFilenameFromPath(user_data_root);
+ bool success = GetProfileNameFromFolderName(current_folder_name_,
+ &current_profile_name_);
+ // The current profile is a default profile if the current user data folder
+ // name is just kUserDataDirname or when the folder name doesn't have the
+ // kUserDataDirname as prefix.
+ is_current_profile_default_ =
+ !success || (current_folder_name_ == chrome::kUserDataDirname);
+
+ // (TODO:munjal) Fix issue 5070:
+ // http://code.google.com/p/chromium/issues/detail?id=5070
+
+ file_util::UpOneDirectory(&user_data_root_);
+}
+
+UserDataManager::~UserDataManager() {
+}
+
+// static
+bool UserDataManager::GetProfileNameFromFolderName(
+ const std::wstring& folder_name,
+ std::wstring* profile_name) {
+ // The folder name should start with a specific prefix for it to be a valid
+ // profile folder.
+ if (folder_name.find(chrome::kUserDataDirname) != 0)
+ return false;
+
+ // Seems like we cannot use arraysize macro for externally defined constants.
+ // Is there a way?
+ unsigned int prefix_length = wcslen(chrome::kUserDataDirname);
+ // Subtract 1 from the size of the array for trailing null character.
+ unsigned int separator_length = arraysize(kProfileFolderSeparator) - 1;
+
+ // It's safe to use profile_name variable for intermediate values since we
+ // will always return true now.
+ *profile_name = folder_name.substr(prefix_length);
+ // Remove leading separator if present.
+ if (profile_name->find_first_of(kProfileFolderSeparator) == 0)
+ *profile_name = profile_name->substr(separator_length);
+
+ if (profile_name->empty())
+ *profile_name = chrome::kNotSignedInProfile;
+
+ return true;
+}
+
+// static
+std::wstring UserDataManager::GetFolderNameFromProfileName(
+ const std::wstring& profile_name) {
+ std::wstring folder_name = chrome::kUserDataDirname;
+ if (profile_name != chrome::kNotSignedInProfile) {
+ folder_name += kProfileFolderSeparator;
+ folder_name += profile_name;
+ }
+ return folder_name;
+}
+
+std::wstring UserDataManager::GetUserDataFolderForProfile(
+ const std::wstring& profile_name) const {
+ std::wstring folder_name = GetFolderNameFromProfileName(profile_name);
+ std::wstring folder_path(user_data_root_);
+ file_util::AppendToPath(&folder_path, folder_name);
+ return folder_path;
+}
+
+std::wstring UserDataManager::GetCommandForProfile(
+ const std::wstring& profile_name) const {
+ std::wstring user_data_dir = GetUserDataFolderForProfile(profile_name);
+ std::wstring command;
+ PathService::Get(base::FILE_EXE, &command);
+ CommandLine::AppendSwitchWithValue(&command,
+ switches::kUserDataDir,
+ user_data_dir);
+ std::wstring local_state_path;
+ PathService::Get(chrome::FILE_LOCAL_STATE, &local_state_path);
+ CommandLine::AppendSwitchWithValue(&command,
+ switches::kParentProfile,
+ local_state_path);
+ return command;
+}
+
+void UserDataManager::LaunchChromeForProfile(
+ const std::wstring& profile_name) const {
+ std::wstring command = GetCommandForProfile(profile_name);
+ base::LaunchApp(command, false, false, NULL);
+}
+
+void UserDataManager::LaunchChromeForProfile(int index) const {
+ // Helper deletes itself when done.
+ LaunchChromeForProfileIndexHelper* helper =
+ new LaunchChromeForProfileIndexHelper(this, index);
+ helper->StartLaunch();
+}
+
+void UserDataManager::GetProfiles(std::vector<std::wstring>* profiles) const {
+ // This function should be called on the file thread.
+ DCHECK(MessageLoop::current() ==
+ ChromeThread::GetMessageLoop(ChromeThread::FILE));
+ file_util::FileEnumerator file_enum(user_data_root_,
+ false,
+ file_util::FileEnumerator::DIRECTORIES);
+ std::wstring folder_name;
+ while (!(folder_name = file_enum.Next()).empty()) {
+ folder_name = file_util::GetFilenameFromPath(folder_name);
+ std::wstring profile_name;
+ if (GetProfileNameFromFolderName(folder_name, &profile_name))
+ profiles->push_back(profile_name);
+ }
+}
+
+bool UserDataManager::CreateDesktopShortcutForProfile(
+ const std::wstring& profile_name) const {
+ std::wstring exe_path;
+ std::wstring shortcut_path;
+ if (!PathService::Get(base::FILE_EXE, &exe_path) ||
+ !ShellUtil::GetDesktopPath(false, &shortcut_path))
+ return false;
+
+ // Working directory.
+ std::wstring exe_folder = file_util::GetDirectoryFromPath(exe_path);
+
+ // Command and arguments.
+ std::wstring cmd;
+ cmd = StringPrintf(L"\"%ls\"", exe_path.c_str());
+ std::wstring user_data_dir = GetUserDataFolderForProfile(profile_name);
+ std::wstring args = CommandLine::PrefixedSwitchStringWithValue(
+ switches::kUserDataDir,
+ user_data_dir);
+ args = StringPrintf(L"\"%ls\"", args.c_str());
+
+ // Shortcut path.
+ std::wstring shortcut_name = l10n_util::GetStringF(
+ IDS_START_IN_PROFILE_SHORTCUT_NAME,
+ profile_name);
+ shortcut_name.append(L".lnk");
+ file_util::AppendToPath(&shortcut_path, shortcut_name);
+
+ return file_util::CreateShortcutLink(cmd.c_str(),
+ shortcut_path.c_str(),
+ exe_folder.c_str(),
+ args.c_str(),
+ NULL,
+ exe_path.c_str(),
+ 0);
+}
+
+GetProfilesHelper::GetProfilesHelper(Delegate* delegate)
+ : delegate_(delegate) {
+}
+
+void GetProfilesHelper::GetProfiles(MessageLoop* target_loop) {
+ // If the target loop is not NULL then use the target loop, or if it's NULL
+ // then use the current message loop to post a task on it later when we are
+ // done building a list of profiles.
+ if (target_loop) {
+ message_loop_ = target_loop;
+ } else {
+ message_loop_ = MessageLoop::current();
+ }
+ DCHECK(message_loop_);
+ MessageLoop* file_loop = ChromeThread::GetMessageLoop(ChromeThread::FILE);
+ file_loop->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &GetProfilesHelper::GetProfilesFromManager));
+}
+
+// Records that the delegate is closed.
+void GetProfilesHelper::OnDelegateDeleted() {
+ delegate_ = NULL;
+}
+
+void GetProfilesHelper::GetProfilesFromManager() {
+ // This function should be called on the file thread.
+ DCHECK(MessageLoop::current() ==
+ ChromeThread::GetMessageLoop(ChromeThread::FILE));
+
+ // If the delegate is gone by now, no need to do any work.
+ if (!delegate_)
+ return;
+
+ scoped_ptr< std::vector<std::wstring> > profiles(
+ new std::vector<std::wstring>);
+ UserDataManager::Get()->GetProfiles(profiles.get());
+
+ // Post a task on the original thread to call the delegate.
+ message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &GetProfilesHelper::InvokeDelegate,
+ profiles.release()));
+}
+
+void GetProfilesHelper::InvokeDelegate(std::vector<std::wstring>* profiles) {
+ scoped_ptr< std::vector<std::wstring> > udd_profiles(profiles);
+ // If the delegate is gone by now, no need to do any work.
+ if (delegate_)
+ delegate_->OnGetProfilesDone(*udd_profiles.get());
+}