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