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