// Copyright (c) 2012 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 <string> #include <vector> #include "ash/session/session_state_delegate.h" #include "ash/shell.h" #include "ash/shell/example_factory.h" #include "ash/shell/toplevel_window.h" #include "ash/shell_delegate.h" #include "base/basictypes.h" #include "base/callback.h" #include "base/files/file_path.h" #include "base/i18n/case_conversion.h" #include "base/i18n/string_search.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "ui/app_list/app_list_item.h" #include "ui/app_list/app_list_item_list.h" #include "ui/app_list/app_list_model.h" #include "ui/app_list/app_list_view_delegate.h" #include "ui/app_list/search_box_model.h" #include "ui/app_list/search_result.h" #include "ui/app_list/speech_ui_model.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font_list.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/examples/examples_window_with_content.h" namespace ash { namespace shell { namespace { // WindowTypeShelfItem is an app item of app list. It carries a window // launch type and launches corresponding example window when activated. class WindowTypeShelfItem : public app_list::AppListItem { public: enum Type { TOPLEVEL_WINDOW = 0, NON_RESIZABLE_WINDOW, LOCK_SCREEN, WIDGETS_WINDOW, EXAMPLES_WINDOW, LAST_TYPE, }; explicit WindowTypeShelfItem(const std::string& id, Type type) : app_list::AppListItem(id), type_(type) { std::string title(GetTitle(type)); SetIcon(GetIcon(type), false); SetName(title); } static gfx::ImageSkia GetIcon(Type type) { static const SkColor kColors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorYELLOW, SK_ColorCYAN, }; const int kIconSize = 128; SkBitmap icon; icon.allocN32Pixels(kIconSize, kIconSize); icon.eraseColor(kColors[static_cast<int>(type) % arraysize(kColors)]); return gfx::ImageSkia::CreateFrom1xBitmap(icon); } // The text below is not localized as this is an example code. static std::string GetTitle(Type type) { switch (type) { case TOPLEVEL_WINDOW: return "Create Window"; case NON_RESIZABLE_WINDOW: return "Create Non-Resizable Window"; case LOCK_SCREEN: return "Lock Screen"; case WIDGETS_WINDOW: return "Show Example Widgets"; case EXAMPLES_WINDOW: return "Open Views Examples Window"; default: return "Unknown window type."; } } // The text below is not localized as this is an example code. static std::string GetDetails(Type type) { // Assigns details only to some types so that we see both one-line // and two-line results. switch (type) { case WIDGETS_WINDOW: return "Creates a window to show example widgets"; case EXAMPLES_WINDOW: return "Creates a window to show views example."; default: return std::string(); } } static void ActivateItem(Type type, int event_flags) { switch (type) { case TOPLEVEL_WINDOW: { ToplevelWindow::CreateParams params; params.can_resize = true; ToplevelWindow::CreateToplevelWindow(params); break; } case NON_RESIZABLE_WINDOW: { ToplevelWindow::CreateToplevelWindow(ToplevelWindow::CreateParams()); break; } case LOCK_SCREEN: { Shell::GetInstance()->session_state_delegate()->LockScreen(); break; } case WIDGETS_WINDOW: { CreateWidgetsWindow(); break; } case EXAMPLES_WINDOW: { views::examples::ShowExamplesWindowWithContent( views::examples::DO_NOTHING_ON_CLOSE, Shell::GetInstance()->delegate()->GetActiveBrowserContext(), NULL); break; } default: break; } } // AppListItem virtual void Activate(int event_flags) OVERRIDE { ActivateItem(type_, event_flags); } private: Type type_; DISALLOW_COPY_AND_ASSIGN(WindowTypeShelfItem); }; // ExampleSearchResult is an app list search result. It provides what icon to // show, what should title and details text look like. It also carries the // matching window launch type so that AppListViewDelegate knows how to open // it. class ExampleSearchResult : public app_list::SearchResult { public: ExampleSearchResult(WindowTypeShelfItem::Type type, const base::string16& query) : type_(type) { SetIcon(WindowTypeShelfItem::GetIcon(type_)); base::string16 title = base::UTF8ToUTF16(WindowTypeShelfItem::GetTitle(type_)); set_title(title); Tags title_tags; const size_t match_len = query.length(); // Highlight matching parts in title with bold. // Note the following is not a proper way to handle i18n string. title = base::i18n::ToLower(title); size_t match_start = title.find(query); while (match_start != base::string16::npos) { title_tags.push_back(Tag(Tag::MATCH, match_start, match_start + match_len)); match_start = title.find(query, match_start + match_len); } set_title_tags(title_tags); base::string16 details = base::UTF8ToUTF16(WindowTypeShelfItem::GetDetails(type_)); set_details(details); Tags details_tags; details_tags.push_back(Tag(Tag::DIM, 0, details.length())); set_details_tags(details_tags); } WindowTypeShelfItem::Type type() const { return type_; } private: WindowTypeShelfItem::Type type_; DISALLOW_COPY_AND_ASSIGN(ExampleSearchResult); }; class ExampleAppListViewDelegate : public app_list::AppListViewDelegate { public: ExampleAppListViewDelegate() : model_(new app_list::AppListModel) { PopulateApps(); DecorateSearchBox(model_->search_box()); } private: void PopulateApps() { for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) { WindowTypeShelfItem::Type type = static_cast<WindowTypeShelfItem::Type>(i); std::string id = base::StringPrintf("%d", i); scoped_ptr<WindowTypeShelfItem> shelf_item( new WindowTypeShelfItem(id, type)); model_->AddItem(shelf_item.PassAs<app_list::AppListItem>()); } } gfx::ImageSkia CreateSearchBoxIcon() { const base::string16 icon_text = base::ASCIIToUTF16("ash"); const gfx::Size icon_size(32, 32); gfx::Canvas canvas(icon_size, 1.0f, false /* is_opaque */); canvas.DrawStringRectWithFlags( icon_text, gfx::FontList(), SK_ColorBLACK, gfx::Rect(icon_size), gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_SUBPIXEL_RENDERING); return gfx::ImageSkia(canvas.ExtractImageRep()); } void DecorateSearchBox(app_list::SearchBoxModel* search_box_model) { search_box_model->SetIcon(CreateSearchBoxIcon()); search_box_model->SetHintText(base::ASCIIToUTF16("Type to search...")); } // Overridden from app_list::AppListViewDelegate: virtual bool ForceNativeDesktop() const OVERRIDE { return false; } virtual void SetProfileByPath(const base::FilePath& profile_path) OVERRIDE { // Nothing needs to be done. } virtual const Users& GetUsers() const OVERRIDE { return users_; } virtual bool ShouldCenterWindow() const OVERRIDE { return false; } virtual app_list::AppListModel* GetModel() OVERRIDE { return model_.get(); } virtual app_list::SpeechUIModel* GetSpeechUI() OVERRIDE { return &speech_ui_; } virtual void GetShortcutPathForApp( const std::string& app_id, const base::Callback<void(const base::FilePath&)>& callback) OVERRIDE { callback.Run(base::FilePath()); } virtual void OpenSearchResult(app_list::SearchResult* result, bool auto_launch, int event_flags) OVERRIDE { const ExampleSearchResult* example_result = static_cast<const ExampleSearchResult*>(result); WindowTypeShelfItem::ActivateItem(example_result->type(), event_flags); } virtual void InvokeSearchResultAction(app_list::SearchResult* result, int action_index, int event_flags) OVERRIDE { NOTIMPLEMENTED(); } virtual base::TimeDelta GetAutoLaunchTimeout() OVERRIDE { return base::TimeDelta(); } virtual void AutoLaunchCanceled() OVERRIDE { } virtual void StartSearch() OVERRIDE { base::string16 query; base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query); query = base::i18n::ToLower(query); model_->results()->DeleteAll(); if (query.empty()) return; for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) { WindowTypeShelfItem::Type type = static_cast<WindowTypeShelfItem::Type>(i); base::string16 title = base::UTF8ToUTF16(WindowTypeShelfItem::GetTitle(type)); if (base::i18n::StringSearchIgnoringCaseAndAccents( query, title, NULL, NULL)) { model_->results()->Add(new ExampleSearchResult(type, query)); } } } virtual void StopSearch() OVERRIDE { // Nothing needs to be done. } virtual void ViewInitialized() OVERRIDE { // Nothing needs to be done. } virtual void Dismiss() OVERRIDE { DCHECK(ash::Shell::HasInstance()); Shell::GetInstance()->DismissAppList(); } virtual void ViewClosing() OVERRIDE { // Nothing needs to be done. } virtual gfx::ImageSkia GetWindowIcon() OVERRIDE { return gfx::ImageSkia(); } virtual void OpenSettings() OVERRIDE { // Nothing needs to be done. } virtual void OpenHelp() OVERRIDE { // Nothing needs to be done. } virtual void OpenFeedback() OVERRIDE { // Nothing needs to be done. } virtual void ToggleSpeechRecognition() OVERRIDE { NOTIMPLEMENTED(); } virtual void ShowForProfileByPath( const base::FilePath& profile_path) OVERRIDE { // Nothing needs to be done. } virtual views::View* CreateStartPageWebView(const gfx::Size& size) OVERRIDE { return NULL; } virtual std::vector<views::View*> CreateCustomPageWebViews( const gfx::Size& size) OVERRIDE { return std::vector<views::View*>(); } virtual bool IsSpeechRecognitionEnabled() OVERRIDE { return false; } scoped_ptr<app_list::AppListModel> model_; app_list::SpeechUIModel speech_ui_; Users users_; DISALLOW_COPY_AND_ASSIGN(ExampleAppListViewDelegate); }; } // namespace app_list::AppListViewDelegate* CreateAppListViewDelegate() { return new ExampleAppListViewDelegate; } } // namespace shell } // namespace ash