diff options
author | deanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-10 12:35:31 +0000 |
---|---|---|
committer | deanm@chromium.org <deanm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-10 12:35:31 +0000 |
commit | bdfde861c70504cab986e086e1b00b2b0c5c60aa (patch) | |
tree | 355b746c663a480dbc18bda000c6dbfad4dcbe90 /chrome | |
parent | 3ca588d7d6e79fb4d2f0e6b6a4ebbded29eba733 (diff) | |
download | chromium_src-bdfde861c70504cab986e086e1b00b2b0c5c60aa.zip chromium_src-bdfde861c70504cab986e086e1b00b2b0c5c60aa.tar.gz chromium_src-bdfde861c70504cab986e086e1b00b2b0c5c60aa.tar.bz2 |
Implement a GTK LocationBarView and Autocomplete{Edit,Popup}View.
This implements some beginning functionality of "omnibox". It uses GtkTextView for a rich text edit for the location bar. Color emphasis, inline autocomplete, and the results popup work. You can select one of the omnibox results using the keyboard. Mouse selection doesn't work. The results popup code will have to be scraped and reimplemented with cairo / pango.
BUG=8236
Review URL: http://codereview.chromium.org/40013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11323 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc | 483 | ||||
-rw-r--r-- | chrome/browser/autocomplete/autocomplete_edit_view_gtk.h | 201 | ||||
-rwxr-xr-x | chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc | 115 | ||||
-rwxr-xr-x | chrome/browser/autocomplete/autocomplete_popup_view_gtk.h | 55 | ||||
-rw-r--r-- | chrome/browser/browser.scons | 3 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_gtk.cc | 91 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_toolbar_gtk.h | 24 | ||||
-rw-r--r-- | chrome/browser/gtk/location_bar_view_gtk.cc | 143 | ||||
-rw-r--r-- | chrome/browser/gtk/location_bar_view_gtk.h | 88 |
9 files changed, 1114 insertions, 89 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc new file mode 100644 index 0000000..cae7c6e --- /dev/null +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.cc @@ -0,0 +1,483 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" + +#include <gtk/gtk.h> + +#include "base/logging.h" +#include "base/string_util.h" +#include "chrome/browser/autocomplete/autocomplete_edit.h" +#include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/toolbar_model.h" +#include "chrome/common/notification_service.h" +#include "googleurl/src/gurl.h" + +namespace { + +const char kTextBaseColor[] = "#808080"; +const char kSecureSchemeColor[] = "#009614"; +const char kInsecureSchemeColor[] = "#009614"; +const GdkColor kSecureBackgroundColor = {0, 65535, 62965, 50115}; // #fff5c3 +const GdkColor kInsecureBackgroundColor = {0, 65535, 65535, 65535}; // #ffffff + +} // namespace + +AutocompleteEditViewGtk::AutocompleteEditViewGtk( + AutocompleteEditController* controller, + ToolbarModel* toolbar_model, + Profile* profile, + CommandUpdater* command_updater) + : text_view_(NULL), + tag_table_(NULL), + text_buffer_(NULL), + base_tag_(NULL), + secure_scheme_tag_(NULL), + insecure_scheme_tag_(NULL), + model_(new AutocompleteEditModel(this, controller, profile)), + popup_view_(new AutocompletePopupViewGtk(this, model_.get(), profile)), + controller_(controller), + toolbar_model_(toolbar_model), + command_updater_(command_updater), + popup_window_mode_(false), // TODO(deanm) + scheme_security_level_(ToolbarModel::NORMAL) { + model_->set_popup_model(popup_view_->model()); +} + +AutocompleteEditViewGtk::~AutocompleteEditViewGtk() { + NotificationService::current()->Notify( + NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, + Source<AutocompleteEditViewGtk>(this), + NotificationService::NoDetails()); +} + +void AutocompleteEditViewGtk::Init() { + tag_table_ = gtk_text_tag_table_new(); + text_buffer_ = gtk_text_buffer_new(tag_table_); + text_view_ = gtk_text_view_new_with_buffer(text_buffer_); + + gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_view_), 4); + gtk_text_view_set_right_margin(GTK_TEXT_VIEW(text_view_), 4); + + // TODO(deanm): This is a super lame attempt to vertically center our single + // line of text in a multiline edit control. Mannnn. + gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(text_view_), 4); + + // TODO(deanm): This will probably have to be handled differently with the + // tab to search business. Maybe we should just eat the tab characters. + // We want the tab key to move focus, not insert a tab. + gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(text_view_), false); + + base_tag_ = gtk_text_buffer_create_tag(text_buffer_, + NULL, "foreground", kTextBaseColor, NULL); + secure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, + NULL, "foreground", kSecureSchemeColor, NULL); + insecure_scheme_tag_ = gtk_text_buffer_create_tag(text_buffer_, + NULL, "foreground", kInsecureSchemeColor, NULL); + + // NOTE: This code used to connect to "changed", however this was fired too + // often and during bad times (our own buffer changes?). It works out much + // better to listen to end-user-action, which should be fired whenever the + // user makes some sort of change to the buffer. + g_signal_connect(text_buffer_, "begin-user-action", + G_CALLBACK(&HandleBeginUserActionThunk), this); + g_signal_connect(text_buffer_, "end-user-action", + G_CALLBACK(&HandleEndUserActionThunk), this); + g_signal_connect(text_view_, "size-request", + G_CALLBACK(&HandleViewSizeRequest), this); + g_signal_connect(text_view_, "button-press-event", + G_CALLBACK(&HandleViewButtonPressThunk), this); + g_signal_connect(text_view_, "focus-in-event", + G_CALLBACK(&HandleViewFocusInThunk), this); + g_signal_connect(text_view_, "focus-out-event", + G_CALLBACK(&HandleViewFocusOutThunk), this); + // NOTE: The GtkTextView documentation asks you not to connect to this + // signal, but it is very convenient and clean for catching up/down. + g_signal_connect(text_view_, "move-cursor", + G_CALLBACK(&HandleViewMoveCursorThunk), this); +} + +void AutocompleteEditViewGtk::FocusLocation() { + gtk_widget_grab_focus(text_view_); + SelectAll(false); +} + +void AutocompleteEditViewGtk::SaveStateToTab(TabContents* tab) { + NOTIMPLEMENTED(); +} + +void AutocompleteEditViewGtk::Update(const TabContents* contents) { + // NOTE: We're getting the URL text here from the ToolbarModel. + bool visibly_changed_permanent_text = + model_->UpdatePermanentText(toolbar_model_->GetText()); + + ToolbarModel::SecurityLevel security_level = + toolbar_model_->GetSchemeSecurityLevel(); + bool changed_security_level = (security_level != scheme_security_level_); + scheme_security_level_ = security_level; + + if (contents) { + RevertAll(); + // TODO(deanm): Tab switching. The Windows code puts some state in a + // PropertyBag on the tab contents, and restores state from there. + } else if (visibly_changed_permanent_text) { + RevertAll(); + // TODO(deanm): There should be code to restore select all here. + } else if(changed_security_level) { + EmphasizeURLComponents(); + } +} + +void AutocompleteEditViewGtk::OpenURL(const GURL& url, + WindowOpenDisposition disposition, + PageTransition::Type transition, + const GURL& alternate_nav_url, + size_t selected_line, + const std::wstring& keyword) { + if (!url.is_valid()) + return; + + model_->SendOpenNotification(selected_line, keyword); + + if (disposition != NEW_BACKGROUND_TAB) + RevertAll(); // Revert the box to its unedited state + controller_->OnAutocompleteAccept(url, disposition, transition, + alternate_nav_url); +} + +std::wstring AutocompleteEditViewGtk::GetText() const { + GtkTextIter start, end; + gtk_text_buffer_get_bounds(text_buffer_, &start, &end); + gchar* utf8 = gtk_text_buffer_get_text(text_buffer_, &start, &end, false); + std::wstring out(UTF8ToWide(utf8)); + g_free(utf8); + return out; +} + +void AutocompleteEditViewGtk::SetUserText(const std::wstring& text, + const std::wstring& display_text, + bool update_popup) { + NOTIMPLEMENTED(); +} + +void AutocompleteEditViewGtk::SetWindowTextAndCaretPos(const std::wstring& text, + size_t caret_pos) { + std::string utf8 = WideToUTF8(text); + gtk_text_buffer_set_text(text_buffer_, utf8.data(), utf8.length()); + EmphasizeURLComponents(); + + GtkTextIter cur_pos; + gtk_text_buffer_get_iter_at_offset(text_buffer_, &cur_pos, caret_pos); + gtk_text_buffer_place_cursor(text_buffer_, &cur_pos); +} + +bool AutocompleteEditViewGtk::IsSelectAll() { + NOTIMPLEMENTED(); + return false; +} + +void AutocompleteEditViewGtk::SelectAll(bool reversed) { + GtkTextIter start, end; + if (reversed) { + gtk_text_buffer_get_bounds(text_buffer_, &end, &start); + } else { + gtk_text_buffer_get_bounds(text_buffer_, &start, &end); + } + gtk_text_buffer_place_cursor(text_buffer_, &start); + gtk_text_buffer_select_range(text_buffer_, &start, &end); +} + +void AutocompleteEditViewGtk::RevertAll() { + ClosePopup(); + model_->Revert(); + TextChanged(); +} + +void AutocompleteEditViewGtk::UpdatePopup() { + model_->SetInputInProgress(true); + if (!model_->has_focus()) + return; + + // Don't inline autocomplete when the caret/selection isn't at the end of + // the text. + CharRange sel = GetSelection(); + model_->StartAutocomplete(sel.cp_max < GetTextLength()); +} + +void AutocompleteEditViewGtk::ClosePopup() { + popup_view_->model()->StopAutocomplete(); +} + +void AutocompleteEditViewGtk::OnTemporaryTextMaybeChanged( + const std::wstring& display_text, + bool save_original_selection) { + // TODO(deanm): Ignoring save_original_selection here, etc. + SetWindowTextAndCaretPos(display_text, display_text.length()); + TextChanged(); +} + +bool AutocompleteEditViewGtk::OnInlineAutocompleteTextMaybeChanged( + const std::wstring& display_text, + size_t user_text_length) { + if (display_text == GetText()) + return false; + + SetWindowTextAndCaretPos(display_text, 0); + + // Select the part of the text that was inline autocompleted. + GtkTextIter bound, insert; + gtk_text_buffer_get_bounds(text_buffer_, &insert, &bound); + gtk_text_buffer_get_iter_at_offset(text_buffer_, &insert, user_text_length); + gtk_text_buffer_select_range(text_buffer_, &insert, &bound); + + TextChanged(); + return true; +} + +void AutocompleteEditViewGtk::OnRevertTemporaryText() { + NOTIMPLEMENTED(); +} + +void AutocompleteEditViewGtk::OnBeforePossibleChange() { + // Record our state. + text_before_change_ = GetText(); + sel_before_change_ = GetSelection(); +} + +// TODO(deanm): This is mostly stolen from Windows, and will need some work. +bool AutocompleteEditViewGtk::OnAfterPossibleChange() { + CharRange new_sel = GetSelection(); + int length = GetTextLength(); + bool selection_differs = (new_sel.cp_min != sel_before_change_.cp_min) || + (new_sel.cp_max != sel_before_change_.cp_max); + bool at_end_of_edit = (new_sel.cp_min == length && new_sel.cp_max == length); + + // See if the text or selection have changed since OnBeforePossibleChange(). + std::wstring new_text(GetText()); + bool text_differs = (new_text != text_before_change_); + + // When the user has deleted text, we don't allow inline autocomplete. Make + // sure to not flag cases like selecting part of the text and then pasting + // (or typing) the prefix of that selection. (We detect these by making + // sure the caret, which should be after any insertion, hasn't moved + // forward of the old selection start.) + bool just_deleted_text = + (text_before_change_.length() > new_text.length()) && + (new_sel.cp_min <= std::min(sel_before_change_.cp_min, + sel_before_change_.cp_max)); + + bool something_changed = model_->OnAfterPossibleChange(new_text, + selection_differs, text_differs, just_deleted_text, at_end_of_edit); + + if (something_changed && text_differs) + TextChanged(); + + return something_changed; +} + +void AutocompleteEditViewGtk::BottomLeftPosWidth(int* x, int* y, int* width) { + gdk_window_get_origin(text_view_->window, x, y); + *y += text_view_->allocation.height; + *width = text_view_->allocation.width; +} + +void AutocompleteEditViewGtk::HandleBeginUserAction() { + OnBeforePossibleChange(); +} + +void AutocompleteEditViewGtk::HandleEndUserAction() { + bool had_newline = false; + + // TODO(deanm): obviously super inefficient. + for(;;) { + GtkTextIter cur, end; + gtk_text_buffer_get_bounds(text_buffer_, &cur, &end); + + while (!gtk_text_iter_equal(&cur, &end)) { + if (gtk_text_iter_ends_line(&cur)) { + had_newline = true; + GtkTextIter next = cur; + gtk_text_iter_forward_char(&next); + gtk_text_buffer_delete(text_buffer_, &cur, &next); + + // We've invalidated our iterators, gotta start again. + break; + } + + gtk_text_iter_forward_char(&cur); + } + + // We've exhausted the whole input and there is now only 1 line, good. + if (gtk_text_iter_equal(&cur, &end)) + break; + } + + OnAfterPossibleChange(); + + if (had_newline) + model_->AcceptInput(CURRENT_TAB, false); +} + +// static +void AutocompleteEditViewGtk::HandleViewSizeRequest(GtkWidget* view, + GtkRequisition* req, + gpointer unused) { + // Don't force a minimum size, allow our embedder to size us better. + req->height = req->width = 1; +} + +gboolean AutocompleteEditViewGtk::HandleViewButtonPress(GdkEventButton* event) { + // When the GtkTextView is clicked, it will call gtk_widget_grab_focus. + // I believe this causes the focus-in event to be fired before the main + // clicked handling code. If we were to try to set the selection from + // the focus-in event, it's just going to be undone by the click handler. + // This is a bit ugly. We shim in to get the click before the GtkTextView, + // then if we don't have focus, we (hopefully safely) assume that the click + // will cause us to become focused. We call GtkTextView's default handler + // and then stop propagation. This allows us to run our code after the + // default handler, even if that handler stopped propagation. + if (GTK_WIDGET_HAS_FOCUS(text_view_)) + return FALSE; // Continue to propagate into the GtkTextView handler. + + // Call the GtkTextView default handler, ignoring the fact that it will + // likely have told us to stop propagating. We want to handle selection. + GtkWidgetClass* klass = GTK_WIDGET_GET_CLASS(text_view_); + klass->button_press_event(text_view_, event); + + // Select the full input when we get focus. + SelectAll(false); + // So we told the buffer where the cursor should be, but make sure to tell + // the view so it can scroll it to be visible if needed. + // NOTE: This function doesn't seem to like a count of 0, looking at the + // code it will skip an important loop. Use -1 to achieve the same. + GtkTextIter start, end; + gtk_text_buffer_get_bounds(text_buffer_, &start, &end); + gtk_text_view_move_visually(GTK_TEXT_VIEW(text_view_), &start, -1); + + return TRUE; // Don't continue, we called the default handler already. +} + +gboolean AutocompleteEditViewGtk::HandleViewFocusIn() { + model_->OnSetFocus(false); + // TODO(deanm): Some keyword hit business, etc here. + + return FALSE; // Continue propagation. +} + +gboolean AutocompleteEditViewGtk::HandleViewFocusOut() { + // Close the popup. + ClosePopup(); + + // Tell the model to reset itself. + model_->OnKillFocus(); + + // TODO(deanm): This probably isn't right, and doesn't match Windows. We + // don't really want to match Windows though, because it probably feels + // wrong on Linux. Firefox doesn't have great behavior here also, imo. + // Deselect any selection and make sure the input is at the beginning. + GtkTextIter start, end; + gtk_text_buffer_get_bounds(text_buffer_, &start, &end); + gtk_text_buffer_place_cursor(text_buffer_, &start); + return FALSE; // Pass the event on to the GtkTextView. +} + +void AutocompleteEditViewGtk::HandleViewMoveCursor( + GtkMovementStep step, + gint count, + gboolean extendion_selection) { + // Handle up / down cursor movement on our own. + if (step == GTK_MOVEMENT_DISPLAY_LINES) { + model_->OnUpOrDownKeyPressed(count); + // move-cursor doesn't use a signal accumulator on the return value (it + // just ignores them), so we have to stop the propagation. + g_signal_stop_emission_by_name(text_view_, "move-cursor"); + return; + } + // Propagate into GtkTextView. +} + +AutocompleteEditViewGtk::CharRange AutocompleteEditViewGtk::GetSelection() { + // You can not just use get_selection_bounds here, since the order will be + // ascending, and you don't know where the user's start and end of the + // selection was (if the selection was forwards or backwards). Get the + // actual marks so that we can preserve the selection direction. + GtkTextIter start, insert; + GtkTextMark* mark; + + mark = gtk_text_buffer_get_selection_bound(text_buffer_); + gtk_text_buffer_get_iter_at_mark(text_buffer_, &start, mark); + + mark = gtk_text_buffer_get_insert(text_buffer_); + gtk_text_buffer_get_iter_at_mark(text_buffer_, &insert, mark); + + return CharRange(gtk_text_iter_get_offset(&start), + gtk_text_iter_get_offset(&insert)); +} + +void AutocompleteEditViewGtk::ItersFromCharRange(const CharRange& range, + GtkTextIter* iter_min, + GtkTextIter* iter_max) { + gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_min, range.cp_min); + gtk_text_buffer_get_iter_at_offset(text_buffer_, iter_max, range.cp_max); +} + +int AutocompleteEditViewGtk::GetTextLength() { + GtkTextIter start, end; + gtk_text_buffer_get_bounds(text_buffer_, &start, &end); + return gtk_text_iter_get_offset(&end); +} + +void AutocompleteEditViewGtk::EmphasizeURLComponents() { + // See whether the contents are a URL with a non-empty host portion, which we + // should emphasize. To check for a URL, rather than using the type returned + // by Parse(), ask the model, which will check the desired page transition for + // this input. This can tell us whether an UNKNOWN input string is going to + // be treated as a search or a navigation, and is the same method the Paste + // And Go system uses. + url_parse::Parsed parts; + AutocompleteInput::Parse(GetText(), model_->GetDesiredTLD(), &parts, NULL); + bool emphasize = model_->CurrentTextIsURL() && (parts.host.len > 0); + + // Set the baseline emphasis. + GtkTextIter start, end; + gtk_text_buffer_get_bounds(text_buffer_, &start, &end); + gtk_text_buffer_remove_all_tags(text_buffer_, &start, &end); + if (emphasize) { + gtk_text_buffer_apply_tag(text_buffer_, base_tag_, &start, &end); + + // We've found a host name, give it more emphasis. + gtk_text_buffer_get_iter_at_line_index(text_buffer_, &start, 0, + parts.host.begin); + gtk_text_buffer_get_iter_at_line_index(text_buffer_, &end, 0, + parts.host.end()); + gtk_text_buffer_remove_all_tags(text_buffer_, &start, &end); + } + + // Emphasize the scheme for security UI display purposes (if necessary). + if (!model_->user_input_in_progress() && parts.scheme.is_nonempty() && + (scheme_security_level_ != ToolbarModel::NORMAL)) { + gtk_text_buffer_get_iter_at_line_index(text_buffer_, &start, 0, + parts.scheme.begin); + gtk_text_buffer_get_iter_at_line_index(text_buffer_, &end, 0, + parts.scheme.end()); + const GdkColor* background; + if (scheme_security_level_ == ToolbarModel::SECURE) { + background = &kSecureBackgroundColor; + gtk_text_buffer_apply_tag(text_buffer_, secure_scheme_tag_, + &start, &end); + } else { + background = &kInsecureBackgroundColor; + gtk_text_buffer_apply_tag(text_buffer_, insecure_scheme_tag_, + &start, &end); + } + gtk_widget_modify_base(text_view_, GTK_STATE_NORMAL, background); + } +} + +void AutocompleteEditViewGtk::TextChanged() { + EmphasizeURLComponents(); + controller_->OnChanged(); +} diff --git a/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h new file mode 100644 index 0000000..85d16ae --- /dev/null +++ b/chrome/browser/autocomplete/autocomplete_edit_view_gtk.h @@ -0,0 +1,201 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_ +#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_ + +#include <gtk/gtk.h> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/autocomplete/autocomplete.h" +#include "chrome/browser/autocomplete/autocomplete_edit_view.h" +#include "chrome/browser/toolbar_model.h" +#include "chrome/common/page_transition_types.h" +#include "webkit/glue/window_open_disposition.h" + +class AutocompleteEditController; +class AutocompleteEditModel; +class AutocompletePopupViewGtk; +class CommandUpdater; +class Profile; +class TabContents; +class ToolbarModel; + +class AutocompleteEditViewGtk : public AutocompleteEditView { + public: + AutocompleteEditViewGtk(AutocompleteEditController* controller, + ToolbarModel* toolbar_model, + Profile* profile, + CommandUpdater* command_updater); + ~AutocompleteEditViewGtk(); + + // Initialize, create the underlying widgets, etc. + void Init(); + + GtkWidget* widget() { return text_view_; } + + // Grab keyboard input focus, putting focus on the location widget. + void FocusLocation(); + + // Implement the AutocompleteEditView interface. + virtual AutocompleteEditModel* model() { return model_.get(); } + virtual const AutocompleteEditModel* model() const { return model_.get(); } + + virtual void SaveStateToTab(TabContents* tab); + + virtual void Update(const TabContents* tab_for_state_restoring); + + virtual void OpenURL(const GURL& url, + WindowOpenDisposition disposition, + PageTransition::Type transition, + const GURL& alternate_nav_url, + size_t selected_line, + const std::wstring& keyword); + + virtual std::wstring GetText() const; + + virtual void SetUserText(const std::wstring& text) { + SetUserText(text, text, true); + } + virtual void SetUserText(const std::wstring& text, + const std::wstring& display_text, + bool update_popup); + + virtual void SetWindowTextAndCaretPos(const std::wstring& text, + size_t caret_pos); + + virtual bool IsSelectAll(); + virtual void SelectAll(bool reversed); + virtual void RevertAll(); + + virtual void UpdatePopup(); + virtual void ClosePopup(); + + virtual void OnTemporaryTextMaybeChanged(const std::wstring& display_text, + bool save_original_selection); + virtual bool OnInlineAutocompleteTextMaybeChanged( + const std::wstring& display_text, size_t user_text_length); + virtual void OnRevertTemporaryText(); + virtual void OnBeforePossibleChange(); + virtual bool OnAfterPossibleChange(); + + // Return the position (root coordinates) of the bottom left corner and width + // of the location input box. Used by the popup view to position itself. + void BottomLeftPosWidth(int* x, int* y, int* width); + + private: + // Modeled like the Windows CHARRANGE. Represent a pair of cursor position + // offsets. Since GtkTextIters are invalid after the buffer is changed, we + // work in character offsets (not bytes). + struct CharRange { + CharRange() : cp_min(0), cp_max(0) { } + CharRange(int n, int x) : cp_min(n), cp_max(x) { } + + // Work in integers to match the gint GTK APIs. + int cp_min; // For a selection: Represents the start. + int cp_max; // For a selection: Represents the end (insert position). + }; + + // TODO(deanm): Would be nice to insulate the thunkers better, etc. + static void HandleBeginUserActionThunk(GtkTextBuffer* unused, gpointer self) { + reinterpret_cast<AutocompleteEditViewGtk*>(self)->HandleBeginUserAction(); + } + void HandleBeginUserAction(); + + static void HandleEndUserActionThunk(GtkTextBuffer* unused, gpointer self) { + reinterpret_cast<AutocompleteEditViewGtk*>(self)->HandleEndUserAction(); + } + void HandleEndUserAction(); + + static void HandleViewSizeRequest(GtkWidget* view, GtkRequisition* req, + gpointer unused); + + static gboolean HandleViewButtonPressThunk(GtkWidget* view, + GdkEventButton* event, + gpointer self) { + return reinterpret_cast<AutocompleteEditViewGtk*>(self)-> + HandleViewButtonPress(event); + } + gboolean HandleViewButtonPress(GdkEventButton* event); + + static gboolean HandleViewFocusInThunk(GtkWidget* view, + GdkEventFocus* event, + gpointer self) { + return reinterpret_cast<AutocompleteEditViewGtk*>(self)-> + HandleViewFocusIn(); + } + gboolean HandleViewFocusIn(); + + static gboolean HandleViewFocusOutThunk(GtkWidget* view, + GdkEventFocus* event, + gpointer self) { + return reinterpret_cast<AutocompleteEditViewGtk*>(self)-> + HandleViewFocusOut(); + } + gboolean HandleViewFocusOut(); + + static void HandleViewMoveCursorThunk(GtkWidget* view, + GtkMovementStep step, + gint count, + gboolean extend_selection, + gpointer self) { + reinterpret_cast<AutocompleteEditViewGtk*>(self)-> + HandleViewMoveCursor(step, count, extend_selection); + } + void HandleViewMoveCursor(GtkMovementStep step, + gint count, + gboolean extendion_selection); + + // Get the character indices of the current selection. This honors + // direction, cp_max is the insertion point, and cp_min is the bound. + CharRange GetSelection(); + + // Translate from character positions to iterators for the current buffer. + void ItersFromCharRange(const CharRange& range, + GtkTextIter* iter_min, + GtkTextIter* iter_max); + + // Return the number of characers in the current buffer. + int GetTextLength(); + + // Try to parse the current text as a URL and colorize the components. + void EmphasizeURLComponents(); + + // Internally invoked whenever the text changes in some way. + void TextChanged(); + + GtkWidget* text_view_; + + GtkTextTagTable* tag_table_; + GtkTextBuffer* text_buffer_; + + GtkTextTag* base_tag_; + GtkTextTag* secure_scheme_tag_; + GtkTextTag* insecure_scheme_tag_; + + scoped_ptr<AutocompleteEditModel> model_; + scoped_ptr<AutocompletePopupViewGtk> popup_view_; + AutocompleteEditController* controller_; + ToolbarModel* toolbar_model_; + + // The object that handles additional command functionality exposed on the + // edit, such as invoking the keyword editor. + CommandUpdater* command_updater_; + + // When true, the location bar view is read only and also is has a slightly + // different presentation (font size / color). This is used for popups. + // TODO(deanm). + bool popup_window_mode_; + + ToolbarModel::SecurityLevel scheme_security_level_; + + // Tracking state before and after a possible change. + std::wstring text_before_change_; + CharRange sel_before_change_; + + DISALLOW_COPY_AND_ASSIGN(AutocompleteEditViewGtk); +}; + +#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_EDIT_VIEW_GTK_H_ diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc new file mode 100755 index 0000000..8f1b586 --- /dev/null +++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autocomplete/autocomplete_popup_view_gtk.h" + +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "chrome/browser/autocomplete/autocomplete.h" +#include "chrome/browser/autocomplete/autocomplete_edit.h" +#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" +#include "chrome/browser/autocomplete/autocomplete_popup_model.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_model.h" +#include "chrome/common/notification_service.h" + +namespace { + +const GdkColor kPopupBorderColor = {0, 51143, 51914, 52942}; // #c7cace +const GdkColor kPopupBackground = {0, 65535, 65535, 65535}; // #ffffff +const GdkColor kHighlightColor = {0, 49601, 51400, 55769}; // #c1c8d9 + +} // namespace + +AutocompletePopupViewGtk::AutocompletePopupViewGtk( + AutocompleteEditViewGtk* edit_view, + AutocompleteEditModel* edit_model, + Profile* profile) + : model_(new AutocompletePopupModel(this, edit_model, profile)), + edit_view_(edit_view), + window_(gtk_window_new(GTK_WINDOW_POPUP)), + vbox_(NULL), + opened_(false) { + GTK_WIDGET_UNSET_FLAGS(window_, GTK_CAN_FOCUS); + // Don't allow the window to be resized. This also forces the window to + // shrink down to the size of its child contents. + gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); + // Set up a 1 pixel border around the popup. + gtk_container_set_border_width(GTK_CONTAINER(window_), 1); + gtk_widget_modify_bg(window_, GTK_STATE_NORMAL, &kPopupBorderColor); + gtk_widget_modify_base(window_, GTK_STATE_NORMAL, &kPopupBorderColor); +} + +AutocompletePopupViewGtk::~AutocompletePopupViewGtk() { + if (vbox_) + gtk_widget_destroy(vbox_); + gtk_widget_destroy(window_); +} + +void AutocompletePopupViewGtk::InvalidateLine(size_t line) { + UpdatePopupAppearance(); +} + +void AutocompletePopupViewGtk::UpdatePopupAppearance() { + const AutocompleteResult& result = model_->result(); + if (result.empty()) { + Hide(); + return; + } + + // TODO(deanm): This could be done better, but the code is temporary + // and will need to be replaced with custom drawing and not widgets. + if (vbox_) + gtk_widget_destroy(vbox_); + + vbox_ = gtk_vbox_new(FALSE, 0); + + for (size_t i = 0; i < result.size(); ++i) { + std::string utf8; + utf8.append(WideToUTF8(result.match_at(i).contents)); + utf8.append(" - "); + utf8.append(WideToUTF8(result.match_at(i).description)); + GtkWidget* label = gtk_label_new(utf8.c_str()); + // We need to put the labels in an event box for background painting. + GtkWidget* ebox = gtk_event_box_new(); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_container_add(GTK_CONTAINER(ebox), label); + gtk_box_pack_start(GTK_BOX(vbox_), ebox, FALSE, FALSE, 0); + gtk_widget_show(label); + gtk_widget_show(ebox); + if (i == model_->selected_line()) { + gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, &kHighlightColor); + } else { + gtk_widget_modify_bg(ebox, GTK_STATE_NORMAL, &kPopupBackground); + } + } + + gtk_widget_show(vbox_); + gtk_container_add(GTK_CONTAINER(window_), vbox_); + Show(); +} + +void AutocompletePopupViewGtk::OnHoverEnabledOrDisabled(bool disabled) { + NOTIMPLEMENTED(); +} + +void AutocompletePopupViewGtk::PaintUpdatesNow() { + UpdatePopupAppearance(); +} + +void AutocompletePopupViewGtk::Show() { + gint x, y, width; + edit_view_->BottomLeftPosWidth(&x, &y, &width); + gtk_window_move(GTK_WINDOW(window_), x, y); + gtk_widget_set_size_request(window_, width, -1); + gtk_widget_show(window_); + opened_ = true; +} + +void AutocompletePopupViewGtk::Hide() { + gtk_widget_hide(window_); + opened_ = false; +} diff --git a/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h new file mode 100755 index 0000000..3c4fcc8 --- /dev/null +++ b/chrome/browser/autocomplete/autocomplete_popup_view_gtk.h @@ -0,0 +1,55 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_GTK_H_ +#define CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_GTK_H_ + +#include <gtk/gtk.h> + +#include <string> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/autocomplete/autocomplete.h" +#include "chrome/browser/autocomplete/autocomplete_popup_view.h" +#include "webkit/glue/window_open_disposition.h" + +class AutocompletePopupModel; +class AutocompleteEditModel; +class AutocompleteEditViewGtk; +class Profile; +class SkBitmap; + +class AutocompletePopupViewGtk : public AutocompletePopupView { + public: + AutocompletePopupViewGtk(AutocompleteEditViewGtk* edit_view, + AutocompleteEditModel* edit_model, + Profile* profile); + ~AutocompletePopupViewGtk(); + + // Implement the AutocompletePopupView interface. + virtual bool IsOpen() const { return opened_; } + virtual void InvalidateLine(size_t line); + virtual void UpdatePopupAppearance(); + virtual void OnHoverEnabledOrDisabled(bool disabled); + virtual void PaintUpdatesNow(); + + AutocompletePopupModel* model() { return model_.get(); } + + private: + void Show(); + void Hide(); + + scoped_ptr<AutocompletePopupModel> model_; + AutocompleteEditViewGtk* edit_view_; + + GtkWidget* window_; + GtkWidget* vbox_; + + bool opened_; + + DISALLOW_COPY_AND_ASSIGN(AutocompletePopupViewGtk); +}; + +#endif // CHROME_BROWSER_AUTOCOMPLETE_AUTOCOMPLETE_POPUP_VIEW_GTK_H_ diff --git a/chrome/browser/browser.scons b/chrome/browser/browser.scons index 0e6e74d..7c820b4 100644 --- a/chrome/browser/browser.scons +++ b/chrome/browser/browser.scons @@ -736,6 +736,8 @@ if not env.Bit('windows'): if env.Bit('linux'): input_files.Extend([ + 'autocomplete/autocomplete_edit_view_gtk.cc', + 'autocomplete/autocomplete_popup_view_gtk.cc', 'browser_main_gtk.cc', 'gtk/back_forward_menu_model_gtk.cc', 'gtk/browser_toolbar_gtk.cc', @@ -744,6 +746,7 @@ if env.Bit('linux'): 'gtk/custom_button.cc', 'gtk/download_item_gtk.cc', 'gtk/download_shelf_gtk.cc', + 'gtk/location_bar_view_gtk.cc', 'gtk/menu_gtk.cc', 'gtk/nine_box.cc', 'gtk/standard_menus.cc', diff --git a/chrome/browser/gtk/browser_toolbar_gtk.cc b/chrome/browser/gtk/browser_toolbar_gtk.cc index b218beb..c51d27d 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.cc +++ b/chrome/browser/gtk/browser_toolbar_gtk.cc @@ -11,8 +11,9 @@ #include "base/path_service.h" #include "chrome/app/chrome_dll_resource.h" #include "chrome/browser/browser.h" -#include "chrome/browser/gtk/custom_button.h" #include "chrome/browser/gtk/back_forward_menu_model_gtk.h" +#include "chrome/browser/gtk/custom_button.h" +#include "chrome/browser/gtk/location_bar_view_gtk.h" #include "chrome/browser/gtk/standard_menus.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/common/l10n_util.h" @@ -21,17 +22,19 @@ #include "grit/generated_resources.h" #include "grit/theme_resources.h" -// TODO(deanm): Remove this when the LocationBarView is used. -class LocationBar; - const int BrowserToolbarGtk::kToolbarHeight = 38; // For the back/forward dropdown menus, the time in milliseconds between // when the user clicks and the popup menu appears. static const int kMenuTimerDelay = 500; +static void OnGrabFocusThunk(GtkWidget* toolbar, gpointer self) { + reinterpret_cast<BrowserToolbarGtk*>(self)->FocusLocationBar(); +} + BrowserToolbarGtk::BrowserToolbarGtk(Browser* browser) : toolbar_(NULL), - entry_(NULL), + location_bar_(new LocationBarViewGtk(browser->command_updater(), + browser->toolbar_model())), model_(browser->toolbar_model()), browser_(browser), profile_(NULL), @@ -52,6 +55,9 @@ BrowserToolbarGtk::~BrowserToolbarGtk() { } void BrowserToolbarGtk::Init(Profile* profile, GtkAccelGroup* accel_group) { + // Make sure to tell the location bar the profile before calling its Init. + SetProfile(profile); + accel_group_ = accel_group; show_home_button_.Init(prefs::kShowHomeButton, profile->GetPrefs(), this); @@ -89,22 +95,17 @@ void BrowserToolbarGtk::Init(Profile* profile, GtkAccelGroup* accel_group) { star_.reset(BuildToolbarButton(IDR_STAR, IDR_STAR_P, IDR_STAR_H, IDR_STAR_D, l10n_util::GetString(IDS_TOOLTIP_STAR))); - entry_ = gtk_entry_new(); - gtk_widget_set_size_request(entry_, 0, 27); - g_signal_connect(G_OBJECT(entry_), "activate", - G_CALLBACK(OnEntryActivate), this); - g_signal_connect(G_OBJECT(entry_), "focus", - G_CALLBACK(OnEntryFocus), this); - g_signal_connect(G_OBJECT(entry_), "focus-in-event", - G_CALLBACK(OnEntryFocusIn), this); - g_signal_connect(G_OBJECT(entry_), "focus-out-event", - G_CALLBACK(OnEntryFocusOut), this); + location_bar_->Init(); + gtk_box_pack_start(GTK_BOX(toolbar_), location_bar_->widget(), TRUE, TRUE, 0); + + // We listen for ctrl-l which we have send a grab-focus action to the + // toolbar. We want our callback to just call FocusLocationBar(). + g_signal_connect(toolbar_, "grab-focus", + G_CALLBACK(OnGrabFocusThunk), this); gtk_widget_add_accelerator( - entry_, "grab-focus", accel_group_, GDK_l, + toolbar_, "grab-focus", accel_group_, GDK_l, GDK_CONTROL_MASK, GtkAccelFlags(0)); - gtk_box_pack_start(GTK_BOX(toolbar_), entry_, TRUE, TRUE, 0); - go_.reset(BuildToolbarButton(IDR_GO, IDR_GO_P, IDR_GO_H, 0, L"")); gtk_box_pack_start(GTK_BOX(toolbar_), gtk_label_new(" "), FALSE, FALSE, 0); @@ -117,8 +118,6 @@ void BrowserToolbarGtk::Init(Profile* profile, GtkAccelGroup* accel_group) { l10n_util::GetStringF(IDS_APPMENU_TOOLTIP, l10n_util::GetString(IDS_PRODUCT_NAME)))); app_menu_.reset(new MenuGtk(this, GetStandardAppMenu(), accel_group_)); - - SetProfile(profile); } void BrowserToolbarGtk::AddToolbarToBox(GtkWidget* box) { @@ -126,12 +125,11 @@ void BrowserToolbarGtk::AddToolbarToBox(GtkWidget* box) { } LocationBar* BrowserToolbarGtk::GetLocationBar() const { - NOTIMPLEMENTED(); - return NULL; + return location_bar_.get(); } void BrowserToolbarGtk::FocusLocationBar() { - gtk_widget_grab_focus(entry_); + location_bar_->FocusLocation(); } void BrowserToolbarGtk::EnabledStateChangedForCommand(int id, bool enabled) { @@ -195,16 +193,12 @@ void BrowserToolbarGtk::SetProfile(Profile* profile) { return; profile_ = profile; - // TODO(erg): location_bar_ is a normal gtk text box right now. Change this - // when we get omnibox support. - // location_bar_->SetProfile(profile); + location_bar_->SetProfile(profile); } void BrowserToolbarGtk::UpdateTabContents(TabContents* contents, bool should_restore_state) { - // Extract the UTF-8 representation of the URL. - gtk_entry_set_text(GTK_ENTRY(entry_), - contents->GetURL().possibly_invalid_spec().c_str()); + location_bar_->Update(should_restore_state ? contents : NULL); } CustomDrawButton* BrowserToolbarGtk::BuildToolbarButton( @@ -249,45 +243,6 @@ CustomContainerButton* BrowserToolbarGtk::BuildToolbarMenuButton( } // static -void BrowserToolbarGtk::OnEntryActivate(GtkEntry *entry, - BrowserToolbarGtk* toolbar) { - GURL dest(URLFixerUpper::FixupURL(std::string(gtk_entry_get_text(entry)), - std::string())); - toolbar->browser_->GetSelectedTabContents()-> - OpenURL(dest, GURL(), CURRENT_TAB, PageTransition::TYPED); -} - -// static -gboolean BrowserToolbarGtk::OnEntryFocus(GtkWidget* widget, - GtkDirectionType direction, - BrowserToolbarGtk* host) { - if (!GTK_WIDGET_HAS_FOCUS(widget)) { - gtk_widget_grab_focus(widget); - return TRUE; - } - - return FALSE; -} - -// static -gboolean BrowserToolbarGtk::OnEntryFocusIn(GtkWidget* widget, - GdkEventFocus* focus, - BrowserToolbarGtk* host) { - // Set the caret at the end of the text. - gtk_editable_set_position(GTK_EDITABLE(widget), -1); - return FALSE; -} - -// static -gboolean BrowserToolbarGtk::OnEntryFocusOut(GtkWidget* widget, - GdkEventFocus* focus, - BrowserToolbarGtk* host) { - // Clear the selected text (if any). - gtk_editable_set_position(GTK_EDITABLE(widget), 0); - return FALSE; -} - -// static void BrowserToolbarGtk::OnButtonClick(GtkWidget* button, BrowserToolbarGtk* toolbar) { int tag = -1; diff --git a/chrome/browser/gtk/browser_toolbar_gtk.h b/chrome/browser/gtk/browser_toolbar_gtk.h index c943db4..9e854fd 100644 --- a/chrome/browser/gtk/browser_toolbar_gtk.h +++ b/chrome/browser/gtk/browser_toolbar_gtk.h @@ -19,6 +19,7 @@ class Browser; class CustomContainerButton; class CustomDrawButton; class LocationBar; +class LocationBarViewGtk; class Profile; class TabContents; class ToolbarModel; @@ -83,25 +84,6 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, unsigned int accelerator, unsigned int accelerator_mod); - // Gtk callback for the "activate" signal on the |entry_| widget. Responds to - // enter. - static void OnEntryActivate(GtkEntry *entry, BrowserToolbarGtk* toolbar); - - // Gtk callback for the "focus" signal on the |entry_| widget. - static gboolean OnEntryFocus(GtkWidget* widget, - GtkDirectionType direction, - BrowserToolbarGtk* host); - - // Gtk callback for the "focus-in" signal on the |entry_| widget. - static gboolean OnEntryFocusIn(GtkWidget* widget, - GdkEventFocus* focus, - BrowserToolbarGtk* host); - - // Gtk callback for the "focus-out" signal on the |entry_| widget. - static gboolean OnEntryFocusOut(GtkWidget* widget, - GdkEventFocus* focus, - BrowserToolbarGtk* host); - // Gtk callback for the "clicked" signal. static void OnButtonClick(GtkWidget* button, BrowserToolbarGtk* toolbar); @@ -126,8 +108,8 @@ class BrowserToolbarGtk : public CommandUpdater::CommandObserver, // Tooltip container for all GTK widgets in this class. GtkTooltips* toolbar_tooltips_; - // Our temporary URL bar (until we get the omnibox up). - GtkWidget* entry_; + // The location bar view. + scoped_ptr<LocationBarViewGtk> location_bar_; // A pointer to our window's accelerator list. GtkAccelGroup* accel_group_; diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc new file mode 100644 index 0000000..4e97032 --- /dev/null +++ b/chrome/browser/gtk/location_bar_view_gtk.cc @@ -0,0 +1,143 @@ +#include "chrome/browser/gtk/location_bar_view_gtk.h" + +#include <string> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/browser/alternate_nav_url_fetcher.h" +#include "chrome/browser/autocomplete/autocomplete_edit_view_gtk.h" +#include "chrome/browser/command_updater.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/page_transition_types.h" +#include "skia/include/SkBitmap.h" +#include "webkit/glue/window_open_disposition.h" + +LocationBarViewGtk::LocationBarViewGtk(CommandUpdater* command_updater, + ToolbarModel* toolbar_model) + : vbox_(NULL), + profile_(NULL), + command_updater_(command_updater), + toolbar_model_(toolbar_model), + disposition_(CURRENT_TAB), + transition_(PageTransition::TYPED) { +} + +LocationBarViewGtk::~LocationBarViewGtk(){ + // TODO(deanm): Should I destroy the widgets here, or leave it up to the + // embedder? When the embedder destroys their widget, if we're a child, we + // will also get destroyed, so the ownership is kinda unclear. +} + +void LocationBarViewGtk::Init(){ + edit_view_.reset(new AutocompleteEditViewGtk(this, toolbar_model_, profile_, + command_updater_)); + edit_view_->Init(); + + vbox_ = gtk_vbox_new(false, 0); + + // Get the location bar to fit nicely in the toolbar, kinda ugly. + static const int kTopPadding = 2; + static const int kBottomPadding = 3; + GtkWidget* alignment = gtk_alignment_new(0, 0, 1, 1); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), + kTopPadding, kBottomPadding, 0, 0); + gtk_container_add(GTK_CONTAINER(alignment), edit_view_->widget()); + + gtk_box_pack_start(GTK_BOX(vbox_), alignment, TRUE, TRUE, 0); +} + +void LocationBarViewGtk::SetProfile(Profile* profile) { + profile_ = profile; +} + +void LocationBarViewGtk::Update(const TabContents* contents) { + edit_view_->Update(contents); +} + +void LocationBarViewGtk::OnAutocompleteAccept(const GURL& url, + WindowOpenDisposition disposition, + PageTransition::Type transition, + const GURL& alternate_nav_url) { + if (!url.is_valid()) + return; + + location_input_ = UTF8ToWide(url.spec()); + disposition_ = disposition; + transition_ = transition; + + if (!command_updater_) + return; + + if (!alternate_nav_url.is_valid()) { + command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL); + return; + } + + scoped_ptr<AlternateNavURLFetcher> fetcher( + new AlternateNavURLFetcher(alternate_nav_url)); + // The AlternateNavURLFetcher will listen for the pending navigation + // notification that will be issued as a result of the "open URL." It + // will automatically install itself into that navigation controller. + command_updater_->ExecuteCommand(IDC_OPEN_CURRENT_URL); + if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) { + // I'm not sure this should be reachable, but I'm not also sure enough + // that it shouldn't to stick in a NOTREACHED(). In any case, this is + // harmless; we can simply let the fetcher get deleted here and it will + // clean itself up properly. + } else { + fetcher.release(); // The navigation controller will delete the fetcher. + } +} + +void LocationBarViewGtk::OnChanged() { + // TODO(deanm): Here is where we would do layout when we have things like + // the keyword display, ssl icons, etc. +} + +void LocationBarViewGtk::OnInputInProgress(bool in_progress) { + NOTIMPLEMENTED(); +} + +SkBitmap LocationBarViewGtk::GetFavIcon() const { + NOTIMPLEMENTED(); + return SkBitmap(); +} + +std::wstring LocationBarViewGtk::GetTitle() const { + NOTIMPLEMENTED(); + return std::wstring(); +} + +void LocationBarViewGtk::ShowFirstRunBubble(){ + NOTIMPLEMENTED(); +} + +std::wstring LocationBarViewGtk::GetInputString() const{ + return location_input_; +} + +WindowOpenDisposition LocationBarViewGtk::GetWindowOpenDisposition() const{ + return disposition_; +} + +PageTransition::Type LocationBarViewGtk::GetPageTransition() const{ + return transition_; +} + +void LocationBarViewGtk::AcceptInput(){ + NOTIMPLEMENTED(); +} + +void LocationBarViewGtk::FocusLocation(){ + edit_view_->FocusLocation(); +} + +void LocationBarViewGtk::FocusSearch(){ + NOTIMPLEMENTED(); +} + +void LocationBarViewGtk::SaveStateToContents(TabContents* contents){ + NOTIMPLEMENTED(); +} diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h new file mode 100644 index 0000000..50b0775 --- /dev/null +++ b/chrome/browser/gtk/location_bar_view_gtk.h @@ -0,0 +1,88 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_GTK_LOCATION_BAR_VIEW_GTK_H_ +#define CHROME_BROWSER_GTK_LOCATION_BAR_VIEW_GTK_H_ + +#include <gtk/gtk.h> + +#include <string> + +#include "base/basictypes.h" +#include "chrome/browser/autocomplete/autocomplete_edit.h" +#include "chrome/browser/location_bar.h" +#include "chrome/common/page_transition_types.h" +#include "webkit/glue/window_open_disposition.h" + +class AutocompleteEditViewGtk; +class CommandUpdater; +class Profile; +class SkBitmap; +class TabContents; +class ToolbarModel; + +class LocationBarViewGtk : public AutocompleteEditController, + public LocationBar { + public: + LocationBarViewGtk(CommandUpdater* command_updater, + ToolbarModel* toolbar_model); + ~LocationBarViewGtk(); + + void Init(); + + void SetProfile(Profile* profile); + + // Return the native vbox widget. You must call Init() first, or the result + // will be NULL. This is the widget that an embedder should host. + GtkWidget* widget() { return vbox_; } + + // Updates the location bar. We also reset the bar's permanent text and + // security style, and, if |tab_for_state_restoring| is non-NULL, also + // restore saved state that the tab holds. + void Update(const TabContents* tab_for_state_restoring); + + // Implement the AutocompleteEditController interface. + virtual void OnAutocompleteAccept(const GURL& url, + WindowOpenDisposition disposition, + PageTransition::Type transition, + const GURL& alternate_nav_url); + virtual void OnChanged(); + virtual void OnInputInProgress(bool in_progress); + virtual SkBitmap GetFavIcon() const; + virtual std::wstring GetTitle() const; + + // Implement the LocationBar interface. + virtual void ShowFirstRunBubble(); + virtual std::wstring GetInputString() const; + virtual WindowOpenDisposition GetWindowOpenDisposition() const; + virtual PageTransition::Type GetPageTransition() const; + virtual void AcceptInput(); + virtual void FocusLocation(); + virtual void FocusSearch(); + virtual void SaveStateToContents(TabContents* contents); + + private: + GtkWidget* vbox_; + + scoped_ptr<AutocompleteEditViewGtk> edit_view_; + + Profile* profile_; + CommandUpdater* command_updater_; + ToolbarModel* toolbar_model_; + + // When we get an OnAutocompleteAccept notification from the autocomplete + // edit, we save the input string so we can give it back to the browser on + // the LocationBar interface via GetInputString(). + std::wstring location_input_; + + // The user's desired disposition for how their input should be opened + WindowOpenDisposition disposition_; + + // The transition type to use for the navigation + PageTransition::Type transition_; + + DISALLOW_COPY_AND_ASSIGN(LocationBarViewGtk); +}; + +#endif // CHROME_BROWSER_GTK_LOCATION_BAR_VIEW_GTK_H_ |