Skip to content

Commit

Permalink
First pass at splitting the AutocompleteEdit into Model and View. Thi…
Browse files Browse the repository at this point in the history
…s was noticeably harder than with the Popup and I'm not at all sure I've made the right decisions :(. The View code is about 3x larger than the model.

BUG=1343512
Review URL: http://codereview.chromium.org/1872

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2004 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
pkasting@chromium.org committed Sep 10, 2008
1 parent 8fbab00 commit 81c2122
Show file tree
Hide file tree
Showing 14 changed files with 1,576 additions and 1,307 deletions.
1,706 changes: 919 additions & 787 deletions chrome/browser/autocomplete/autocomplete_edit.cc

Large diffs are not rendered by default.

873 changes: 505 additions & 368 deletions chrome/browser/autocomplete/autocomplete_edit.h

Large diffs are not rendered by default.

141 changes: 71 additions & 70 deletions chrome/browser/autocomplete/autocomplete_popup.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,10 @@ int MirroringContext::GetLeft(int x1, int x2) const {
const wchar_t AutocompletePopupView::DrawLineInfo::ellipsis_str[] = L"\x2026";

AutocompletePopupView::AutocompletePopupView(AutocompletePopupModel* model,
const ChromeFont& font)
const ChromeFont& font,
AutocompleteEditView* edit_view)
: model_(model),
edit_view_(edit_view),
line_info_(font),
mirroring_context_(new MirroringContext()),
star_(ResourceBundle::GetSharedInstance().GetBitmapNamed(
Expand Down Expand Up @@ -168,12 +170,11 @@ void AutocompletePopupView::UpdatePopupAppearance() {
// TODO(pkasting): http://b/1345937 All this use of editor accessors should
// die once this class is a true ChromeView.
CRect rc;
model_->editor()->parent_view()->GetBounds(&rc);
edit_view_->parent_view()->GetBounds(&rc);
// Subtract the top left corner to make the coordinates relative to the
// location bar view itself, and convert to screen coordinates.
CPoint top_left(-rc.TopLeft());
ChromeViews::View::ConvertPointToScreen(model_->editor()->parent_view(),
&top_left);
ChromeViews::View::ConvertPointToScreen(edit_view_->parent_view(), &top_left);
rc.OffsetRect(top_left);
// Expand by one pixel on each side since that's the amount the location bar
// view is inset from the divider line that edges the adjacent buttons.
Expand All @@ -194,14 +195,14 @@ void AutocompletePopupView::UpdatePopupAppearance() {
if (!m_hWnd) {
// To prevent this window from being activated, we create an invisible
// window and manually show it without activating it.
Create(model_->editor()->m_hWnd, rc, AUTOCOMPLETEPOPUPVIEW_CLASSNAME,
WS_POPUP, WS_EX_TOOLWINDOW);
Create(edit_view_->m_hWnd, rc, AUTOCOMPLETEPOPUPVIEW_CLASSNAME, WS_POPUP,
WS_EX_TOOLWINDOW);
// When an IME is attached to the rich-edit control, retrieve its window
// handle and show this popup window under the IME windows.
// Otherwise, show this popup window under top-most windows.
// TODO(hbono): http://b/1111369 if we exclude this popup window from the
// display area of IME windows, this workaround becomes unnecessary.
HWND ime_window = ImmGetDefaultIMEWnd(model_->editor()->m_hWnd);
HWND ime_window = ImmGetDefaultIMEWnd(edit_view_->m_hWnd);
SetWindowPos(ime_window ? ime_window : HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
} else {
Expand All @@ -217,9 +218,9 @@ void AutocompletePopupView::UpdatePopupAppearance() {
}

// TODO(pkasting): http://b/1111369 We should call ImmSetCandidateWindow() on
// the model_->editor()'s IME context here, and exclude ourselves from its
// display area. Not clear what to pass for the lpCandidate->ptCurrentPos
// member, though...
// the edit_view_'s IME context here, and exclude ourselves from its display
// area. Not clear what to pass for the lpCandidate->ptCurrentPos member,
// though...
}

void AutocompletePopupView::OnHoverEnabledOrDisabled(bool disabled) {
Expand Down Expand Up @@ -333,7 +334,16 @@ void AutocompletePopupView::OnPaint(HDC other_dc) {

void AutocompletePopupView::OnButtonUp(const CPoint& point,
WindowOpenDisposition disposition) {
model_->OpenLine(PixelToLine(point.y), disposition);
const size_t line = PixelToLine(point.y);
const AutocompleteMatch& match = model_->result()->match_at(line);
// OpenURL() may close the popup, which will clear the result set and, by
// extension, |match| and its contents. So copy the relevant strings out to
// make sure they stay alive until the call completes.
const std::wstring url(match.destination_url);
std::wstring keyword;
const bool is_keyword_hint = model_->GetKeywordForMatch(match, &keyword);
edit_view_->OpenURL(url, disposition, match.transition, std::wstring(), line,
is_keyword_hint ? std::wstring() : keyword);
}

int AutocompletePopupView::LineTopPixel(size_t line) const {
Expand Down Expand Up @@ -712,11 +722,13 @@ const int kPopupCoalesceMs = 100;
const int kPopupUpdateMaxDelayMs = 300;
};

AutocompletePopupModel::AutocompletePopupModel(const ChromeFont& font,
AutocompleteEdit* editor,
Profile* profile)
: view_(new AutocompletePopupView(this, font)),
editor_(editor),
AutocompletePopupModel::AutocompletePopupModel(
const ChromeFont& font,
AutocompleteEditView* edit_view,
AutocompleteEditModel* edit_model,
Profile* profile)
: view_(new AutocompletePopupView(this, font, edit_view)),
edit_model_(edit_model),
controller_(new AutocompleteController(this, profile)),
profile_(profile),
query_in_progress_(false),
Expand Down Expand Up @@ -799,11 +811,13 @@ void AutocompletePopupModel::StopAutocomplete() {
latest_result_.Reset();
CommitLatestResults(true);

// Clear input_ to make sure we don't try and use any of these results for
// the next query we receive. Strictly speaking this isn't necessary, since
// the popup isn't open, but it keeps our internal state consistent and
// serves as future-proofing in case the code in StartAutocomplete() changes.
// Clear input_ and manually_selected_match_ to make sure we don't try and use
// any of these results for the next query we receive. Strictly speaking this
// isn't necessary, since the popup isn't open, but it keeps our internal
// state consistent and serves as future-proofing in case the code in
// StartAutocomplete() changes.
input_.Clear();
manually_selected_match_.Clear();
}

void AutocompletePopupModel::SetHoveredLine(size_t line) {
Expand Down Expand Up @@ -840,10 +854,10 @@ void AutocompletePopupModel::SetSelectedLine(size_t line) {
const AutocompleteMatch& match = result_.match_at(line);
std::wstring keyword;
const bool is_keyword_hint = GetKeywordForMatch(match, &keyword);
editor_->OnPopupDataChanged(match.fill_into_edit, true,
manually_selected_match_, keyword,
is_keyword_hint,
(match.type == AutocompleteMatch::SEARCH));
edit_model_->OnPopupDataChanged(match.fill_into_edit, true,
manually_selected_match_, keyword,
is_keyword_hint,
(match.type == AutocompleteMatch::SEARCH));

// Track the user's selection until they cancel it.
manually_selected_match_.destination_url = match.destination_url;
Expand Down Expand Up @@ -933,6 +947,38 @@ std::wstring AutocompletePopupModel::URLsForDefaultMatch(
return url;
}

bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match,
std::wstring* keyword) {
// Assume we have no keyword until we find otherwise.
keyword->clear();

// If the current match is a keyword, return that as the selected keyword.
if (match.template_url && match.template_url->url() &&
match.template_url->url()->SupportsReplacement()) {
keyword->assign(match.template_url->keyword());
return false;
}

// See if the current match's fill_into_edit corresponds to a keyword.
if (!profile_->GetTemplateURLModel())
return false;
profile_->GetTemplateURLModel()->Load();
const std::wstring keyword_hint(
TemplateURLModel::CleanUserInputKeyword(match.fill_into_edit));
if (keyword_hint.empty())
return false;

// Don't provide a hint if this keyword doesn't support replacement.
const TemplateURL* const template_url =
profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_hint);
if (!template_url || !template_url->url() ||
!template_url->url()->SupportsReplacement())
return false;

keyword->assign(keyword_hint);
return true;
}

AutocompleteLog* AutocompletePopupModel::GetAutocompleteLog() {
return new AutocompleteLog(input_.text(), selected_line_, 0, result_);
}
Expand Down Expand Up @@ -984,19 +1030,6 @@ void AutocompletePopupModel::TryDeletingCurrentItem() {
}
}

void AutocompletePopupModel::OpenLine(size_t line,
WindowOpenDisposition disposition) {
const AutocompleteMatch& match = result_.match_at(line);
// OpenURL() may close the popup, which will clear the result set and, by
// extension, |match| and its contents. So copy the relevant strings out to
// make sure they stay alive until the call completes.
const std::wstring url(match.destination_url);
std::wstring keyword;
const bool is_keyword_hint = GetKeywordForMatch(match, &keyword);
editor_->OpenURL(url, disposition, match.transition, std::wstring(), line,
is_keyword_hint ? std::wstring() : keyword);
}

void AutocompletePopupModel::OnAutocompleteUpdate(bool updated_result,
bool query_complete) {
DCHECK(query_in_progress_);
Expand Down Expand Up @@ -1055,7 +1088,7 @@ void AutocompletePopupModel::SetDefaultMatchAndUpdate(bool immediately) {
is_keyword_hint = GetKeywordForMatch(*match, &keyword);
can_show_search_hint = (match->type == AutocompleteMatch::SEARCH);
}
editor_->OnPopupDataChanged(inline_autocomplete_text, false,
edit_model_->OnPopupDataChanged(inline_autocomplete_text, false,
manually_selected_match_ /* ignored */, keyword, is_keyword_hint,
can_show_search_hint);
}
Expand Down Expand Up @@ -1091,35 +1124,3 @@ void AutocompletePopupModel::CommitLatestResults(bool force) {
else
max_delay_timer_.Stop();
}

bool AutocompletePopupModel::GetKeywordForMatch(const AutocompleteMatch& match,
std::wstring* keyword) {
// Assume we have no keyword until we find otherwise.
keyword->clear();

// If the current match is a keyword, return that as the selected keyword.
if (match.template_url && match.template_url->url() &&
match.template_url->url()->SupportsReplacement()) {
keyword->assign(match.template_url->keyword());
return false;
}

// See if the current match's fill_into_edit corresponds to a keyword.
if (!profile_->GetTemplateURLModel())
return false;
profile_->GetTemplateURLModel()->Load();
const std::wstring keyword_hint(
TemplateURLModel::CleanUserInputKeyword(match.fill_into_edit));
if (keyword_hint.empty())
return false;

// Don't provide a hint if this keyword doesn't support replacement.
const TemplateURL* const template_url =
profile_->GetTemplateURLModel()->GetTemplateURLForKeyword(keyword_hint);
if (!template_url || !template_url->url() ||
!template_url->url()->SupportsReplacement())
return false;

keyword->assign(keyword_hint);
return true;
}
50 changes: 27 additions & 23 deletions chrome/browser/autocomplete/autocomplete_popup.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,21 @@
#include "chrome/common/gfx/chrome_font.h"
#include "chrome/views/view.h"

class AutocompleteEdit;
class AutocompletePopupModel;
class AutocompletePopupView;
class AutocompleteEditModel;
class AutocompleteEditView;
class Profile;
class MirroringContext;
class SkBitmap;

class AutocompletePopupModel;
class AutocompletePopupView;

// TODO(pkasting): http://b/1343512 The names and contents of the classes in
// this file are temporary. I am in hack-and-slash mode right now.

#define AUTOCOMPLETEPOPUPVIEW_CLASSNAME L"Chrome_AutocompletePopupView"

// This class implements a popup window used by AutocompleteEdit to display
// autocomplete results.
// This class implements a popup window used to display autocomplete results.
class AutocompletePopupView
: public CWindowImpl<AutocompletePopupView, CWindow, CControlWinTraits> {
public:
Expand All @@ -50,7 +51,9 @@ class AutocompletePopupView
MSG_WM_PAINT(OnPaint)
END_MSG_MAP()

AutocompletePopupView(AutocompletePopupModel* model, const ChromeFont& font);
AutocompletePopupView(AutocompletePopupModel* model,
const ChromeFont& font,
AutocompleteEditView* edit_view);

// Returns true if the popup is currently open.
bool is_open() const { return m_hWnd != NULL; }
Expand Down Expand Up @@ -179,6 +182,8 @@ class AutocompletePopupView

AutocompletePopupModel* model_;

AutocompleteEditView* edit_view_;

// Cached GDI information for drawing.
DrawLineInfo line_info_;

Expand All @@ -194,12 +199,15 @@ class AutocompletePopupView
// re-enabled. When hovered_line_ is a valid line, the value here is
// out-of-date and should be ignored.
CPoint last_hover_coordinates_;

DISALLOW_COPY_AND_ASSIGN(AutocompletePopupView);
};

class AutocompletePopupModel : public ACControllerListener, public Task {
public:
AutocompletePopupModel(const ChromeFont& font,
AutocompleteEdit* editor,
AutocompleteEditView* edit_view,
AutocompleteEditModel* edit_model,
Profile* profile);
~AutocompletePopupModel();

Expand All @@ -225,9 +233,6 @@ class AutocompletePopupModel : public ACControllerListener, public Task {
// Returns true if the popup is currently open.
bool is_open() const { return view_->is_open(); }

// TODO(pkasting): http://b/134593 This is temporary and should die.
const AutocompleteEdit* editor() const { return editor_; }

// Returns the AutocompleteController used by this popup.
AutocompleteController* autocomplete_controller() const {
return controller_.get();
Expand Down Expand Up @@ -300,6 +305,14 @@ class AutocompletePopupModel : public ACControllerListener, public Task {
bool* is_history_what_you_typed_match,
std::wstring* alternate_nav_url);

// Gets the selected keyword or keyword hint for the given match. Returns
// true if |keyword| represents a keyword hint, or false if |keyword|
// represents a selected keyword. (|keyword| will always be set [though
// possibly to the empty string], and you cannot have both a selected keyword
// and a keyword hint simultaneously.)
bool GetKeywordForMatch(const AutocompleteMatch& match,
std::wstring* keyword);

// Returns a pointer to a heap-allocated AutocompleteLog containing the
// current input text, selected match, and result set. The caller is
// responsible for deleting the object.
Expand All @@ -309,16 +322,13 @@ class AutocompletePopupModel : public ACControllerListener, public Task {
// current selection down (|count| > 0) or up (|count| < 0), clamping to the
// first or last result if necessary. If |count| == 0, the selection will be
// unchanged, but the popup will still redraw and modify the text in the
// AutocompleteEdit.
// AutocompleteEditModel.
void Move(int count);

// Called when the user hits shift-delete. This should determine if the item
// can be removed from history, and if so, remove it and update the popup.
void TryDeletingCurrentItem();

// Called by the view to open the URL corresponding to a particular line.
void OpenLine(size_t line, WindowOpenDisposition disposition);

// ACControllerListener - called when more autocomplete data is available or
// when the query is complete.
//
Expand Down Expand Up @@ -347,17 +357,9 @@ class AutocompletePopupModel : public ACControllerListener, public Task {
// changes back to the user.
void CommitLatestResults(bool force);

// Gets the selected keyword or keyword hint for the given match. Returns
// true if |keyword| represents a keyword hint, or false if |keyword|
// represents a selected keyword. (|keyword| will always be set [though
// possibly to the empty string], and you cannot have both a selected keyword
// and a keyword hint simultaneously.)
bool GetKeywordForMatch(const AutocompleteMatch& match,
std::wstring* keyword);

scoped_ptr<AutocompletePopupView> view_;

AutocompleteEdit* editor_;
AutocompleteEditModel* edit_model_;
scoped_ptr<AutocompleteController> controller_;

// Profile for current tab.
Expand Down Expand Up @@ -399,6 +401,8 @@ class AutocompletePopupModel : public ACControllerListener, public Task {
// The currently selected line. This is kNoMatch when nothing is selected,
// which should only be true when the popup is closed.
size_t selected_line_;

DISALLOW_COPY_AND_ASSIGN(AutocompletePopupModel);
};

#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_H_
Expand Down
4 changes: 2 additions & 2 deletions chrome/browser/autocomplete/edit_drop_target.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ DWORD CopyOrLinkDropEffect(DWORD effect) {

}

EditDropTarget::EditDropTarget(AutocompleteEdit* edit)
EditDropTarget::EditDropTarget(AutocompleteEditView* edit)
: BaseDropTarget(edit->m_hWnd),
edit_(edit),
drag_has_url_(false),
Expand Down Expand Up @@ -91,7 +91,7 @@ DWORD EditDropTarget::OnDrop(IDataObject* data_object,
std::wstring title;
if (os_data.GetURLAndTitle(&url, &title)) {
edit_->SetUserText(UTF8ToWide(url.spec()));
edit_->AcceptInput(CURRENT_TAB, true);
edit_->model()->AcceptInput(CURRENT_TAB, true);
return CopyOrLinkDropEffect(effect);
}
} else if (drag_has_string_) {
Expand Down
Loading

0 comments on commit 81c2122

Please sign in to comment.