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 #include <vector> 7 8 #include "ash/session/session_state_delegate.h" 9 #include "ash/shell.h" 10 #include "ash/shell/example_factory.h" 11 #include "ash/shell/toplevel_window.h" 12 #include "ash/shell_delegate.h" 13 #include "base/basictypes.h" 14 #include "base/callback.h" 15 #include "base/files/file_path.h" 16 #include "base/i18n/case_conversion.h" 17 #include "base/i18n/string_search.h" 18 #include "base/strings/string_util.h" 19 #include "base/strings/stringprintf.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "ui/app_list/app_list_item.h" 22 #include "ui/app_list/app_list_item_list.h" 23 #include "ui/app_list/app_list_model.h" 24 #include "ui/app_list/app_list_view_delegate.h" 25 #include "ui/app_list/search_box_model.h" 26 #include "ui/app_list/search_result.h" 27 #include "ui/app_list/speech_ui_model.h" 28 #include "ui/gfx/canvas.h" 29 #include "ui/gfx/font_list.h" 30 #include "ui/gfx/geometry/rect.h" 31 #include "ui/gfx/image/image_skia.h" 32 #include "ui/views/examples/examples_window_with_content.h" 33 34 namespace ash { 35 namespace shell { 36 37 namespace { 38 39 // WindowTypeShelfItem is an app item of app list. It carries a window 40 // launch type and launches corresponding example window when activated. 41 class WindowTypeShelfItem : public app_list::AppListItem { 42 public: 43 enum Type { 44 TOPLEVEL_WINDOW = 0, 45 NON_RESIZABLE_WINDOW, 46 LOCK_SCREEN, 47 WIDGETS_WINDOW, 48 EXAMPLES_WINDOW, 49 LAST_TYPE, 50 }; 51 52 explicit WindowTypeShelfItem(const std::string& id, Type type) 53 : app_list::AppListItem(id), 54 type_(type) { 55 std::string title(GetTitle(type)); 56 SetIcon(GetIcon(type), false); 57 SetName(title); 58 } 59 60 static gfx::ImageSkia GetIcon(Type type) { 61 static const SkColor kColors[] = { 62 SK_ColorRED, 63 SK_ColorGREEN, 64 SK_ColorBLUE, 65 SK_ColorYELLOW, 66 SK_ColorCYAN, 67 }; 68 69 const int kIconSize = 128; 70 SkBitmap icon; 71 icon.allocN32Pixels(kIconSize, kIconSize); 72 icon.eraseColor(kColors[static_cast<int>(type) % arraysize(kColors)]); 73 return gfx::ImageSkia::CreateFrom1xBitmap(icon); 74 } 75 76 // The text below is not localized as this is an example code. 77 static std::string GetTitle(Type type) { 78 switch (type) { 79 case TOPLEVEL_WINDOW: 80 return "Create Window"; 81 case NON_RESIZABLE_WINDOW: 82 return "Create Non-Resizable Window"; 83 case LOCK_SCREEN: 84 return "Lock Screen"; 85 case WIDGETS_WINDOW: 86 return "Show Example Widgets"; 87 case EXAMPLES_WINDOW: 88 return "Open Views Examples Window"; 89 default: 90 return "Unknown window type."; 91 } 92 } 93 94 // The text below is not localized as this is an example code. 95 static std::string GetDetails(Type type) { 96 // Assigns details only to some types so that we see both one-line 97 // and two-line results. 98 switch (type) { 99 case WIDGETS_WINDOW: 100 return "Creates a window to show example widgets"; 101 case EXAMPLES_WINDOW: 102 return "Creates a window to show views example."; 103 default: 104 return std::string(); 105 } 106 } 107 108 static void ActivateItem(Type type, int event_flags) { 109 switch (type) { 110 case TOPLEVEL_WINDOW: { 111 ToplevelWindow::CreateParams params; 112 params.can_resize = true; 113 ToplevelWindow::CreateToplevelWindow(params); 114 break; 115 } 116 case NON_RESIZABLE_WINDOW: { 117 ToplevelWindow::CreateToplevelWindow(ToplevelWindow::CreateParams()); 118 break; 119 } 120 case LOCK_SCREEN: { 121 Shell::GetInstance()->session_state_delegate()->LockScreen(); 122 break; 123 } 124 case WIDGETS_WINDOW: { 125 CreateWidgetsWindow(); 126 break; 127 } 128 case EXAMPLES_WINDOW: { 129 views::examples::ShowExamplesWindowWithContent( 130 views::examples::DO_NOTHING_ON_CLOSE, 131 Shell::GetInstance()->delegate()->GetActiveBrowserContext(), 132 NULL); 133 break; 134 } 135 default: 136 break; 137 } 138 } 139 140 // AppListItem 141 virtual void Activate(int event_flags) OVERRIDE { 142 ActivateItem(type_, event_flags); 143 } 144 145 private: 146 Type type_; 147 148 DISALLOW_COPY_AND_ASSIGN(WindowTypeShelfItem); 149 }; 150 151 // ExampleSearchResult is an app list search result. It provides what icon to 152 // show, what should title and details text look like. It also carries the 153 // matching window launch type so that AppListViewDelegate knows how to open 154 // it. 155 class ExampleSearchResult : public app_list::SearchResult { 156 public: 157 ExampleSearchResult(WindowTypeShelfItem::Type type, 158 const base::string16& query) 159 : type_(type) { 160 SetIcon(WindowTypeShelfItem::GetIcon(type_)); 161 162 base::string16 title = 163 base::UTF8ToUTF16(WindowTypeShelfItem::GetTitle(type_)); 164 set_title(title); 165 166 Tags title_tags; 167 const size_t match_len = query.length(); 168 169 // Highlight matching parts in title with bold. 170 // Note the following is not a proper way to handle i18n string. 171 title = base::i18n::ToLower(title); 172 size_t match_start = title.find(query); 173 while (match_start != base::string16::npos) { 174 title_tags.push_back(Tag(Tag::MATCH, 175 match_start, 176 match_start + match_len)); 177 match_start = title.find(query, match_start + match_len); 178 } 179 set_title_tags(title_tags); 180 181 base::string16 details = 182 base::UTF8ToUTF16(WindowTypeShelfItem::GetDetails(type_)); 183 set_details(details); 184 Tags details_tags; 185 details_tags.push_back(Tag(Tag::DIM, 0, details.length())); 186 set_details_tags(details_tags); 187 } 188 189 WindowTypeShelfItem::Type type() const { return type_; } 190 191 private: 192 WindowTypeShelfItem::Type type_; 193 194 DISALLOW_COPY_AND_ASSIGN(ExampleSearchResult); 195 }; 196 197 class ExampleAppListViewDelegate : public app_list::AppListViewDelegate { 198 public: 199 ExampleAppListViewDelegate() 200 : model_(new app_list::AppListModel) { 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 Shell::GetInstance()->DismissAppList(); 320 } 321 322 virtual void ViewClosing() OVERRIDE { 323 // Nothing needs to be done. 324 } 325 326 virtual gfx::ImageSkia GetWindowIcon() OVERRIDE { 327 return gfx::ImageSkia(); 328 } 329 330 virtual void OpenSettings() OVERRIDE { 331 // Nothing needs to be done. 332 } 333 334 virtual void OpenHelp() OVERRIDE { 335 // Nothing needs to be done. 336 } 337 338 virtual void OpenFeedback() OVERRIDE { 339 // Nothing needs to be done. 340 } 341 342 virtual void ToggleSpeechRecognition() OVERRIDE { 343 NOTIMPLEMENTED(); 344 } 345 346 virtual void ShowForProfileByPath( 347 const base::FilePath& profile_path) OVERRIDE { 348 // Nothing needs to be done. 349 } 350 351 virtual views::View* CreateStartPageWebView(const gfx::Size& size) OVERRIDE { 352 return NULL; 353 } 354 355 virtual std::vector<views::View*> CreateCustomPageWebViews( 356 const gfx::Size& size) OVERRIDE { 357 return std::vector<views::View*>(); 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 373 app_list::AppListViewDelegate* CreateAppListViewDelegate() { 374 return new ExampleAppListViewDelegate; 375 } 376 377 } // namespace shell 378 } // namespace ash 379