OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/omnibox/omnibox_view_win.h" | 5 #include "chrome/browser/ui/views/omnibox/omnibox_view_win.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <locale> | 8 #include <locale> |
9 #include <string> | 9 #include <string> |
10 | 10 |
(...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 | 432 |
433 } // namespace | 433 } // namespace |
434 | 434 |
435 OmniboxViewWin::OmniboxViewWin(OmniboxEditController* controller, | 435 OmniboxViewWin::OmniboxViewWin(OmniboxEditController* controller, |
436 ToolbarModel* toolbar_model, | 436 ToolbarModel* toolbar_model, |
437 LocationBarView* parent_view, | 437 LocationBarView* parent_view, |
438 CommandUpdater* command_updater, | 438 CommandUpdater* command_updater, |
439 bool popup_window_mode, | 439 bool popup_window_mode, |
440 views::View* location_bar, | 440 views::View* location_bar, |
441 views::View* popup_parent_view) | 441 views::View* popup_parent_view) |
442 : model_(new OmniboxEditModel(this, controller, parent_view->profile())), | 442 : OmniboxView(parent_view->profile(), controller, toolbar_model, |
443 command_updater), | |
443 popup_view_(OmniboxPopupContentsView::Create( | 444 popup_view_(OmniboxPopupContentsView::Create( |
444 parent_view->font(), this, model_.get(), location_bar, | 445 parent_view->font(), this, model_.get(), location_bar, |
445 popup_parent_view)), | 446 popup_parent_view)), |
446 controller_(controller), | |
447 parent_view_(parent_view), | 447 parent_view_(parent_view), |
448 toolbar_model_(toolbar_model), | |
449 command_updater_(command_updater), | |
450 popup_window_mode_(popup_window_mode), | 448 popup_window_mode_(popup_window_mode), |
451 force_hidden_(false), | 449 force_hidden_(false), |
452 tracking_click_(), | 450 tracking_click_(), |
453 tracking_double_click_(false), | 451 tracking_double_click_(false), |
454 double_click_time_(0), | 452 double_click_time_(0), |
455 can_discard_mousemove_(false), | 453 can_discard_mousemove_(false), |
456 ignore_ime_messages_(false), | 454 ignore_ime_messages_(false), |
457 delete_at_end_pressed_(false), | 455 delete_at_end_pressed_(false), |
458 font_(parent_view->font()), | 456 font_(parent_view->font()), |
459 possible_drag_(false), | 457 possible_drag_(false), |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
621 } else if (changed_security_level) { | 619 } else if (changed_security_level) { |
622 // Only the security style changed, nothing else. Redraw our text using it. | 620 // Only the security style changed, nothing else. Redraw our text using it. |
623 EmphasizeURLComponents(); | 621 EmphasizeURLComponents(); |
624 } | 622 } |
625 } | 623 } |
626 | 624 |
627 void OmniboxViewWin::OpenMatch(const AutocompleteMatch& match, | 625 void OmniboxViewWin::OpenMatch(const AutocompleteMatch& match, |
628 WindowOpenDisposition disposition, | 626 WindowOpenDisposition disposition, |
629 const GURL& alternate_nav_url, | 627 const GURL& alternate_nav_url, |
630 size_t selected_line) { | 628 size_t selected_line) { |
631 if (!match.destination_url.is_valid()) | |
632 return; | |
633 | |
634 // When we navigate, we first revert to the unedited state, then if necessary | 629 // When we navigate, we first revert to the unedited state, then if necessary |
635 // synchronously change the permanent text to the new URL. If we don't freeze | 630 // synchronously change the permanent text to the new URL. If we don't freeze |
636 // here, the user could potentially see a flicker of the current URL before | 631 // here, the user could potentially see a flicker of the current URL before |
637 // the new one reappears, which would look glitchy. | 632 // the new one reappears, which would look glitchy. |
638 ScopedFreeze freeze(this, GetTextObjectModel()); | 633 ScopedFreeze freeze(this, GetTextObjectModel()); |
639 model_->OpenMatch(match, disposition, alternate_nav_url, selected_line); | 634 OmniboxView::OpenMatch(match, disposition, alternate_nav_url, selected_line); |
640 } | 635 } |
641 | 636 |
642 string16 OmniboxViewWin::GetText() const { | 637 string16 OmniboxViewWin::GetText() const { |
643 const int len = GetTextLength() + 1; | 638 const int len = GetTextLength() + 1; |
644 string16 str; | 639 string16 str; |
645 if (len > 1) | 640 if (len > 1) |
646 GetWindowText(WriteInto(&str, len), len); | 641 GetWindowText(WriteInto(&str, len), len); |
647 return str; | 642 return str; |
648 } | 643 } |
649 | 644 |
650 bool OmniboxViewWin::IsEditingOrEmpty() const { | |
651 return model_->user_input_in_progress() || (GetTextLength() == 0); | |
652 } | |
653 | |
654 int OmniboxViewWin::GetIcon() const { | |
655 return IsEditingOrEmpty() ? | |
656 AutocompleteMatch::TypeToIcon(model_->CurrentTextType()) : | |
657 toolbar_model_->GetIcon(); | |
658 } | |
659 | |
660 void OmniboxViewWin::SetUserText(const string16& text) { | |
661 SetUserText(text, text, true); | |
662 } | |
663 | |
664 void OmniboxViewWin::SetUserText(const string16& text, | 645 void OmniboxViewWin::SetUserText(const string16& text, |
665 const string16& display_text, | 646 const string16& display_text, |
666 bool update_popup) { | 647 bool update_popup) { |
667 ScopedFreeze freeze(this, GetTextObjectModel()); | 648 ScopedFreeze freeze(this, GetTextObjectModel()); |
668 model_->SetUserText(text); | |
669 saved_selection_for_focus_change_.cpMin = -1; | 649 saved_selection_for_focus_change_.cpMin = -1; |
670 SetWindowTextAndCaretPos(display_text, display_text.length(), update_popup, | 650 OmniboxView::SetUserText(text, display_text, update_popup); |
671 true); | |
672 } | 651 } |
673 | 652 |
674 void OmniboxViewWin::SetWindowTextAndCaretPos(const string16& text, | 653 void OmniboxViewWin::SetWindowTextAndCaretPos(const string16& text, |
675 size_t caret_pos, | 654 size_t caret_pos, |
676 bool update_popup, | 655 bool update_popup, |
677 bool notify_text_changed) { | 656 bool notify_text_changed) { |
678 SetWindowText(text.c_str()); | 657 SetWindowText(text.c_str()); |
679 PlaceCaretAt(caret_pos); | 658 PlaceCaretAt(caret_pos); |
680 | 659 |
681 if (update_popup) | 660 if (update_popup) |
682 UpdatePopup(); | 661 UpdatePopup(); |
683 | 662 |
684 if (notify_text_changed) | 663 if (notify_text_changed) |
685 TextChanged(); | 664 TextChanged(); |
686 } | 665 } |
687 | 666 |
688 void OmniboxViewWin::SetForcedQuery() { | 667 void OmniboxViewWin::SetForcedQuery() { |
689 const string16 current_text(GetText()); | 668 const string16 current_text(GetText()); |
690 const size_t start = current_text.find_first_not_of(kWhitespaceWide); | 669 const size_t start = current_text.find_first_not_of(kWhitespaceWide); |
691 if (start == string16::npos || (current_text[start] != '?')) | 670 if (start == string16::npos || (current_text[start] != '?')) |
692 SetUserText(L"?"); | 671 OmniboxView::SetUserText(L"?"); |
Peter Kasting
2012/07/26 03:59:17
Why is this a direct superclass call? That change
dominich
2012/07/26 22:33:24
There is no version in the derived class that take
Peter Kasting
2012/07/26 23:03:24
Oh, and scope resolution requires that we qualify
| |
693 else | 672 else |
694 SetSelection(current_text.length(), start + 1); | 673 SetSelection(current_text.length(), start + 1); |
695 } | 674 } |
696 | 675 |
697 bool OmniboxViewWin::IsSelectAll() const { | 676 bool OmniboxViewWin::IsSelectAll() const { |
698 CHARRANGE selection; | 677 CHARRANGE selection; |
699 GetSel(selection); | 678 GetSel(selection); |
700 return IsSelectAllForRange(selection); | 679 return IsSelectAllForRange(selection); |
701 } | 680 } |
702 | 681 |
(...skipping 11 matching lines...) Expand all Loading... | |
714 | 693 |
715 void OmniboxViewWin::SelectAll(bool reversed) { | 694 void OmniboxViewWin::SelectAll(bool reversed) { |
716 if (reversed) | 695 if (reversed) |
717 SetSelection(GetTextLength(), 0); | 696 SetSelection(GetTextLength(), 0); |
718 else | 697 else |
719 SetSelection(0, GetTextLength()); | 698 SetSelection(0, GetTextLength()); |
720 } | 699 } |
721 | 700 |
722 void OmniboxViewWin::RevertAll() { | 701 void OmniboxViewWin::RevertAll() { |
723 ScopedFreeze freeze(this, GetTextObjectModel()); | 702 ScopedFreeze freeze(this, GetTextObjectModel()); |
724 ClosePopup(); | |
725 saved_selection_for_focus_change_.cpMin = -1; | 703 saved_selection_for_focus_change_.cpMin = -1; |
726 model_->Revert(); | 704 OmniboxView::RevertAll(); |
727 } | 705 } |
728 | 706 |
729 void OmniboxViewWin::UpdatePopup() { | 707 void OmniboxViewWin::UpdatePopup() { |
730 ScopedFreeze freeze(this, GetTextObjectModel()); | 708 ScopedFreeze freeze(this, GetTextObjectModel()); |
731 model_->SetInputInProgress(true); | 709 model_->SetInputInProgress(true); |
732 | 710 |
733 // Don't allow the popup to open while the candidate window is open, so | 711 // Don't allow the popup to open while the candidate window is open, so |
734 // they don't overlap. | 712 // they don't overlap. |
735 if (ime_candidate_window_open_) | 713 if (ime_candidate_window_open_) |
736 return; | 714 return; |
(...skipping 14 matching lines...) Expand all Loading... | |
751 // * The user is deleting text | 729 // * The user is deleting text |
752 // * The caret/selection isn't at the end of the text | 730 // * The caret/selection isn't at the end of the text |
753 // * The user has just pasted in something that replaced all the text | 731 // * The user has just pasted in something that replaced all the text |
754 // * The user is trying to compose something in an IME | 732 // * The user is trying to compose something in an IME |
755 CHARRANGE sel; | 733 CHARRANGE sel; |
756 GetSel(sel); | 734 GetSel(sel); |
757 model_->StartAutocomplete(sel.cpMax != sel.cpMin, | 735 model_->StartAutocomplete(sel.cpMax != sel.cpMin, |
758 (sel.cpMax < GetTextLength()) || IsImeComposing()); | 736 (sel.cpMax < GetTextLength()) || IsImeComposing()); |
759 } | 737 } |
760 | 738 |
761 void OmniboxViewWin::ClosePopup() { | |
762 model_->StopAutocomplete(); | |
763 } | |
764 | |
765 void OmniboxViewWin::SetFocus() { | 739 void OmniboxViewWin::SetFocus() { |
766 ::SetFocus(m_hWnd); | 740 ::SetFocus(m_hWnd); |
767 } | 741 } |
768 | 742 |
769 void OmniboxViewWin::SetDropHighlightPosition(int position) { | 743 void OmniboxViewWin::SetDropHighlightPosition(int position) { |
770 if (drop_highlight_position_ != position) { | 744 if (drop_highlight_position_ != position) { |
771 RepaintDropHighlight(drop_highlight_position_); | 745 RepaintDropHighlight(drop_highlight_position_); |
772 drop_highlight_position_ = position; | 746 drop_highlight_position_ = position; |
773 RepaintDropHighlight(drop_highlight_position_); | 747 RepaintDropHighlight(drop_highlight_position_); |
774 } | 748 } |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
934 // TODO(hbono): http://b/1111369 if we exclude this popup window from the | 908 // TODO(hbono): http://b/1111369 if we exclude this popup window from the |
935 // display area of IME windows, this workaround becomes unnecessary. | 909 // display area of IME windows, this workaround becomes unnecessary. |
936 HWND ime_window = ImmGetDefaultIMEWnd(edit_native_view); | 910 HWND ime_window = ImmGetDefaultIMEWnd(edit_native_view); |
937 return ime_window ? ime_window : HWND_NOTOPMOST; | 911 return ime_window ? ime_window : HWND_NOTOPMOST; |
938 } | 912 } |
939 | 913 |
940 gfx::NativeView OmniboxViewWin::GetRelativeWindowForPopup() const { | 914 gfx::NativeView OmniboxViewWin::GetRelativeWindowForPopup() const { |
941 return GetRelativeWindowForNativeView(GetNativeView()); | 915 return GetRelativeWindowForNativeView(GetNativeView()); |
942 } | 916 } |
943 | 917 |
944 CommandUpdater* OmniboxViewWin::GetCommandUpdater() { | |
945 return command_updater_; | |
946 } | |
947 | |
948 void OmniboxViewWin::SetInstantSuggestion(const string16& suggestion, | 918 void OmniboxViewWin::SetInstantSuggestion(const string16& suggestion, |
949 bool animate_to_complete) { | 919 bool animate_to_complete) { |
950 parent_view_->SetInstantSuggestion(suggestion, animate_to_complete); | 920 parent_view_->SetInstantSuggestion(suggestion, animate_to_complete); |
951 } | 921 } |
952 | 922 |
953 int OmniboxViewWin::TextWidth() const { | 923 int OmniboxViewWin::TextWidth() const { |
954 return WidthNeededToDisplay(GetText()); | 924 return WidthNeededToDisplay(GetText()); |
955 } | 925 } |
956 | 926 |
957 string16 OmniboxViewWin::GetInstantSuggestion() const { | 927 string16 OmniboxViewWin::GetInstantSuggestion() const { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1003 | 973 |
1004 int OmniboxViewWin::OnPerformDropImpl(const views::DropTargetEvent& event, | 974 int OmniboxViewWin::OnPerformDropImpl(const views::DropTargetEvent& event, |
1005 bool in_drag) { | 975 bool in_drag) { |
1006 const ui::OSExchangeData& data = event.data(); | 976 const ui::OSExchangeData& data = event.data(); |
1007 | 977 |
1008 if (data.HasURL()) { | 978 if (data.HasURL()) { |
1009 GURL url; | 979 GURL url; |
1010 string16 title; | 980 string16 title; |
1011 if (data.GetURLAndTitle(&url, &title)) { | 981 if (data.GetURLAndTitle(&url, &title)) { |
1012 string16 text(StripJavascriptSchemas(UTF8ToUTF16(url.spec()))); | 982 string16 text(StripJavascriptSchemas(UTF8ToUTF16(url.spec()))); |
1013 SetUserText(text); | 983 OmniboxView::SetUserText(text); |
Peter Kasting
2012/07/26 03:59:17
Another case where I'm not sure why this is a supe
dominich
2012/07/26 22:33:24
see above. There shouldn't be a functional change
| |
1014 model()->AcceptInput(CURRENT_TAB, true); | 984 GetModel()->AcceptInput(CURRENT_TAB, true); |
1015 return CopyOrLinkDragOperation(event.source_operations()); | 985 return CopyOrLinkDragOperation(event.source_operations()); |
1016 } | 986 } |
1017 } else if (data.HasString()) { | 987 } else if (data.HasString()) { |
1018 int string_drop_position = drop_highlight_position(); | 988 int string_drop_position = drop_highlight_position(); |
1019 string16 text; | 989 string16 text; |
1020 if ((string_drop_position != -1 || !in_drag) && data.GetString(&text)) { | 990 if ((string_drop_position != -1 || !in_drag) && data.GetString(&text)) { |
1021 DCHECK(string_drop_position == -1 || | 991 DCHECK(string_drop_position == -1 || |
1022 ((string_drop_position >= 0) && | 992 ((string_drop_position >= 0) && |
1023 (string_drop_position <= GetTextLength()))); | 993 (string_drop_position <= GetTextLength()))); |
1024 if (in_drag) { | 994 if (in_drag) { |
(...skipping 1229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2254 // the end of the text, but triple-click will still work. | 2224 // the end of the text, but triple-click will still work. |
2255 if (x < left_bound) { | 2225 if (x < left_bound) { |
2256 return (is_triple_click && ltr_text_in_ltr_layout) ? left_bound - 1 : | 2226 return (is_triple_click && ltr_text_in_ltr_layout) ? left_bound - 1 : |
2257 left_bound; | 2227 left_bound; |
2258 } | 2228 } |
2259 if ((length == 0) || (x < right_bound)) | 2229 if ((length == 0) || (x < right_bound)) |
2260 return x; | 2230 return x; |
2261 return is_triple_click ? (right_bound - 1) : right_bound; | 2231 return is_triple_click ? (right_bound - 1) : right_bound; |
2262 } | 2232 } |
2263 | 2233 |
2234 int OmniboxViewWin::GetOmniboxTextLength() const { | |
2235 return static_cast<int>(GetTextLength()); | |
2236 } | |
2237 | |
2264 void OmniboxViewWin::EmphasizeURLComponents() { | 2238 void OmniboxViewWin::EmphasizeURLComponents() { |
2265 ITextDocument* const text_object_model = GetTextObjectModel(); | 2239 ITextDocument* const text_object_model = GetTextObjectModel(); |
2266 ScopedFreeze freeze(this, text_object_model); | 2240 ScopedFreeze freeze(this, text_object_model); |
2267 ScopedSuspendUndo suspend_undo(text_object_model); | 2241 ScopedSuspendUndo suspend_undo(text_object_model); |
2268 | 2242 |
2269 // Save the selection. | 2243 // Save the selection. |
2270 CHARRANGE saved_sel; | 2244 CHARRANGE saved_sel; |
2271 GetSelection(saved_sel); | 2245 GetSelection(saved_sel); |
2272 | 2246 |
2273 // See whether the contents are a URL with a non-empty host portion, which we | 2247 // See whether the contents are a URL with a non-empty host portion, which we |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2450 return; | 2424 return; |
2451 | 2425 |
2452 HGDIOBJ last_pen = SelectObject(hdc, CreatePen(PS_SOLID, 1, RGB(0, 0, 0))); | 2426 HGDIOBJ last_pen = SelectObject(hdc, CreatePen(PS_SOLID, 1, RGB(0, 0, 0))); |
2453 MoveToEx(hdc, clip_rect.left, clip_rect.top, NULL); | 2427 MoveToEx(hdc, clip_rect.left, clip_rect.top, NULL); |
2454 LineTo(hdc, clip_rect.left, clip_rect.bottom); | 2428 LineTo(hdc, clip_rect.left, clip_rect.bottom); |
2455 DeleteObject(SelectObject(hdc, last_pen)); | 2429 DeleteObject(SelectObject(hdc, last_pen)); |
2456 } | 2430 } |
2457 | 2431 |
2458 void OmniboxViewWin::TextChanged() { | 2432 void OmniboxViewWin::TextChanged() { |
2459 ScopedFreeze freeze(this, GetTextObjectModel()); | 2433 ScopedFreeze freeze(this, GetTextObjectModel()); |
2460 EmphasizeURLComponents(); | 2434 OmniboxView::TextChanged(); |
2461 model_->OnChanged(); | |
2462 } | 2435 } |
2463 | 2436 |
2464 ITextDocument* OmniboxViewWin::GetTextObjectModel() const { | 2437 ITextDocument* OmniboxViewWin::GetTextObjectModel() const { |
2465 if (!text_object_model_) { | 2438 if (!text_object_model_) { |
2466 // This is lazily initialized, instead of being initialized in the | 2439 // This is lazily initialized, instead of being initialized in the |
2467 // constructor, in order to avoid hurting startup performance. | 2440 // constructor, in order to avoid hurting startup performance. |
2468 base::win::ScopedComPtr<IRichEditOle, NULL> ole_interface; | 2441 base::win::ScopedComPtr<IRichEditOle, NULL> ole_interface; |
2469 ole_interface.Attach(GetOleInterface()); | 2442 ole_interface.Attach(GetOleInterface()); |
2470 if (ole_interface) { | 2443 if (ole_interface) { |
2471 ole_interface.QueryInterface( | 2444 ole_interface.QueryInterface( |
(...skipping 30 matching lines...) Expand all Loading... | |
2502 } | 2475 } |
2503 | 2476 |
2504 const string16 start_text(GetText()); | 2477 const string16 start_text(GetText()); |
2505 string16 text_to_write(GetSelectedText()); | 2478 string16 text_to_write(GetSelectedText()); |
2506 GURL url; | 2479 GURL url; |
2507 bool write_url; | 2480 bool write_url; |
2508 const bool is_all_selected = IsSelectAllForRange(sel); | 2481 const bool is_all_selected = IsSelectAllForRange(sel); |
2509 | 2482 |
2510 // |sel| was set by GetSelection(), which preserves selection direction, so | 2483 // |sel| was set by GetSelection(), which preserves selection direction, so |
2511 // sel.cpMin may not be the smaller value. | 2484 // sel.cpMin may not be the smaller value. |
2512 model()->AdjustTextForCopy(std::min(sel.cpMin, sel.cpMax), is_all_selected, | 2485 GetModel()->AdjustTextForCopy(std::min(sel.cpMin, sel.cpMax), is_all_selected, |
2513 &text_to_write, &url, &write_url); | 2486 &text_to_write, &url, &write_url); |
2514 | 2487 |
2515 if (write_url) { | 2488 if (write_url) { |
2516 string16 title; | 2489 string16 title; |
2517 SkBitmap favicon; | 2490 SkBitmap favicon; |
2518 if (is_all_selected) | 2491 if (is_all_selected) |
2519 model_->GetDataForURLExport(&url, &title, &favicon); | 2492 model_->GetDataForURLExport(&url, &title, &favicon); |
2520 button_drag_utils::SetURLAndDragImage(url, title, favicon, &data, | 2493 button_drag_utils::SetURLAndDragImage(url, title, favicon, &data, |
2521 native_view_host_->GetWidget()); | 2494 native_view_host_->GetWidget()); |
2522 supported_modes |= DROPEFFECT_LINK; | 2495 supported_modes |= DROPEFFECT_LINK; |
2523 content::RecordAction(UserMetricsAction("Omnibox_DragURL")); | 2496 content::RecordAction(UserMetricsAction("Omnibox_DragURL")); |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2659 return (rect.left - client_rect.left) + (client_rect.right - rect.right); | 2632 return (rect.left - client_rect.left) + (client_rect.right - rect.right); |
2660 } | 2633 } |
2661 | 2634 |
2662 int OmniboxViewWin::WidthNeededToDisplay(const string16& text) const { | 2635 int OmniboxViewWin::WidthNeededToDisplay(const string16& text) const { |
2663 // Use font_.GetStringWidth() instead of | 2636 // Use font_.GetStringWidth() instead of |
2664 // PosFromChar(location_entry_->GetTextLength()) because PosFromChar() is | 2637 // PosFromChar(location_entry_->GetTextLength()) because PosFromChar() is |
2665 // apparently buggy. In both LTR UI and RTL UI with left-to-right layout, | 2638 // apparently buggy. In both LTR UI and RTL UI with left-to-right layout, |
2666 // PosFromChar(i) might return 0 when i is greater than 1. | 2639 // PosFromChar(i) might return 0 when i is greater than 1. |
2667 return font_.GetStringWidth(text) + GetHorizontalMargin(); | 2640 return font_.GetStringWidth(text) + GetHorizontalMargin(); |
2668 } | 2641 } |
2669 | |
2670 bool OmniboxViewWin::IsCaretAtEnd() const { | |
2671 long length = GetTextLength(); | |
2672 CHARRANGE sel; | |
2673 GetSelection(sel); | |
2674 return sel.cpMin == sel.cpMax && sel.cpMin == length; | |
2675 } | |
OLD | NEW |