Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / apps / app_info_dialog / app_info_summary_panel.cc
1 // Copyright 2014 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 "chrome/browser/ui/views/apps/app_info_dialog/app_info_summary_panel.h"
6
7 #include <vector>
8
9 #include "base/callback_forward.h"
10 #include "base/command_line.h"
11 #include "base/file_util.h"
12 #include "base/i18n/time_formatting.h"
13 #include "base/logging.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/task_runner_util.h"
16 #include "chrome/browser/extensions/extension_service.h"
17 #include "chrome/browser/extensions/launch_util.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "chrome/grit/generated_resources.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "extensions/browser/extension_prefs.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/manifest.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/base/models/combobox_model.h"
29 #include "ui/base/text/bytes_formatting.h"
30 #include "ui/views/controls/combobox/combobox.h"
31 #include "ui/views/controls/label.h"
32 #include "ui/views/layout/box_layout.h"
33 #include "ui/views/layout/layout_constants.h"
34 #include "ui/views/view.h"
35 #include "ui/views/widget/widget.h"
36
37 // A model for a combobox selecting the launch options for a hosted app.
38 // Displays different options depending on the host OS.
39 class LaunchOptionsComboboxModel : public ui::ComboboxModel {
40  public:
41   LaunchOptionsComboboxModel();
42   virtual ~LaunchOptionsComboboxModel();
43
44   extensions::LaunchType GetLaunchTypeAtIndex(int index) const;
45   int GetIndexForLaunchType(extensions::LaunchType launch_type) const;
46
47   // Overridden from ui::ComboboxModel:
48   virtual int GetItemCount() const OVERRIDE;
49   virtual base::string16 GetItemAt(int index) OVERRIDE;
50
51  private:
52   // A list of the launch types available in the combobox, in order.
53   std::vector<extensions::LaunchType> launch_types_;
54
55   // A list of the messages to display in the combobox, in order. The indexes in
56   // this list correspond to the indexes in launch_types_.
57   std::vector<base::string16> launch_type_messages_;
58 };
59
60 LaunchOptionsComboboxModel::LaunchOptionsComboboxModel() {
61   if (CommandLine::ForCurrentProcess()->HasSwitch(
62           switches::kEnableStreamlinedHostedApps)) {
63     // Streamlined hosted apps can only toggle between LAUNCH_TYPE_WINDOW and
64     // LAUNCH_TYPE_REGULAR.
65     // TODO(sashab): Use a checkbox for this choice instead of combobox.
66     launch_types_.push_back(extensions::LAUNCH_TYPE_REGULAR);
67     launch_type_messages_.push_back(
68         l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_TAB));
69
70     // Although LAUNCH_TYPE_WINDOW doesn't work on Mac, the streamlined hosted
71     // apps flag isn't available on Mac, so we must be on a non-Mac OS.
72     launch_types_.push_back(extensions::LAUNCH_TYPE_WINDOW);
73     launch_type_messages_.push_back(
74         l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_WINDOW));
75   } else {
76     launch_types_.push_back(extensions::LAUNCH_TYPE_REGULAR);
77     launch_type_messages_.push_back(
78         l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_REGULAR));
79
80     launch_types_.push_back(extensions::LAUNCH_TYPE_PINNED);
81     launch_type_messages_.push_back(
82         l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_PINNED));
83
84 #if defined(OS_MACOSX)
85     // Mac does not support standalone web app browser windows or maximize.
86     launch_types_.push_back(extensions::LAUNCH_TYPE_FULLSCREEN);
87     launch_type_messages_.push_back(
88         l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_FULLSCREEN));
89 #else
90     launch_types_.push_back(extensions::LAUNCH_TYPE_WINDOW);
91     launch_type_messages_.push_back(
92         l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_WINDOW));
93
94     // Even though the launch type is Full Screen, it is more accurately
95     // described as Maximized in non-Mac OSs.
96     launch_types_.push_back(extensions::LAUNCH_TYPE_FULLSCREEN);
97     launch_type_messages_.push_back(
98         l10n_util::GetStringUTF16(IDS_APP_CONTEXT_MENU_OPEN_MAXIMIZED));
99 #endif
100   }
101 }
102
103 LaunchOptionsComboboxModel::~LaunchOptionsComboboxModel() {
104 }
105
106 extensions::LaunchType LaunchOptionsComboboxModel::GetLaunchTypeAtIndex(
107     int index) const {
108   return launch_types_[index];
109 }
110
111 int LaunchOptionsComboboxModel::GetIndexForLaunchType(
112     extensions::LaunchType launch_type) const {
113   for (size_t i = 0; i < launch_types_.size(); i++) {
114     if (launch_types_[i] == launch_type) {
115       return i;
116     }
117   }
118   // If the requested launch type is not available, just select the first one.
119   LOG(WARNING) << "Unavailable launch type " << launch_type << " selected.";
120   return 0;
121 }
122
123 int LaunchOptionsComboboxModel::GetItemCount() const {
124   return launch_types_.size();
125 }
126
127 base::string16 LaunchOptionsComboboxModel::GetItemAt(int index) {
128   return launch_type_messages_[index];
129 }
130
131 AppInfoSummaryPanel::AppInfoSummaryPanel(Profile* profile,
132                                          const extensions::Extension* app)
133     : AppInfoPanel(profile, app),
134       description_heading_(NULL),
135       description_label_(NULL),
136       details_heading_(NULL),
137       size_title_(NULL),
138       size_value_(NULL),
139       version_title_(NULL),
140       version_value_(NULL),
141       installed_time_title_(NULL),
142       installed_time_value_(NULL),
143       last_run_time_title_(NULL),
144       last_run_time_value_(NULL),
145       launch_options_combobox_(NULL),
146       weak_ptr_factory_(this) {
147   // Create UI elements.
148   CreateDescriptionControl();
149   CreateDetailsControl();
150   CreateLaunchOptionControl();
151
152   // Layout elements.
153   SetLayoutManager(
154       new views::BoxLayout(views::BoxLayout::kVertical,
155                            0,
156                            0,
157                            views::kUnrelatedControlVerticalSpacing));
158
159   LayoutDescriptionControl();
160   LayoutDetailsControl();
161
162   if (launch_options_combobox_)
163     AddChildView(launch_options_combobox_);
164 }
165
166 AppInfoSummaryPanel::~AppInfoSummaryPanel() {
167   // Destroy view children before their models.
168   RemoveAllChildViews(true);
169 }
170
171 void AppInfoSummaryPanel::CreateDescriptionControl() {
172   if (!app_->description().empty()) {
173     const size_t kMaxLength = 400;
174
175     base::string16 text = base::UTF8ToUTF16(app_->description());
176     if (text.length() > kMaxLength) {
177       text = text.substr(0, kMaxLength);
178       text += base::ASCIIToUTF16(" ... ");
179     }
180
181     description_heading_ = CreateHeading(
182         l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_DESCRIPTION_TITLE));
183     description_label_ = new views::Label(text);
184     description_label_->SetMultiLine(true);
185     description_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
186   }
187 }
188
189 void AppInfoSummaryPanel::CreateDetailsControl() {
190   // The size doesn't make sense for component apps.
191   if (app_->location() != extensions::Manifest::COMPONENT) {
192     size_title_ = new views::Label(
193         l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_SIZE_LABEL));
194     size_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
195
196     size_value_ = new views::Label(
197         l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_SIZE_LOADING_LABEL));
198     size_value_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
199
200     StartCalculatingAppSize();
201   }
202
203   // The version doesn't make sense for bookmark apps.
204   if (!app_->from_bookmark()) {
205     // Display 'Version: Built-in' for component apps.
206     base::string16 version_str = base::ASCIIToUTF16(app_->VersionString());
207     if (app_->location() == extensions::Manifest::COMPONENT)
208       version_str = l10n_util::GetStringUTF16(
209           IDS_APPLICATION_INFO_VERSION_BUILT_IN_LABEL);
210
211     version_title_ = new views::Label(
212         l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_VERSION_LABEL));
213     version_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
214
215     version_value_ = new views::Label(version_str);
216     version_value_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
217   }
218
219   // The install date doesn't make sense for component apps.
220   if (app_->location() != extensions::Manifest::COMPONENT) {
221     installed_time_title_ = new views::Label(
222         l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_INSTALLED_LABEL));
223     installed_time_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
224
225     installed_time_value_ =
226         new views::Label(base::TimeFormatShortDate(GetInstalledTime()));
227     installed_time_value_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
228   }
229
230   // The last run time is currently incorrect for component and hosted apps,
231   // since it is not updated when they are accessed outside of their shortcuts.
232   // TODO(sashab): Update the run time for these correctly: crbug.com/398716
233   if (app_->location() != extensions::Manifest::COMPONENT &&
234       !app_->is_hosted_app()) {
235     last_run_time_title_ = new views::Label(
236         l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_LAST_RUN_LABEL));
237     last_run_time_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
238
239     // Display 'Never' if the app has never been run.
240     base::string16 last_run_value_str =
241         l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_LAST_RUN_NEVER_LABEL);
242     if (GetLastLaunchedTime() != base::Time())
243       last_run_value_str = base::TimeFormatShortDate(GetLastLaunchedTime());
244
245     last_run_time_value_ = new views::Label(last_run_value_str);
246     last_run_time_value_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
247   }
248
249   // Only generate the heading if we have at least one field to display.
250   if (version_title_ || installed_time_title_ || last_run_time_title_) {
251     details_heading_ = CreateHeading(
252         l10n_util::GetStringUTF16(IDS_APPLICATION_INFO_DETAILS_TITLE));
253   }
254 }
255
256 void AppInfoSummaryPanel::CreateLaunchOptionControl() {
257   if (CanSetLaunchType()) {
258     launch_options_combobox_model_.reset(new LaunchOptionsComboboxModel());
259     launch_options_combobox_ =
260         new views::Combobox(launch_options_combobox_model_.get());
261
262     launch_options_combobox_->set_listener(this);
263     launch_options_combobox_->SetSelectedIndex(
264         launch_options_combobox_model_->GetIndexForLaunchType(GetLaunchType()));
265   }
266 }
267
268 void AppInfoSummaryPanel::LayoutDescriptionControl() {
269   if (description_label_) {
270     DCHECK(description_heading_);
271     views::View* vertical_stack = CreateVerticalStack();
272     vertical_stack->AddChildView(description_heading_);
273     vertical_stack->AddChildView(description_label_);
274     AddChildView(vertical_stack);
275   }
276 }
277
278 void AppInfoSummaryPanel::LayoutDetailsControl() {
279   if (details_heading_) {
280     views::View* details_stack =
281         CreateVerticalStack(views::kRelatedControlSmallVerticalSpacing);
282
283     if (version_title_ && version_value_) {
284       details_stack->AddChildView(
285           CreateKeyValueField(version_title_, version_value_));
286     }
287
288     if (installed_time_title_ && installed_time_value_) {
289       details_stack->AddChildView(
290           CreateKeyValueField(installed_time_title_, installed_time_value_));
291     }
292
293     if (last_run_time_title_ && last_run_time_value_) {
294       details_stack->AddChildView(
295           CreateKeyValueField(last_run_time_title_, last_run_time_value_));
296     }
297
298     if (size_title_ && size_value_) {
299       details_stack->AddChildView(
300           CreateKeyValueField(size_title_, size_value_));
301     }
302
303     views::View* vertical_stack = CreateVerticalStack();
304     vertical_stack->AddChildView(details_heading_);
305     vertical_stack->AddChildView(details_stack);
306     AddChildView(vertical_stack);
307   }
308 }
309
310 void AppInfoSummaryPanel::OnPerformAction(views::Combobox* combobox) {
311   if (combobox == launch_options_combobox_) {
312     SetLaunchType(launch_options_combobox_model_->GetLaunchTypeAtIndex(
313         launch_options_combobox_->selected_index()));
314   } else {
315     NOTREACHED();
316   }
317 }
318
319 void AppInfoSummaryPanel::StartCalculatingAppSize() {
320   base::PostTaskAndReplyWithResult(
321       content::BrowserThread::GetBlockingPool(),
322       FROM_HERE,
323       base::Bind(&base::ComputeDirectorySize, app_->path()),
324       base::Bind(&AppInfoSummaryPanel::OnAppSizeCalculated, AsWeakPtr()));
325 }
326
327 void AppInfoSummaryPanel::OnAppSizeCalculated(int64 app_size_in_bytes) {
328   size_value_->SetText(ui::FormatBytes(app_size_in_bytes));
329 }
330
331 base::Time AppInfoSummaryPanel::GetInstalledTime() const {
332   return extensions::ExtensionPrefs::Get(profile_)->GetInstallTime(app_->id());
333 }
334
335 base::Time AppInfoSummaryPanel::GetLastLaunchedTime() const {
336   return extensions::ExtensionPrefs::Get(profile_)
337       ->GetLastLaunchTime(app_->id());
338 }
339
340 extensions::LaunchType AppInfoSummaryPanel::GetLaunchType() const {
341   return extensions::GetLaunchType(extensions::ExtensionPrefs::Get(profile_),
342                                    app_);
343 }
344
345 void AppInfoSummaryPanel::SetLaunchType(
346     extensions::LaunchType launch_type) const {
347   DCHECK(CanSetLaunchType());
348   ExtensionService* service =
349       extensions::ExtensionSystem::Get(profile_)->extension_service();
350   extensions::SetLaunchType(service, app_->id(), launch_type);
351 }
352
353 bool AppInfoSummaryPanel::CanSetLaunchType() const {
354   // V2 apps don't have a launch type, and neither does the Chrome app.
355   return app_->id() != extension_misc::kChromeAppId && !app_->is_platform_app();
356 }