| 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 #ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_H_ | 5 #ifndef UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_H_ |
| 6 #define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_H_ | 6 #define UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_H_ |
| 7 | 7 |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "ui/base/models/simple_menu_model.h" | 22 #include "ui/base/models/simple_menu_model.h" |
| 23 #include "ui/base/touch/touch_editing_controller.h" | 23 #include "ui/base/touch/touch_editing_controller.h" |
| 24 #include "ui/events/keycodes/keyboard_codes.h" | 24 #include "ui/events/keycodes/keyboard_codes.h" |
| 25 #include "ui/gfx/font_list.h" | 25 #include "ui/gfx/font_list.h" |
| 26 #include "ui/gfx/range/range.h" | 26 #include "ui/gfx/range/range.h" |
| 27 #include "ui/gfx/selection_model.h" | 27 #include "ui/gfx/selection_model.h" |
| 28 #include "ui/gfx/text_constants.h" | 28 #include "ui/gfx/text_constants.h" |
| 29 #include "ui/views/context_menu_controller.h" | 29 #include "ui/views/context_menu_controller.h" |
| 30 #include "ui/views/controls/textfield/textfield_model.h" | 30 #include "ui/views/controls/textfield/textfield_model.h" |
| 31 #include "ui/views/drag_controller.h" | 31 #include "ui/views/drag_controller.h" |
| 32 #include "ui/views/selection_controller.h" |
| 33 #include "ui/views/selection_controller_delegate.h" |
| 32 #include "ui/views/view.h" | 34 #include "ui/views/view.h" |
| 33 #include "ui/views/word_lookup_client.h" | 35 #include "ui/views/word_lookup_client.h" |
| 34 | 36 |
| 35 namespace views { | 37 namespace views { |
| 36 | 38 |
| 37 class MenuRunner; | 39 class MenuRunner; |
| 38 class Painter; | 40 class Painter; |
| 39 class TextfieldController; | 41 class TextfieldController; |
| 40 | 42 |
| 41 // A views/skia textfield implementation. No platform-specific code is used. | 43 // A views/skia textfield implementation. No platform-specific code is used. |
| 42 class VIEWS_EXPORT Textfield : public View, | 44 class VIEWS_EXPORT Textfield : public View, |
| 43 public TextfieldModel::Delegate, | 45 public TextfieldModel::Delegate, |
| 44 public ContextMenuController, | 46 public ContextMenuController, |
| 45 public DragController, | 47 public DragController, |
| 46 public WordLookupClient, | 48 public WordLookupClient, |
| 49 public SelectionControllerDelegate, |
| 47 public ui::TouchEditable, | 50 public ui::TouchEditable, |
| 48 public ui::TextInputClient { | 51 public ui::TextInputClient { |
| 49 public: | 52 public: |
| 50 // The textfield's class name. | 53 // The textfield's class name. |
| 51 static const char kViewClassName[]; | 54 static const char kViewClassName[]; |
| 52 | 55 |
| 53 // The preferred size of the padding to be used around textfield text. | 56 // The preferred size of the padding to be used around textfield text. |
| 54 static const int kTextPadding; | 57 static const int kTextPadding; |
| 55 | 58 |
| 56 // Returns the text cursor blink time in milliseconds, or 0 for no blinking. | 59 // Returns the text cursor blink time in milliseconds, or 0 for no blinking. |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 // Empty and invalid ranges are ignored. | 206 // Empty and invalid ranges are ignored. |
| 204 void SetStyle(gfx::TextStyle style, bool value); | 207 void SetStyle(gfx::TextStyle style, bool value); |
| 205 void ApplyStyle(gfx::TextStyle style, bool value, const gfx::Range& range); | 208 void ApplyStyle(gfx::TextStyle style, bool value, const gfx::Range& range); |
| 206 | 209 |
| 207 // Clears Edit history. | 210 // Clears Edit history. |
| 208 void ClearEditHistory(); | 211 void ClearEditHistory(); |
| 209 | 212 |
| 210 // Set the accessible name of the text field. | 213 // Set the accessible name of the text field. |
| 211 void SetAccessibleName(const base::string16& name); | 214 void SetAccessibleName(const base::string16& name); |
| 212 | 215 |
| 213 // Returns whether there is a drag operation originating from the textfield. | |
| 214 bool HasTextBeingDragged(); | |
| 215 | |
| 216 // View overrides: | 216 // View overrides: |
| 217 gfx::Insets GetInsets() const override; | 217 gfx::Insets GetInsets() const override; |
| 218 int GetBaseline() const override; | 218 int GetBaseline() const override; |
| 219 gfx::Size GetPreferredSize() const override; | 219 gfx::Size GetPreferredSize() const override; |
| 220 const char* GetClassName() const override; | 220 const char* GetClassName() const override; |
| 221 void SetBorder(std::unique_ptr<Border> b) override; | 221 void SetBorder(std::unique_ptr<Border> b) override; |
| 222 gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override; | 222 gfx::NativeCursor GetCursor(const ui::MouseEvent& event) override; |
| 223 bool OnMousePressed(const ui::MouseEvent& event) override; | 223 bool OnMousePressed(const ui::MouseEvent& event) override; |
| 224 bool OnMouseDragged(const ui::MouseEvent& event) override; | 224 bool OnMouseDragged(const ui::MouseEvent& event) override; |
| 225 void OnMouseReleased(const ui::MouseEvent& event) override; | 225 void OnMouseReleased(const ui::MouseEvent& event) override; |
| 226 void OnMouseCaptureLost() override; |
| 226 WordLookupClient* GetWordLookupClient() override; | 227 WordLookupClient* GetWordLookupClient() override; |
| 227 void OnGestureEvent(ui::GestureEvent* event) override; | 228 void OnGestureEvent(ui::GestureEvent* event) override; |
| 228 bool AcceleratorPressed(const ui::Accelerator& accelerator) override; | 229 bool AcceleratorPressed(const ui::Accelerator& accelerator) override; |
| 229 bool CanHandleAccelerators() const override; | 230 bool CanHandleAccelerators() const override; |
| 230 void AboutToRequestFocusFromTabTraversal(bool reverse) override; | 231 void AboutToRequestFocusFromTabTraversal(bool reverse) override; |
| 231 bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override; | 232 bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override; |
| 232 bool GetDropFormats( | 233 bool GetDropFormats( |
| 233 int* formats, | 234 int* formats, |
| 234 std::set<ui::Clipboard::FormatType>* format_types) override; | 235 std::set<ui::Clipboard::FormatType>* format_types) override; |
| 235 bool CanDrop(const ui::OSExchangeData& data) override; | 236 bool CanDrop(const ui::OSExchangeData& data) override; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 263 int GetDragOperationsForView(View* sender, const gfx::Point& p) override; | 264 int GetDragOperationsForView(View* sender, const gfx::Point& p) override; |
| 264 bool CanStartDragForView(View* sender, | 265 bool CanStartDragForView(View* sender, |
| 265 const gfx::Point& press_pt, | 266 const gfx::Point& press_pt, |
| 266 const gfx::Point& p) override; | 267 const gfx::Point& p) override; |
| 267 | 268 |
| 268 // WordLookupClient overrides: | 269 // WordLookupClient overrides: |
| 269 bool GetDecoratedWordAtPoint(const gfx::Point& point, | 270 bool GetDecoratedWordAtPoint(const gfx::Point& point, |
| 270 gfx::DecoratedText* decorated_word, | 271 gfx::DecoratedText* decorated_word, |
| 271 gfx::Point* baseline_point) override; | 272 gfx::Point* baseline_point) override; |
| 272 | 273 |
| 274 // SelectionControllerDelegate overrides: |
| 275 bool HasTextBeingDragged() const override; |
| 276 |
| 273 // ui::TouchEditable overrides: | 277 // ui::TouchEditable overrides: |
| 274 void SelectRect(const gfx::Point& start, const gfx::Point& end) override; | 278 void SelectRect(const gfx::Point& start, const gfx::Point& end) override; |
| 275 void MoveCaretTo(const gfx::Point& point) override; | 279 void MoveCaretTo(const gfx::Point& point) override; |
| 276 void GetSelectionEndPoints(gfx::SelectionBound* anchor, | 280 void GetSelectionEndPoints(gfx::SelectionBound* anchor, |
| 277 gfx::SelectionBound* focus) override; | 281 gfx::SelectionBound* focus) override; |
| 278 gfx::Rect GetBounds() override; | 282 gfx::Rect GetBounds() override; |
| 279 gfx::NativeView GetNativeView() const override; | 283 gfx::NativeView GetNativeView() const override; |
| 280 void ConvertPointToScreen(gfx::Point* point) override; | 284 void ConvertPointToScreen(gfx::Point* point) override; |
| 281 void ConvertPointFromScreen(gfx::Point* point) override; | 285 void ConvertPointFromScreen(gfx::Point* point) override; |
| 282 bool DrawsHandles() override; | 286 bool DrawsHandles() override; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override; | 324 bool IsTextEditCommandEnabled(ui::TextEditCommand command) const override; |
| 321 void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override; | 325 void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override; |
| 322 | 326 |
| 323 protected: | 327 protected: |
| 324 // Inserts or appends a character in response to an IME operation. | 328 // Inserts or appends a character in response to an IME operation. |
| 325 virtual void DoInsertChar(base::char16 ch); | 329 virtual void DoInsertChar(base::char16 ch); |
| 326 | 330 |
| 327 // Returns the TextfieldModel's text/cursor/selection rendering model. | 331 // Returns the TextfieldModel's text/cursor/selection rendering model. |
| 328 gfx::RenderText* GetRenderText() const; | 332 gfx::RenderText* GetRenderText() const; |
| 329 | 333 |
| 330 gfx::Point last_click_location() const { return last_click_location_; } | 334 gfx::Point GetLastClickLocation() const; |
| 331 | 335 |
| 332 // Get the text from the selection clipboard. | 336 // Get the text from the selection clipboard. |
| 333 virtual base::string16 GetSelectionClipboardText() const; | 337 virtual base::string16 GetSelectionClipboardText() const; |
| 334 | 338 |
| 335 // Executes the given |command|. | 339 // Executes the given |command|. |
| 336 virtual void ExecuteTextEditCommand(ui::TextEditCommand command); | 340 virtual void ExecuteTextEditCommand(ui::TextEditCommand command); |
| 337 | 341 |
| 338 private: | 342 private: |
| 339 friend class TextfieldTestApi; | 343 friend class TextfieldTestApi; |
| 340 | 344 |
| 341 // View overrides: | 345 // View overrides: |
| 342 // Declared final since overriding by subclasses would interfere with the | 346 // Declared final since overriding by subclasses would interfere with the |
| 343 // accounting related to the scheduled text edit command. Subclasses should | 347 // accounting related to the scheduled text edit command. Subclasses should |
| 344 // use TextfieldController::HandleKeyEvent, to intercept the key event. | 348 // use TextfieldController::HandleKeyEvent, to intercept the key event. |
| 345 bool OnKeyPressed(const ui::KeyEvent& event) final; | 349 bool OnKeyPressed(const ui::KeyEvent& event) final; |
| 346 bool OnKeyReleased(const ui::KeyEvent& event) final; | 350 bool OnKeyReleased(const ui::KeyEvent& event) final; |
| 347 | 351 |
| 352 // SelectionControllerDelegate overrides: |
| 353 gfx::RenderText* GetRenderTextForSelectionController() override; |
| 354 bool IsReadOnly() const override; |
| 355 void SetTextBeingDragged(bool value) override; |
| 356 int GetViewHeight() const override; |
| 357 int GetViewWidth() const override; |
| 358 int GetDragSelectionDelay() const override; |
| 359 void OnBeforePointerAction() override; |
| 360 void OnAfterPointerAction(bool text_changed, bool selection_changed) override; |
| 361 // Callers within Textfield should call UpdateAfterChange depending on the |
| 362 // return value. |
| 363 bool PasteSelectionClipboard() override; |
| 364 void UpdateSelectionClipboard() override; |
| 365 |
| 348 // Handles a request to change the value of this text field from software | 366 // Handles a request to change the value of this text field from software |
| 349 // using an accessibility API (typically automation software, screen readers | 367 // using an accessibility API (typically automation software, screen readers |
| 350 // don't normally use this). Sets the value and clears the selection. | 368 // don't normally use this). Sets the value and clears the selection. |
| 351 void AccessibilitySetValue(const base::string16& new_value); | 369 void AccessibilitySetValue(const base::string16& new_value); |
| 352 | 370 |
| 353 // Updates the painted background color. | 371 // Updates the painted background color. |
| 354 void UpdateBackgroundColor(); | 372 void UpdateBackgroundColor(); |
| 355 | 373 |
| 356 // Updates the border per the state of |invalid_|. | 374 // Updates the border per the state of |invalid_|. |
| 357 void UpdateBorder(); | 375 void UpdateBorder(); |
| 358 | 376 |
| 359 // Does necessary updates when the text and/or cursor position changes. | 377 // Does necessary updates when the text and/or cursor position changes. |
| 360 void UpdateAfterChange(bool text_changed, bool cursor_changed); | 378 void UpdateAfterChange(bool text_changed, bool cursor_changed); |
| 361 | 379 |
| 362 // A callback function to periodically update the cursor state. | 380 // A callback function to periodically update the cursor state. |
| 363 void UpdateCursor(); | 381 void UpdateCursor(); |
| 364 | 382 |
| 365 // Repaint the cursor. | 383 // Repaint the cursor. |
| 366 void RepaintCursor(); | 384 void RepaintCursor(); |
| 367 | 385 |
| 368 void PaintTextAndCursor(gfx::Canvas* canvas); | 386 void PaintTextAndCursor(gfx::Canvas* canvas); |
| 369 | 387 |
| 370 // Helper function to call MoveCursorTo on the TextfieldModel. | 388 // Helper function to call MoveCursorTo on the TextfieldModel. |
| 371 void MoveCursorTo(const gfx::Point& point, bool select); | 389 void MoveCursorTo(const gfx::Point& point, bool select); |
| 372 | 390 |
| 373 // Helper function to update the selection on a mouse drag. | |
| 374 void SelectThroughLastDragLocation(); | |
| 375 | |
| 376 // Convenience method to notify the InputMethod and TouchSelectionController. | 391 // Convenience method to notify the InputMethod and TouchSelectionController. |
| 377 void OnCaretBoundsChanged(); | 392 void OnCaretBoundsChanged(); |
| 378 | 393 |
| 379 // Convenience method to call TextfieldController::OnBeforeUserAction(); | 394 // Convenience method to call TextfieldController::OnBeforeUserAction(); |
| 380 void OnBeforeUserAction(); | 395 void OnBeforeUserAction(); |
| 381 | 396 |
| 382 // Convenience method to call TextfieldController::OnAfterUserAction(); | 397 // Convenience method to call TextfieldController::OnAfterUserAction(); |
| 383 void OnAfterUserAction(); | 398 void OnAfterUserAction(); |
| 384 | 399 |
| 385 // Calls |model_->Cut()| and notifies TextfieldController on success. | 400 // Calls |model_->Cut()| and notifies TextfieldController on success. |
| 386 bool Cut(); | 401 bool Cut(); |
| 387 | 402 |
| 388 // Calls |model_->Copy()| and notifies TextfieldController on success. | 403 // Calls |model_->Copy()| and notifies TextfieldController on success. |
| 389 bool Copy(); | 404 bool Copy(); |
| 390 | 405 |
| 391 // Calls |model_->Paste()| and calls TextfieldController::ContentsChanged() | 406 // Calls |model_->Paste()| and calls TextfieldController::ContentsChanged() |
| 392 // explicitly if paste succeeded. | 407 // explicitly if paste succeeded. |
| 393 bool Paste(); | 408 bool Paste(); |
| 394 | 409 |
| 395 // Utility function to prepare the context menu. | 410 // Utility function to prepare the context menu. |
| 396 void UpdateContextMenu(); | 411 void UpdateContextMenu(); |
| 397 | 412 |
| 398 // Tracks the mouse clicks for single/double/triple clicks. | |
| 399 void TrackMouseClicks(const ui::MouseEvent& event); | |
| 400 | |
| 401 // Returns true if the current text input type allows access by the IME. | 413 // Returns true if the current text input type allows access by the IME. |
| 402 bool ImeEditingAllowed() const; | 414 bool ImeEditingAllowed() const; |
| 403 | 415 |
| 404 // Reveals the password character at |index| for a set duration. | 416 // Reveals the password character at |index| for a set duration. |
| 405 // If |index| is -1, the existing revealed character will be reset. | 417 // If |index| is -1, the existing revealed character will be reset. |
| 406 void RevealPasswordChar(int index); | 418 void RevealPasswordChar(int index); |
| 407 | 419 |
| 408 void CreateTouchSelectionControllerAndNotifyIt(); | 420 void CreateTouchSelectionControllerAndNotifyIt(); |
| 409 | 421 |
| 410 // Updates the selection clipboard to any non-empty text selection for a non- | |
| 411 // password textfield. | |
| 412 void UpdateSelectionClipboard() const; | |
| 413 | |
| 414 // Pastes the selection clipboard for the specified mouse event. | |
| 415 void PasteSelectionClipboard(const ui::MouseEvent& event); | |
| 416 | |
| 417 // Called when editing a textfield fails because the textfield is readonly. | 422 // Called when editing a textfield fails because the textfield is readonly. |
| 418 void OnEditFailed(); | 423 void OnEditFailed(); |
| 419 | 424 |
| 420 // Returns true if an insertion cursor should be visible (a vertical bar, | 425 // Returns true if an insertion cursor should be visible (a vertical bar, |
| 421 // placed at the point new text will be inserted). | 426 // placed at the point new text will be inserted). |
| 422 bool ShouldShowCursor() const; | 427 bool ShouldShowCursor() const; |
| 423 | 428 |
| 424 // Returns true if an insertion cursor should be visible and blinking. | 429 // Returns true if an insertion cursor should be visible and blinking. |
| 425 bool ShouldBlinkCursor() const; | 430 bool ShouldBlinkCursor() const; |
| 426 | 431 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 | 485 |
| 481 // The input type of this text field. | 486 // The input type of this text field. |
| 482 ui::TextInputType text_input_type_; | 487 ui::TextInputType text_input_type_; |
| 483 | 488 |
| 484 // The input flags of this text field. | 489 // The input flags of this text field. |
| 485 int text_input_flags_; | 490 int text_input_flags_; |
| 486 | 491 |
| 487 // The timer to reveal the last typed password character. | 492 // The timer to reveal the last typed password character. |
| 488 base::OneShotTimer password_reveal_timer_; | 493 base::OneShotTimer password_reveal_timer_; |
| 489 | 494 |
| 490 // Tracks whether a user action is being performed; i.e. OnBeforeUserAction() | 495 // Tracks whether a user action is being performed which may change the |
| 491 // has been called, but OnAfterUserAction() has not yet been called. | 496 // textfield; i.e. OnBeforeUserAction() has been called, but |
| 497 // OnAfterUserAction() has not yet been called. |
| 492 bool performing_user_action_; | 498 bool performing_user_action_; |
| 493 | 499 |
| 494 // True if InputMethod::CancelComposition() should not be called. | 500 // True if InputMethod::CancelComposition() should not be called. |
| 495 bool skip_input_method_cancel_composition_; | 501 bool skip_input_method_cancel_composition_; |
| 496 | 502 |
| 497 // Insertion cursor repaint timer and visibility. | 503 // Insertion cursor repaint timer and visibility. |
| 498 base::RepeatingTimer cursor_blink_timer_; | 504 base::RepeatingTimer cursor_blink_timer_; |
| 499 | 505 |
| 500 // The drop cursor is a visual cue for where dragged text will be dropped. | 506 // The drop cursor is a visual cue for where dragged text will be dropped. |
| 501 bool drop_cursor_visible_; | 507 bool drop_cursor_visible_; |
| 502 gfx::SelectionModel drop_cursor_position_; | 508 gfx::SelectionModel drop_cursor_position_; |
| 503 | 509 |
| 504 // Is the user potentially dragging and dropping from this view? | 510 // Is the user potentially dragging and dropping from this view? |
| 505 bool initiating_drag_; | 511 bool initiating_drag_; |
| 506 | 512 |
| 507 // A timer and point used to modify the selection when dragging. | |
| 508 base::RepeatingTimer drag_selection_timer_; | |
| 509 gfx::Point last_drag_location_; | |
| 510 | |
| 511 // State variables used to track double and triple clicks. | |
| 512 size_t aggregated_clicks_; | |
| 513 base::TimeTicks last_click_time_; | |
| 514 gfx::Point last_click_location_; | |
| 515 gfx::Range double_click_word_; | |
| 516 | |
| 517 std::unique_ptr<ui::TouchEditingControllerDeprecated> | 513 std::unique_ptr<ui::TouchEditingControllerDeprecated> |
| 518 touch_selection_controller_; | 514 touch_selection_controller_; |
| 519 | 515 |
| 516 SelectionController selection_controller_; |
| 517 |
| 520 // Used to track touch drag starting location and offset to enable touch | 518 // Used to track touch drag starting location and offset to enable touch |
| 521 // scrolling. | 519 // scrolling. |
| 522 gfx::Point drag_start_location_; | 520 gfx::Point drag_start_location_; |
| 523 int drag_start_display_offset_; | 521 int drag_start_display_offset_; |
| 524 | 522 |
| 525 // Tracks if touch editing handles are hidden because user has started | 523 // Tracks if touch editing handles are hidden because user has started |
| 526 // scrolling. If |true|, handles are shown after scrolling ends. | 524 // scrolling. If |true|, handles are shown after scrolling ends. |
| 527 bool touch_handles_hidden_due_to_scroll_; | 525 bool touch_handles_hidden_due_to_scroll_; |
| 528 | 526 |
| 529 // True if this textfield should use a focus ring to indicate focus. | 527 // True if this textfield should use a focus ring to indicate focus. |
| 530 bool use_focus_ring_; | 528 bool use_focus_ring_; |
| 531 | 529 |
| 532 // Context menu related members. | 530 // Context menu related members. |
| 533 std::unique_ptr<ui::SimpleMenuModel> context_menu_contents_; | 531 std::unique_ptr<ui::SimpleMenuModel> context_menu_contents_; |
| 534 std::unique_ptr<views::MenuRunner> context_menu_runner_; | 532 std::unique_ptr<views::MenuRunner> context_menu_runner_; |
| 535 | 533 |
| 536 // Used to bind callback functions to this object. | 534 // Used to bind callback functions to this object. |
| 537 base::WeakPtrFactory<Textfield> weak_ptr_factory_; | 535 base::WeakPtrFactory<Textfield> weak_ptr_factory_; |
| 538 | 536 |
| 539 DISALLOW_COPY_AND_ASSIGN(Textfield); | 537 DISALLOW_COPY_AND_ASSIGN(Textfield); |
| 540 }; | 538 }; |
| 541 | 539 |
| 542 } // namespace views | 540 } // namespace views |
| 543 | 541 |
| 544 #endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_H_ | 542 #endif // UI_VIEWS_CONTROLS_TEXTFIELD_TEXTFIELD_H_ |
| OLD | NEW |