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