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 33 namespace ash { 34 namespace shell { 35 36 namespace { 37 38 // WindowTypeShelfItem is an app item of app list. It carries a window 39 // launch type and launches corresponding example window when activated. 40 class 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.setConfig(SkBitmap::kARGB_8888_Config, kIconSize, kIconSize); 71 icon.allocPixels(); 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 speech_ui_(app_list::SPEECH_RECOGNITION_OFF) { 202 PopulateApps(); 203 DecorateSearchBox(model_->search_box()); 204 } 205 206 private: 207 void PopulateApps() { 208 for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) { 209 WindowTypeShelfItem::Type type = 210 static_cast<WindowTypeShelfItem::Type>(i); 211 std::string id = base::StringPrintf("%d", i); 212 scoped_ptr<WindowTypeShelfItem> shelf_item( 213 new WindowTypeShelfItem(id, type)); 214 model_->AddItem(shelf_item.PassAs<app_list::AppListItem>()); 215 } 216 } 217 218 gfx::ImageSkia CreateSearchBoxIcon() { 219 const base::string16 icon_text = base::ASCIIToUTF16("ash"); 220 const gfx::Size icon_size(32, 32); 221 222 gfx::Canvas canvas(icon_size, 1.0f, false /* is_opaque */); 223 canvas.DrawStringRectWithFlags( 224 icon_text, 225 gfx::FontList(), 226 SK_ColorBLACK, 227 gfx::Rect(icon_size), 228 gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_SUBPIXEL_RENDERING); 229 230 return gfx::ImageSkia(canvas.ExtractImageRep()); 231 } 232 233 void DecorateSearchBox(app_list::SearchBoxModel* search_box_model) { 234 search_box_model->SetIcon(CreateSearchBoxIcon()); 235 search_box_model->SetHintText(base::ASCIIToUTF16("Type to search...")); 236 } 237 238 // Overridden from app_list::AppListViewDelegate: 239 virtual bool ForceNativeDesktop() const OVERRIDE { 240 return false; 241 } 242 243 virtual void SetProfileByPath(const base::FilePath& profile_path) OVERRIDE { 244 // Nothing needs to be done. 245 } 246 247 virtual const Users& GetUsers() const OVERRIDE { 248 return users_; 249 } 250 251 virtual bool ShouldCenterWindow() const OVERRIDE { 252 return false; 253 } 254 255 virtual app_list::AppListModel* GetModel() OVERRIDE { return model_.get(); } 256 257 virtual app_list::SpeechUIModel* GetSpeechUI() OVERRIDE { 258 return &speech_ui_; 259 } 260 261 virtual void GetShortcutPathForApp( 262 const std::string& app_id, 263 const base::Callback<void(const base::FilePath&)>& callback) OVERRIDE { 264 callback.Run(base::FilePath()); 265 } 266 267 virtual void OpenSearchResult(app_list::SearchResult* result, 268 bool auto_launch, 269 int event_flags) OVERRIDE { 270 const ExampleSearchResult* example_result = 271 static_cast<const ExampleSearchResult*>(result); 272 WindowTypeShelfItem::ActivateItem(example_result->type(), event_flags); 273 } 274 275 virtual void InvokeSearchResultAction(app_list::SearchResult* result, 276 int action_index, 277 int event_flags) OVERRIDE { 278 NOTIMPLEMENTED(); 279 } 280 281 virtual base::TimeDelta GetAutoLaunchTimeout() OVERRIDE { 282 return base::TimeDelta(); 283 } 284 285 virtual void AutoLaunchCanceled() OVERRIDE { 286 } 287 288 virtual void StartSearch() OVERRIDE { 289 base::string16 query; 290 base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query); 291 query = base::i18n::ToLower(query); 292 293 model_->results()->DeleteAll(); 294 if (query.empty()) 295 return; 296 297 for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) { 298 WindowTypeShelfItem::Type type = 299 static_cast<WindowTypeShelfItem::Type>(i); 300 301 base::string16 title = 302 base::UTF8ToUTF16(WindowTypeShelfItem::GetTitle(type)); 303 if (base::i18n::StringSearchIgnoringCaseAndAccents( 304 query, title, NULL, NULL)) { 305 model_->results()->Add(new ExampleSearchResult(type, query)); 306 } 307 } 308 } 309 310 virtual void StopSearch() OVERRIDE { 311 // Nothing needs to be done. 312 } 313 314 virtual void ViewInitialized() OVERRIDE { 315 // Nothing needs to be done. 316 } 317 318 virtual void Dismiss() OVERRIDE { 319 DCHECK(ash::Shell::HasInstance()); 320 if (Shell::GetInstance()->GetAppListTargetVisibility()) 321 Shell::GetInstance()->ToggleAppList(NULL); 322 } 323 324 virtual void ViewClosing() OVERRIDE { 325 // Nothing needs to be done. 326 } 327 328 virtual gfx::ImageSkia GetWindowIcon() OVERRIDE { 329 return gfx::ImageSkia(); 330 } 331 332 virtual void OpenSettings() OVERRIDE { 333 // Nothing needs to be done. 334 } 335 336 virtual void OpenHelp() OVERRIDE { 337 // Nothing needs to be done. 338 } 339 340 virtual void OpenFeedback() OVERRIDE { 341 // Nothing needs to be done. 342 } 343 344 virtual void ToggleSpeechRecognition() OVERRIDE { 345 NOTIMPLEMENTED(); 346 } 347 348 virtual void ShowForProfileByPath( 349 const base::FilePath& profile_path) OVERRIDE { 350 // Nothing needs to be done. 351 } 352 353 virtual views::View* CreateStartPageWebView(const gfx::Size& size) OVERRIDE { 354 return NULL; 355 } 356 357 virtual bool IsSpeechRecognitionEnabled() OVERRIDE { 358 return false; 359 } 360 361 scoped_ptr<app_list::AppListModel> model_; 362 app_list::SpeechUIModel speech_ui_; 363 Users users_; 364 365 DISALLOW_COPY_AND_ASSIGN(ExampleAppListViewDelegate); 366 }; 367 368 } // namespace 369 370 app_list::AppListViewDelegate* CreateAppListViewDelegate() { 371 return new ExampleAppListViewDelegate; 372 } 373 374 } // namespace shell 375 } // namespace ash 376