Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(375)

Side by Side Diff: chrome/browser/autocomplete/autocomplete_edit_view_views.cc

Issue 6245003: Views-implementation of AutocompleteEditView (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/autocomplete/autocomplete_edit_view_views.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/autocomplete/autocomplete_edit_view_views.h"
6
7 #include "app/l10n_util.h"
8 #include "base/logging.h"
9 #include "base/string_util.h"
10 #include "base/utf_string_conversions.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/autocomplete/autocomplete_edit.h"
13 #include "chrome/browser/autocomplete/autocomplete_match.h"
14 #include "chrome/browser/autocomplete/autocomplete_popup_model.h"
15 #include "chrome/browser/command_updater.h"
16 #include "chrome/browser/tab_contents/tab_contents.h"
17 #include "chrome/browser/ui/views/autocomplete/autocomplete_popup_contents_view. h"
18 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
19 #include "chrome/common/notification_service.h"
20 #include "gfx/font.h"
21 #include "googleurl/src/gurl.h"
22 #include "grit/generated_resources.h"
23 #include "net/base/escape.h"
24 #include "views/border.h"
25 #include "views/fill_layout.h"
26
27 namespace {
28
29 // Textfield for autocomplete that intercepts events that are necessary
30 // for AutocompleteEditViewViews.
31 class AutocompleteTextfield : public views::Textfield {
32 public:
33 explicit AutocompleteTextfield(
34 AutocompleteEditViewViews* autocomplete_edit_view)
35 : views::Textfield(views::Textfield::STYLE_DEFAULT),
36 autocomplete_edit_view_(autocomplete_edit_view) {
37 DCHECK(autocomplete_edit_view_);
38 RemoveBorder();
39 }
40
41 // views::View implementation
42 virtual void DidGainFocus() {
43 views::Textfield::DidGainFocus();
44 autocomplete_edit_view_->HandleFocusIn();
45 }
46
47 virtual void WillLoseFocus() {
48 views::Textfield::WillLoseFocus();
49 autocomplete_edit_view_->HandleFocusOut();
50 }
51
52 virtual bool OnKeyPressed(const views::KeyEvent& e) {
53 bool handled = views::Textfield::OnKeyPressed(e);
54 return autocomplete_edit_view_->HandleAfterKeyEvent(e, handled) || handled;
55 }
56
57 virtual bool OnKeyReleased(const views::KeyEvent& e) {
58 return autocomplete_edit_view_->HandleKeyReleaseEvent(e);
59 }
60
61 virtual bool IsFocusable() const {
62 // Bypass Textfield::IsFocusable. The omnibox in popup window requires
63 // focus in order for text selection to work.
64 return views::View::IsFocusable();
65 }
66
67 private:
68 AutocompleteEditViewViews* autocomplete_edit_view_;
69
70 DISALLOW_COPY_AND_ASSIGN(AutocompleteTextfield);
71 };
72
73 // Stores omnibox state for each tab.
74 struct ViewState {
75 explicit ViewState(const views::TextRange& selection_range)
76 : selection_range(selection_range) {
77 }
78
79 // Range of selected text.
80 views::TextRange selection_range;
81 };
82
83 struct AutocompleteEditState {
84 AutocompleteEditState(const AutocompleteEditModel::State& model_state,
85 const ViewState& view_state)
86 : model_state(model_state),
87 view_state(view_state) {
88 }
89
90 const AutocompleteEditModel::State model_state;
91 const ViewState view_state;
92 };
93
94 // Returns a lazily initialized property bag accessor for saving our state in a
95 // TabContents.
96 PropertyAccessor<AutocompleteEditState>* GetStateAccessor() {
97 static PropertyAccessor<AutocompleteEditState> state;
98 return &state;
99 }
100
101 const int kAutocompleteVerticalMargin = 4;
102
103 } // namespace
104
105 AutocompleteEditViewViews::AutocompleteEditViewViews(
106 AutocompleteEditController* controller,
107 ToolbarModel* toolbar_model,
108 Profile* profile,
109 CommandUpdater* command_updater,
110 bool popup_window_mode,
111 const views::View* location_bar)
112 : model_(new AutocompleteEditModel(this, controller, profile)),
113 popup_view_(new AutocompletePopupContentsView(
114 gfx::Font(), this, model_.get(), profile, location_bar)),
115 controller_(controller),
116 toolbar_model_(toolbar_model),
117 command_updater_(command_updater),
118 popup_window_mode_(popup_window_mode),
119 security_level_(ToolbarModel::NONE),
120 delete_was_pressed_(false),
121 delete_at_end_pressed_(false) {
122 model_->SetPopupModel(popup_view_->GetModel());
123 set_border(views::Border::CreateEmptyBorder(kAutocompleteVerticalMargin, 0,
124 kAutocompleteVerticalMargin, 0));
125 }
126
127 AutocompleteEditViewViews::~AutocompleteEditViewViews() {
128 NotificationService::current()->Notify(
129 NotificationType::AUTOCOMPLETE_EDIT_DESTROYED,
130 Source<AutocompleteEditViewViews>(this),
131 NotificationService::NoDetails());
132 // Explicitly teardown members which have a reference to us. Just to be safe
133 // we want them to be destroyed before destroying any other internal state.
134 popup_view_.reset();
135 model_.reset();
136 }
137
138 ////////////////////////////////////////////////////////////////////////////////
139 // AutocompleteEditViewViews public:
140
141 void AutocompleteEditViewViews::Init() {
142 // The height of the text view is going to change based on the font used. We
143 // don't want to stretch the height, and we want it vertically centered.
144 // TODO(oshima): make sure the above happens with views.
145 textfield_ = new AutocompleteTextfield(this);
146 textfield_->SetController(this);
147
148 if (popup_window_mode_)
149 textfield_->SetReadOnly(true);
150
151 // Manually invoke SetBaseColor() because TOOLKIT_VIEWS doesn't observe
152 // themes.
153 SetBaseColor();
154 }
155
156 void AutocompleteEditViewViews::SetBaseColor() {
157 // TODO(oshima): Implment style change.
158 NOTIMPLEMENTED();
159 }
160
161 bool AutocompleteEditViewViews::HandleAfterKeyEvent(
162 const views::KeyEvent& event,
163 bool handled) {
164 handling_key_press_ = false;
165 if (content_maybe_changed_by_key_press_)
166 OnAfterPossibleChange();
167
168 if (event.GetKeyCode() == ui::VKEY_RETURN) {
169 bool alt_held = event.IsAltDown();
170 model_->AcceptInput(alt_held ? NEW_FOREGROUND_TAB : CURRENT_TAB, false);
171 handled = true;
172 } else if (!handled && event.GetKeyCode() == ui::VKEY_ESCAPE) {
173 // We can handle the Escape key if textfield did not handle it.
174 // If it's not handled by us, then we need to propagate it up to the parent
175 // widgets, so that Escape accelerator can still work.
176 handled = model_->OnEscapeKeyPressed();
177 } else if (event.GetKeyCode() == ui::VKEY_CONTROL) {
178 // Omnibox2 can switch its contents while pressing a control key. To switch
179 // the contents of omnibox2, we notify the AutocompleteEditModel class when
180 // the control-key state is changed.
181 model_->OnControlKeyChanged(true);
182 } else if (!text_changed_ && event.GetKeyCode() == ui::VKEY_DELETE &&
183 event.IsShiftDown()) {
184 // If shift+del didn't change the text, we let this delete an entry from
185 // the popup. We can't check to see if the IME handled it because even if
186 // nothing is selected, the IME or the TextView still report handling it.
187 AutocompletePopupModel* popup_model = popup_view_->GetModel();
188 if (popup_model->IsOpen())
189 popup_model->TryDeletingCurrentItem();
190 } else if (!handled && event.GetKeyCode() == ui::VKEY_UP) {
191 model_->OnUpOrDownKeyPressed(-1);
192 handled = true;
193 } else if (!handled && event.GetKeyCode() == ui::VKEY_DOWN) {
194 model_->OnUpOrDownKeyPressed(1);
195 handled = true;
196 } else if (!handled &&
197 event.GetKeyCode() == ui::VKEY_TAB &&
198 !event.IsShiftDown() &&
199 !event.IsControlDown()) {
200 if (model_->is_keyword_hint() && !model_->keyword().empty()) {
201 model_->AcceptKeyword();
202 handled = true;
203 } else {
204 // TODO(Oshima): handle instant
205 }
206 }
207 // TODO(oshima): page up & down
208
209 return handled;
210 }
211
212 bool AutocompleteEditViewViews::HandleKeyReleaseEvent(
213 const views::KeyEvent& event) {
214 // Omnibox2 can switch its contents while pressing a control key. To switch
215 // the contents of omnibox2, we notify the AutocompleteEditModel class when
216 // the control-key state is changed.
217 if (event.GetKeyCode() == ui::VKEY_CONTROL) {
218 // TODO(oshima): investigate if we need to support keyboard with two
219 // controls. See autocomplete_edit_view_gtk.cc.
220 model_->OnControlKeyChanged(false);
221 return true;
222 }
223 return false;
224 }
225
226 void AutocompleteEditViewViews::HandleFocusIn() {
227 // TODO(oshima): Get control key state.
228 model_->OnSetFocus(false);
229 // Don't call controller_->OnSetFocus as this view has already
230 // acquired the focus.
231 }
232
233 void AutocompleteEditViewViews::HandleFocusOut() {
234 // TODO(oshima): we don't have native view. This requires
235 // further refactoring.
236 controller_->OnAutocompleteLosingFocus(NULL);
237 // Close the popup.
238 ClosePopup();
239 // Tell the model to reset itself.
240 model_->OnKillFocus();
241 controller_->OnKillFocus();
242 }
243
244 ////////////////////////////////////////////////////////////////////////////////
245 // AutocompleteEditViewViews, views::View implementation:
246
247 bool AutocompleteEditViewViews::OnMousePressed(
248 const views::MouseEvent& event) {
249 if (event.IsLeftMouseButton()) {
250 // Button press event may change the selection, we need to record the change
251 // and report it to |model_| later when button is released.
252 OnBeforePossibleChange();
253 }
254 // Pass the event through to TextfieldViews.
255 return false;
256 }
257
258 void AutocompleteEditViewViews::Layout() {
259 gfx::Insets insets = GetInsets();
260 textfield_->SetBounds(insets.left(), insets.top(),
261 width() - insets.width(),
262 height() - insets.height());
263 }
264
265 ////////////////////////////////////////////////////////////////////////////////
266 // AutocompleteEditViewViews, AutocopmleteEditView implementation:
267
268 AutocompleteEditModel* AutocompleteEditViewViews::model() {
269 return model_.get();
270 }
271
272 const AutocompleteEditModel* AutocompleteEditViewViews::model() const {
273 return model_.get();
274 }
275
276 void AutocompleteEditViewViews::SaveStateToTab(TabContents* tab) {
277 DCHECK(tab);
278
279 // NOTE: GetStateForTabSwitch may affect GetSelection, so order is important.
280 AutocompleteEditModel::State model_state = model_->GetStateForTabSwitch();
281 views::TextRange selection;
282 textfield_->GetSelectedRange(&selection);
283 GetStateAccessor()->SetProperty(
284 tab->property_bag(),
285 AutocompleteEditState(model_state, ViewState(selection)));
286 }
287
288 void AutocompleteEditViewViews::Update(const TabContents* contents) {
289 // NOTE: We're getting the URL text here from the ToolbarModel.
290 bool visibly_changed_permanent_text =
291 model_->UpdatePermanentText(toolbar_model_->GetText());
292
293 ToolbarModel::SecurityLevel security_level =
294 toolbar_model_->GetSecurityLevel();
295 bool changed_security_level = (security_level != security_level_);
296 security_level_ = security_level;
297
298 // TODO(oshima): Copied from gtk implementation which is
299 // slightly different from WIN impl. Find out the correct implementation
300 // for views-implementation.
301 if (contents) {
302 RevertAll();
303 const AutocompleteEditState* state =
304 GetStateAccessor()->GetProperty(contents->property_bag());
305 if (state) {
306 model_->RestoreState(state->model_state);
307
308 // Move the marks for the cursor and the other end of the selection to
309 // the previously-saved offsets (but preserve PRIMARY).
310 textfield_->SelectRange(state->view_state.selection_range);
311 }
312 } else if (visibly_changed_permanent_text) {
313 RevertAll();
314 } else if (changed_security_level) {
315 EmphasizeURLComponents();
316 }
317 }
318
319 void AutocompleteEditViewViews::OpenURL(const GURL& url,
320 WindowOpenDisposition disposition,
321 PageTransition::Type transition,
322 const GURL& alternate_nav_url,
323 size_t selected_line,
324 const std::wstring& keyword) {
325 if (!url.is_valid())
326 return;
327
328 model_->OpenURL(url, disposition, transition, alternate_nav_url,
329 selected_line, keyword);
330 }
331
332 std::wstring AutocompleteEditViewViews::GetText() const {
333 // TODO(oshima): IME support
334 return UTF16ToWide(textfield_->text());
335 }
336
337 bool AutocompleteEditViewViews::IsEditingOrEmpty() const {
338 return model_->user_input_in_progress() || (GetTextLength() == 0);
339 }
340
341 int AutocompleteEditViewViews::GetIcon() const {
342 return IsEditingOrEmpty() ?
343 AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) :
344 toolbar_model_->GetIcon();
345 }
346
347 void AutocompleteEditViewViews::SetUserText(const std::wstring& text) {
348 SetUserText(text, text, true);
349 }
350
351 void AutocompleteEditViewViews::SetUserText(const std::wstring& text,
352 const std::wstring& display_text,
353 bool update_popup) {
354 model_->SetUserText(text);
355 SetWindowTextAndCaretPos(display_text, display_text.length());
356 if (update_popup)
357 UpdatePopup();
358 TextChanged();
359 }
360
361 void AutocompleteEditViewViews::SetWindowTextAndCaretPos(
362 const std::wstring& text,
363 size_t caret_pos) {
364 const views::TextRange range(caret_pos, caret_pos);
365 SetTextAndSelectedRange(text, range);
366 }
367
368 void AutocompleteEditViewViews::SetForcedQuery() {
369 const std::wstring current_text(GetText());
370 const size_t start = current_text.find_first_not_of(kWhitespaceWide);
371 if (start == std::wstring::npos || (current_text[start] != '?')) {
372 SetUserText(L"?");
373 } else {
374 SelectRange(current_text.size(), start + 1);
375 }
376 }
377
378 bool AutocompleteEditViewViews::IsSelectAll() {
379 // TODO(oshima): IME support.
380 return textfield_->text() == textfield_->GetSelectedText();
381 }
382
383 bool AutocompleteEditViewViews::DeleteAtEndPressed() {
384 return delete_at_end_pressed_;
385 }
386
387 void AutocompleteEditViewViews::GetSelectionBounds(
388 std::wstring::size_type* start,
389 std::wstring::size_type* end) {
390 views::TextRange range;
391 textfield_->GetSelectedRange(&range);
392 *start = static_cast<size_t>(range.end());
393 *end = static_cast<size_t>(range.start());
394 }
395
396 void AutocompleteEditViewViews::SelectAll(bool reversed) {
397 if (reversed)
398 SelectRange(GetTextLength(), 0);
399 else
400 SelectRange(0, GetTextLength());
401 }
402
403 void AutocompleteEditViewViews::RevertAll() {
404 ClosePopup();
405 model_->Revert();
406 TextChanged();
407 }
408
409 void AutocompleteEditViewViews::UpdatePopup() {
410 model_->SetInputInProgress(true);
411 if (!model_->has_focus())
412 return;
413
414 // Don't inline autocomplete when the caret/selection isn't at the end of
415 // the text, or in the middle of composition.
416 views::TextRange sel;
417 textfield_->GetSelectedRange(&sel);
418 bool no_inline_autocomplete = sel.GetMax() < GetTextLength();
419
420 // TODO(oshima): Support IME. Don't show autocomplete if IME has some text.
421 model_->StartAutocomplete(!sel.is_empty(), no_inline_autocomplete);
422 }
423
424 void AutocompleteEditViewViews::ClosePopup() {
425 if (popup_view_->GetModel()->IsOpen())
426 controller_->OnAutocompleteWillClosePopup();
427
428 popup_view_->GetModel()->StopAutocomplete();
429 }
430
431 void AutocompleteEditViewViews::SetFocus() {
432 // In views-implementation, the focus is on textfield rather than
433 // AutocompleteEditView.
434 textfield_->RequestFocus();
435 }
436
437 void AutocompleteEditViewViews::OnTemporaryTextMaybeChanged(
438 const std::wstring& display_text,
439 bool save_original_selection) {
440 if (save_original_selection)
441 textfield_->GetSelectedRange(&saved_temporary_selection_);
442
443 SetWindowTextAndCaretPos(display_text, display_text.length());
444 TextChanged();
445 }
446
447 bool AutocompleteEditViewViews::OnInlineAutocompleteTextMaybeChanged(
448 const std::wstring& display_text,
449 size_t user_text_length) {
450 if (display_text == GetText())
451 return false;
452 views::TextRange range(display_text.size(), user_text_length);
453 SetTextAndSelectedRange(display_text, range);
454 TextChanged();
455 return true;
456 }
457
458 void AutocompleteEditViewViews::OnRevertTemporaryText() {
459 textfield_->SelectRange(saved_temporary_selection_);
460 TextChanged();
461 }
462
463 void AutocompleteEditViewViews::OnBeforePossibleChange() {
464 // Record our state.
465 text_before_change_ = GetText();
466 textfield_->GetSelectedRange(&sel_before_change_);
467 }
468
469 bool AutocompleteEditViewViews::OnAfterPossibleChange() {
470 // OnAfterPossibleChange should be called once per modification,
471 // and we should ignore if this is called while a key event is being handled
472 // because OnAfterPossibleChagne will be called after the key event is
473 // actually handled.
474 if (handling_key_press_) {
475 content_maybe_changed_by_key_press_ = true;
476 return false;
477 }
478 views::TextRange new_sel;
479 textfield_->GetSelectedRange(&new_sel);
480
481 size_t length = GetTextLength();
482 bool at_end_of_edit = (new_sel.start() == length && new_sel.end() == length);
483
484 // See if the text or selection have changed since OnBeforePossibleChange().
485 std::wstring new_text = GetText();
486 text_changed_ = (new_text != text_before_change_);
487 bool selection_differs = !sel_before_change_.Equals(new_sel);
488
489 // When the user has deleted text, we don't allow inline autocomplete. Make
490 // sure to not flag cases like selecting part of the text and then pasting
491 // (or typing) the prefix of that selection. (We detect these by making
492 // sure the caret, which should be after any insertion, hasn't moved
493 // forward of the old selection start.)
494 bool just_deleted_text =
495 (text_before_change_.length() > new_text.length()) &&
496 (new_sel.start() <= sel_before_change_.GetMin());
497
498 delete_at_end_pressed_ = false;
499
500 bool something_changed = model_->OnAfterPossibleChange(new_text,
501 selection_differs, text_changed_, just_deleted_text, at_end_of_edit);
502
503 // If only selection was changed, we don't need to call |controller_|'s
504 // OnChanged() method, which is called in TextChanged().
505 // But we still need to call EmphasizeURLComponents() to make sure the text
506 // attributes are updated correctly.
507 if (something_changed && text_changed_) {
508 TextChanged();
509 } else if (selection_differs) {
510 EmphasizeURLComponents();
511 } else if (delete_was_pressed_ && at_end_of_edit) {
512 delete_at_end_pressed_ = true;
513 controller_->OnChanged();
514 }
515 delete_was_pressed_ = false;
516
517 return something_changed;
518 }
519
520 gfx::NativeView AutocompleteEditViewViews::GetNativeView() const {
521 return GetWidget()->GetNativeView();
522 }
523
524 CommandUpdater* AutocompleteEditViewViews::GetCommandUpdater() {
525 return command_updater_;
526 }
527
528 views::View* AutocompleteEditViewViews::AddToView(views::View* parent) {
529 parent->AddChildView(this);
530 AddChildView(textfield_);
531 return this;
532 }
533
534 int AutocompleteEditViewViews::TextWidth() const {
535 // TODO(oshima): add horizontal margin.
536 return textfield_->font().GetStringWidth(textfield_->text());
537 }
538
539 bool AutocompleteEditViewViews::IsImeComposing() const {
540 return false;
541 }
542
543 bool AutocompleteEditViewViews::CommitInstantSuggestion(
544 const std::wstring& typed_text,
545 const std::wstring& suggested_text) {
546 model_->FinalizeInstantQuery(typed_text, suggested_text);
547 return true;
548 }
549
550 void AutocompleteEditViewViews::SetInstantSuggestion(const string16& input) {
551 NOTIMPLEMENTED();
552 }
553
554 ////////////////////////////////////////////////////////////////////////////////
555 // AutocompleteEditViewViews, NotificationObserver implementation:
556
557 void AutocompleteEditViewViews::Observe(NotificationType type,
558 const NotificationSource& source,
559 const NotificationDetails& details) {
560 DCHECK(type == NotificationType::BROWSER_THEME_CHANGED);
561 SetBaseColor();
562 }
563
564 ////////////////////////////////////////////////////////////////////////////////
565 // AutocompleteEditViewViews, Textfield::Controller implementation:
566
567 void AutocompleteEditViewViews::ContentsChanged(views::Textfield* sender,
568 const string16& new_contents) {
569 if (handling_key_press_)
570 content_maybe_changed_by_key_press_ = true;
571 }
572
573 bool AutocompleteEditViewViews::HandleKeyEvent(
574 views::Textfield* textfield,
575 const views::KeyEvent& event) {
576 delete_was_pressed_ = event.GetKeyCode() == ui::VKEY_DELETE;
577
578 // Reset |text_changed_| before passing the key event on to the text view.
579 text_changed_ = false;
580 OnBeforePossibleChange();
581 handling_key_press_ = true;
582 content_maybe_changed_by_key_press_ = false;
583
584 if (event.GetKeyCode() == ui::VKEY_BACK) {
585 // Checks if it's currently in keyword search mode.
586 if (model_->is_keyword_hint() || model_->keyword().empty())
587 return false;
588 // If there is selection, let textfield handle the backspace.
589 if (!textfield_->GetSelectedText().empty())
590 return false;
591 // If not at the begining of the text, let textfield handle the backspace.
592 if (textfield_->GetCursorPosition())
593 return false;
594 model_->ClearKeyword(GetText());
595 return true;
596 }
597
598 return false;
599 }
600
601 ////////////////////////////////////////////////////////////////////////////////
602 // AutocompleteEditViewViews, private:
603
604 size_t AutocompleteEditViewViews::GetTextLength() const {
605 // TODO(oshima): Support instant, IME.
606 return textfield_->text().length();
607 }
608
609 void AutocompleteEditViewViews::EmphasizeURLComponents() {
610 // TODO(oshima): Update URL visual style
611 NOTIMPLEMENTED();
612 }
613
614 void AutocompleteEditViewViews::TextChanged() {
615 EmphasizeURLComponents();
616 controller_->OnChanged();
617 }
618
619 void AutocompleteEditViewViews::SetTextAndSelectedRange(
620 const std::wstring& text,
621 const views::TextRange& range) {
622 if (text != GetText())
623 textfield_->SetText(WideToUTF16(text));
624 textfield_->SelectRange(range);
625 }
626
627 string16 AutocompleteEditViewViews::GetSelectedText() const {
628 // TODO(oshima): Support instant, IME.
629 return textfield_->GetSelectedText();
630 }
631
632 void AutocompleteEditViewViews::SelectRange(size_t caret, size_t end) {
633 const views::TextRange range(caret, end);
634 textfield_->SelectRange(range);
635 }
OLDNEW
« no previous file with comments | « chrome/browser/autocomplete/autocomplete_edit_view_views.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698