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