app_list.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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 3// found in the LICENSE file. 4 5#include <string> 6 7#include "ash/session/session_state_delegate.h" 8#include "ash/shell.h" 9#include "ash/shell/example_factory.h" 10#include "ash/shell/toplevel_window.h" 11#include "ash/shell_delegate.h" 12#include "base/basictypes.h" 13#include "base/callback.h" 14#include "base/files/file_path.h" 15#include "base/i18n/case_conversion.h" 16#include "base/i18n/string_search.h" 17#include "base/strings/string_util.h" 18#include "base/strings/stringprintf.h" 19#include "base/strings/utf_string_conversions.h" 20#include "ui/app_list/app_list_item.h" 21#include "ui/app_list/app_list_item_list.h" 22#include "ui/app_list/app_list_model.h" 23#include "ui/app_list/app_list_view_delegate.h" 24#include "ui/app_list/search_box_model.h" 25#include "ui/app_list/search_result.h" 26#include "ui/app_list/speech_ui_model.h" 27#include "ui/gfx/canvas.h" 28#include "ui/gfx/font_list.h" 29#include "ui/gfx/geometry/rect.h" 30#include "ui/gfx/image/image_skia.h" 31#include "ui/views/examples/examples_window_with_content.h" 32 33namespace ash { 34namespace shell { 35 36namespace { 37 38// WindowTypeShelfItem is an app item of app list. It carries a window 39// launch type and launches corresponding example window when activated. 40class WindowTypeShelfItem : public app_list::AppListItem { 41 public: 42 enum Type { 43 TOPLEVEL_WINDOW = 0, 44 NON_RESIZABLE_WINDOW, 45 LOCK_SCREEN, 46 WIDGETS_WINDOW, 47 EXAMPLES_WINDOW, 48 LAST_TYPE, 49 }; 50 51 explicit WindowTypeShelfItem(const std::string& id, Type type) 52 : app_list::AppListItem(id), 53 type_(type) { 54 std::string title(GetTitle(type)); 55 SetIcon(GetIcon(type), false); 56 SetName(title); 57 } 58 59 static gfx::ImageSkia GetIcon(Type type) { 60 static const SkColor kColors[] = { 61 SK_ColorRED, 62 SK_ColorGREEN, 63 SK_ColorBLUE, 64 SK_ColorYELLOW, 65 SK_ColorCYAN, 66 }; 67 68 const int kIconSize = 128; 69 SkBitmap icon; 70 icon.allocN32Pixels(kIconSize, kIconSize); 71 icon.eraseColor(kColors[static_cast<int>(type) % arraysize(kColors)]); 72 return gfx::ImageSkia::CreateFrom1xBitmap(icon); 73 } 74 75 // The text below is not localized as this is an example code. 76 static std::string GetTitle(Type type) { 77 switch (type) { 78 case TOPLEVEL_WINDOW: 79 return "Create Window"; 80 case NON_RESIZABLE_WINDOW: 81 return "Create Non-Resizable Window"; 82 case LOCK_SCREEN: 83 return "Lock Screen"; 84 case WIDGETS_WINDOW: 85 return "Show Example Widgets"; 86 case EXAMPLES_WINDOW: 87 return "Open Views Examples Window"; 88 default: 89 return "Unknown window type."; 90 } 91 } 92 93 // The text below is not localized as this is an example code. 94 static std::string GetDetails(Type type) { 95 // Assigns details only to some types so that we see both one-line 96 // and two-line results. 97 switch (type) { 98 case WIDGETS_WINDOW: 99 return "Creates a window to show example widgets"; 100 case EXAMPLES_WINDOW: 101 return "Creates a window to show views example."; 102 default: 103 return std::string(); 104 } 105 } 106 107 static void ActivateItem(Type type, int event_flags) { 108 switch (type) { 109 case TOPLEVEL_WINDOW: { 110 ToplevelWindow::CreateParams params; 111 params.can_resize = true; 112 ToplevelWindow::CreateToplevelWindow(params); 113 break; 114 } 115 case NON_RESIZABLE_WINDOW: { 116 ToplevelWindow::CreateToplevelWindow(ToplevelWindow::CreateParams()); 117 break; 118 } 119 case LOCK_SCREEN: { 120 Shell::GetInstance()->session_state_delegate()->LockScreen(); 121 break; 122 } 123 case WIDGETS_WINDOW: { 124 CreateWidgetsWindow(); 125 break; 126 } 127 case EXAMPLES_WINDOW: { 128 views::examples::ShowExamplesWindowWithContent( 129 views::examples::DO_NOTHING_ON_CLOSE, 130 Shell::GetInstance()->delegate()->GetActiveBrowserContext(), 131 NULL); 132 break; 133 } 134 default: 135 break; 136 } 137 } 138 139 // AppListItem 140 virtual void Activate(int event_flags) OVERRIDE { 141 ActivateItem(type_, event_flags); 142 } 143 144 private: 145 Type type_; 146 147 DISALLOW_COPY_AND_ASSIGN(WindowTypeShelfItem); 148}; 149 150// ExampleSearchResult is an app list search result. It provides what icon to 151// show, what should title and details text look like. It also carries the 152// matching window launch type so that AppListViewDelegate knows how to open 153// it. 154class ExampleSearchResult : public app_list::SearchResult { 155 public: 156 ExampleSearchResult(WindowTypeShelfItem::Type type, 157 const base::string16& query) 158 : type_(type) { 159 SetIcon(WindowTypeShelfItem::GetIcon(type_)); 160 161 base::string16 title = 162 base::UTF8ToUTF16(WindowTypeShelfItem::GetTitle(type_)); 163 set_title(title); 164 165 Tags title_tags; 166 const size_t match_len = query.length(); 167 168 // Highlight matching parts in title with bold. 169 // Note the following is not a proper way to handle i18n string. 170 title = base::i18n::ToLower(title); 171 size_t match_start = title.find(query); 172 while (match_start != base::string16::npos) { 173 title_tags.push_back(Tag(Tag::MATCH, 174 match_start, 175 match_start + match_len)); 176 match_start = title.find(query, match_start + match_len); 177 } 178 set_title_tags(title_tags); 179 180 base::string16 details = 181 base::UTF8ToUTF16(WindowTypeShelfItem::GetDetails(type_)); 182 set_details(details); 183 Tags details_tags; 184 details_tags.push_back(Tag(Tag::DIM, 0, details.length())); 185 set_details_tags(details_tags); 186 } 187 188 WindowTypeShelfItem::Type type() const { return type_; } 189 190 private: 191 WindowTypeShelfItem::Type type_; 192 193 DISALLOW_COPY_AND_ASSIGN(ExampleSearchResult); 194}; 195 196class ExampleAppListViewDelegate : public app_list::AppListViewDelegate { 197 public: 198 ExampleAppListViewDelegate() 199 : model_(new app_list::AppListModel), 200 speech_ui_(app_list::SPEECH_RECOGNITION_OFF) { 201 PopulateApps(); 202 DecorateSearchBox(model_->search_box()); 203 } 204 205 private: 206 void PopulateApps() { 207 for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) { 208 WindowTypeShelfItem::Type type = 209 static_cast<WindowTypeShelfItem::Type>(i); 210 std::string id = base::StringPrintf("%d", i); 211 scoped_ptr<WindowTypeShelfItem> shelf_item( 212 new WindowTypeShelfItem(id, type)); 213 model_->AddItem(shelf_item.PassAs<app_list::AppListItem>()); 214 } 215 } 216 217 gfx::ImageSkia CreateSearchBoxIcon() { 218 const base::string16 icon_text = base::ASCIIToUTF16("ash"); 219 const gfx::Size icon_size(32, 32); 220 221 gfx::Canvas canvas(icon_size, 1.0f, false /* is_opaque */); 222 canvas.DrawStringRectWithFlags( 223 icon_text, 224 gfx::FontList(), 225 SK_ColorBLACK, 226 gfx::Rect(icon_size), 227 gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_SUBPIXEL_RENDERING); 228 229 return gfx::ImageSkia(canvas.ExtractImageRep()); 230 } 231 232 void DecorateSearchBox(app_list::SearchBoxModel* search_box_model) { 233 search_box_model->SetIcon(CreateSearchBoxIcon()); 234 search_box_model->SetHintText(base::ASCIIToUTF16("Type to search...")); 235 } 236 237 // Overridden from app_list::AppListViewDelegate: 238 virtual bool ForceNativeDesktop() const OVERRIDE { 239 return false; 240 } 241 242 virtual void SetProfileByPath(const base::FilePath& profile_path) OVERRIDE { 243 // Nothing needs to be done. 244 } 245 246 virtual const Users& GetUsers() const OVERRIDE { 247 return users_; 248 } 249 250 virtual bool ShouldCenterWindow() const OVERRIDE { 251 return false; 252 } 253 254 virtual app_list::AppListModel* GetModel() OVERRIDE { return model_.get(); } 255 256 virtual app_list::SpeechUIModel* GetSpeechUI() OVERRIDE { 257 return &speech_ui_; 258 } 259 260 virtual void GetShortcutPathForApp( 261 const std::string& app_id, 262 const base::Callback<void(const base::FilePath&)>& callback) OVERRIDE { 263 callback.Run(base::FilePath()); 264 } 265 266 virtual void OpenSearchResult(app_list::SearchResult* result, 267 bool auto_launch, 268 int event_flags) OVERRIDE { 269 const ExampleSearchResult* example_result = 270 static_cast<const ExampleSearchResult*>(result); 271 WindowTypeShelfItem::ActivateItem(example_result->type(), event_flags); 272 } 273 274 virtual void InvokeSearchResultAction(app_list::SearchResult* result, 275 int action_index, 276 int event_flags) OVERRIDE { 277 NOTIMPLEMENTED(); 278 } 279 280 virtual base::TimeDelta GetAutoLaunchTimeout() OVERRIDE { 281 return base::TimeDelta(); 282 } 283 284 virtual void AutoLaunchCanceled() OVERRIDE { 285 } 286 287 virtual void StartSearch() OVERRIDE { 288 base::string16 query; 289 base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query); 290 query = base::i18n::ToLower(query); 291 292 model_->results()->DeleteAll(); 293 if (query.empty()) 294 return; 295 296 for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) { 297 WindowTypeShelfItem::Type type = 298 static_cast<WindowTypeShelfItem::Type>(i); 299 300 base::string16 title = 301 base::UTF8ToUTF16(WindowTypeShelfItem::GetTitle(type)); 302 if (base::i18n::StringSearchIgnoringCaseAndAccents( 303 query, title, NULL, NULL)) { 304 model_->results()->Add(new ExampleSearchResult(type, query)); 305 } 306 } 307 } 308 309 virtual void StopSearch() OVERRIDE { 310 // Nothing needs to be done. 311 } 312 313 virtual void ViewInitialized() OVERRIDE { 314 // Nothing needs to be done. 315 } 316 317 virtual void Dismiss() OVERRIDE { 318 DCHECK(ash::Shell::HasInstance()); 319 if (Shell::GetInstance()->GetAppListTargetVisibility()) 320 Shell::GetInstance()->ToggleAppList(NULL); 321 } 322 323 virtual void ViewClosing() OVERRIDE { 324 // Nothing needs to be done. 325 } 326 327 virtual gfx::ImageSkia GetWindowIcon() OVERRIDE { 328 return gfx::ImageSkia(); 329 } 330 331 virtual void OpenSettings() OVERRIDE { 332 // Nothing needs to be done. 333 } 334 335 virtual void OpenHelp() OVERRIDE { 336 // Nothing needs to be done. 337 } 338 339 virtual void OpenFeedback() OVERRIDE { 340 // Nothing needs to be done. 341 } 342 343 virtual void ToggleSpeechRecognition() OVERRIDE { 344 NOTIMPLEMENTED(); 345 } 346 347 virtual void ShowForProfileByPath( 348 const base::FilePath& profile_path) OVERRIDE { 349 // Nothing needs to be done. 350 } 351 352 virtual views::View* CreateStartPageWebView(const gfx::Size& size) OVERRIDE { 353 return NULL; 354 } 355 356 virtual views::View* CreateCustomPageWebView(const gfx::Size& size) OVERRIDE { 357 return NULL; 358 } 359 360 virtual bool IsSpeechRecognitionEnabled() OVERRIDE { 361 return false; 362 } 363 364 scoped_ptr<app_list::AppListModel> model_; 365 app_list::SpeechUIModel speech_ui_; 366 Users users_; 367 368 DISALLOW_COPY_AND_ASSIGN(ExampleAppListViewDelegate); 369}; 370 371} // namespace 372 373app_list::AppListViewDelegate* CreateAppListViewDelegate() { 374 return new ExampleAppListViewDelegate; 375} 376 377} // namespace shell 378} // namespace ash 379