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