app_list.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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
33namespace ash {
34namespace shell {
35
36namespace {
37
38// WindowTypeShelfItem is an app item of app list. It carries a window
39// launch type and launches corresponding example window when activated.
40class 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.allocN32Pixels(kIconSize, kIconSize);
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()->GetActiveBrowserContext(),
131            NULL);
132        break;
133      }
134      default:
135        break;
136    }
137  }
138
139  // AppListItem
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(WindowTypeShelfItem);
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(WindowTypeShelfItem::Type type,
157                      const base::string16& query)
158      : type_(type) {
159    SetIcon(WindowTypeShelfItem::GetIcon(type_));
160
161    base::string16 title =
162        base::UTF8ToUTF16(WindowTypeShelfItem::GetTitle(type_));
163    set_title(title);
164
165    Tags title_tags;
166    const size_t match_len = query.length();
167
168    // Highlight matching parts in title with bold.
169    // Note the following is not a proper way to handle i18n string.
170    title = base::i18n::ToLower(title);
171    size_t match_start = title.find(query);
172    while (match_start != base::string16::npos) {
173      title_tags.push_back(Tag(Tag::MATCH,
174                               match_start,
175                               match_start + match_len));
176      match_start = title.find(query, match_start + match_len);
177    }
178    set_title_tags(title_tags);
179
180    base::string16 details =
181        base::UTF8ToUTF16(WindowTypeShelfItem::GetDetails(type_));
182    set_details(details);
183    Tags details_tags;
184    details_tags.push_back(Tag(Tag::DIM, 0, details.length()));
185    set_details_tags(details_tags);
186  }
187
188  WindowTypeShelfItem::Type type() const { return type_; }
189
190 private:
191  WindowTypeShelfItem::Type type_;
192
193  DISALLOW_COPY_AND_ASSIGN(ExampleSearchResult);
194};
195
196class ExampleAppListViewDelegate : public app_list::AppListViewDelegate {
197 public:
198  ExampleAppListViewDelegate()
199      : model_(new app_list::AppListModel),
200        speech_ui_(app_list::SPEECH_RECOGNITION_OFF) {
201    PopulateApps();
202    DecorateSearchBox(model_->search_box());
203  }
204
205 private:
206  void PopulateApps() {
207    for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) {
208      WindowTypeShelfItem::Type type =
209          static_cast<WindowTypeShelfItem::Type>(i);
210      std::string id = base::StringPrintf("%d", i);
211      scoped_ptr<WindowTypeShelfItem> shelf_item(
212          new WindowTypeShelfItem(id, type));
213      model_->AddItem(shelf_item.PassAs<app_list::AppListItem>());
214    }
215  }
216
217  gfx::ImageSkia CreateSearchBoxIcon() {
218    const base::string16 icon_text = base::ASCIIToUTF16("ash");
219    const gfx::Size icon_size(32, 32);
220
221    gfx::Canvas canvas(icon_size, 1.0f, false /* is_opaque */);
222    canvas.DrawStringRectWithFlags(
223        icon_text,
224        gfx::FontList(),
225        SK_ColorBLACK,
226        gfx::Rect(icon_size),
227        gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_SUBPIXEL_RENDERING);
228
229    return gfx::ImageSkia(canvas.ExtractImageRep());
230  }
231
232  void DecorateSearchBox(app_list::SearchBoxModel* search_box_model) {
233    search_box_model->SetIcon(CreateSearchBoxIcon());
234    search_box_model->SetHintText(base::ASCIIToUTF16("Type to search..."));
235  }
236
237  // Overridden from app_list::AppListViewDelegate:
238  virtual bool ForceNativeDesktop() const OVERRIDE {
239    return false;
240  }
241
242  virtual void SetProfileByPath(const base::FilePath& profile_path) OVERRIDE {
243    // Nothing needs to be done.
244  }
245
246  virtual const Users& GetUsers() const OVERRIDE {
247    return users_;
248  }
249
250  virtual bool ShouldCenterWindow() const OVERRIDE {
251    return false;
252  }
253
254  virtual app_list::AppListModel* GetModel() OVERRIDE { return model_.get(); }
255
256  virtual app_list::SpeechUIModel* GetSpeechUI() OVERRIDE {
257    return &speech_ui_;
258  }
259
260  virtual void GetShortcutPathForApp(
261      const std::string& app_id,
262      const base::Callback<void(const base::FilePath&)>& callback) OVERRIDE {
263    callback.Run(base::FilePath());
264  }
265
266  virtual void OpenSearchResult(app_list::SearchResult* result,
267                                bool auto_launch,
268                                int event_flags) OVERRIDE {
269    const ExampleSearchResult* example_result =
270        static_cast<const ExampleSearchResult*>(result);
271    WindowTypeShelfItem::ActivateItem(example_result->type(), event_flags);
272  }
273
274  virtual void InvokeSearchResultAction(app_list::SearchResult* result,
275                                        int action_index,
276                                        int event_flags) OVERRIDE {
277    NOTIMPLEMENTED();
278  }
279
280  virtual base::TimeDelta GetAutoLaunchTimeout() OVERRIDE {
281    return base::TimeDelta();
282  }
283
284  virtual void AutoLaunchCanceled() OVERRIDE {
285  }
286
287  virtual void StartSearch() OVERRIDE {
288    base::string16 query;
289    base::TrimWhitespace(model_->search_box()->text(), base::TRIM_ALL, &query);
290    query = base::i18n::ToLower(query);
291
292    model_->results()->DeleteAll();
293    if (query.empty())
294      return;
295
296    for (int i = 0; i < static_cast<int>(WindowTypeShelfItem::LAST_TYPE); ++i) {
297      WindowTypeShelfItem::Type type =
298          static_cast<WindowTypeShelfItem::Type>(i);
299
300      base::string16 title =
301          base::UTF8ToUTF16(WindowTypeShelfItem::GetTitle(type));
302      if (base::i18n::StringSearchIgnoringCaseAndAccents(
303              query, title, NULL, NULL)) {
304        model_->results()->Add(new ExampleSearchResult(type, query));
305      }
306    }
307  }
308
309  virtual void StopSearch() OVERRIDE {
310    // Nothing needs to be done.
311  }
312
313  virtual void ViewInitialized() OVERRIDE {
314    // Nothing needs to be done.
315  }
316
317  virtual void Dismiss() OVERRIDE {
318    DCHECK(ash::Shell::HasInstance());
319    if (Shell::GetInstance()->GetAppListTargetVisibility())
320      Shell::GetInstance()->ToggleAppList(NULL);
321  }
322
323  virtual void ViewClosing() OVERRIDE {
324    // Nothing needs to be done.
325  }
326
327  virtual gfx::ImageSkia GetWindowIcon() OVERRIDE {
328    return gfx::ImageSkia();
329  }
330
331  virtual void OpenSettings() OVERRIDE {
332    // Nothing needs to be done.
333  }
334
335  virtual void OpenHelp() OVERRIDE {
336    // Nothing needs to be done.
337  }
338
339  virtual void OpenFeedback() OVERRIDE {
340    // Nothing needs to be done.
341  }
342
343  virtual void ToggleSpeechRecognition() OVERRIDE {
344    NOTIMPLEMENTED();
345  }
346
347  virtual void ShowForProfileByPath(
348      const base::FilePath& profile_path) OVERRIDE {
349    // Nothing needs to be done.
350  }
351
352  virtual views::View* CreateStartPageWebView(const gfx::Size& size) OVERRIDE {
353    return NULL;
354  }
355
356  virtual views::View* CreateCustomPageWebView(const gfx::Size& size) OVERRIDE {
357    return NULL;
358  }
359
360  virtual bool IsSpeechRecognitionEnabled() OVERRIDE {
361    return false;
362  }
363
364  scoped_ptr<app_list::AppListModel> model_;
365  app_list::SpeechUIModel speech_ui_;
366  Users users_;
367
368  DISALLOW_COPY_AND_ASSIGN(ExampleAppListViewDelegate);
369};
370
371}  // namespace
372
373app_list::AppListViewDelegate* CreateAppListViewDelegate() {
374  return new ExampleAppListViewDelegate;
375}
376
377}  // namespace shell
378}  // namespace ash
379