/Externals/wxWidgets3/src/common/textentrycmn.cpp
C++ | 472 lines | 272 code | 96 blank | 104 comment | 28 complexity | 5f955959f31397f43d9dc20520502d80 MD5 | raw file
- ///////////////////////////////////////////////////////////////////////////////
- // Name: src/common/textentrycmn.cpp
- // Purpose: wxTextEntryBase implementation
- // Author: Vadim Zeitlin
- // Created: 2007-09-26
- // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
- // Licence: wxWindows licence
- ///////////////////////////////////////////////////////////////////////////////
- // ============================================================================
- // declarations
- // ============================================================================
- // ----------------------------------------------------------------------------
- // headers
- // ----------------------------------------------------------------------------
- // for compilers that support precompilation, includes "wx.h".
- #include "wx/wxprec.h"
- #ifdef __BORLANDC__
- #pragma hdrstop
- #endif
- #if wxUSE_TEXTCTRL || wxUSE_COMBOBOX
- #ifndef WX_PRECOMP
- #include "wx/window.h"
- #include "wx/dataobj.h"
- #endif //WX_PRECOMP
- #include "wx/textentry.h"
- #include "wx/textcompleter.h"
- #include "wx/clipbrd.h"
- // ----------------------------------------------------------------------------
- // wxTextEntryHintData
- // ----------------------------------------------------------------------------
- class WXDLLIMPEXP_CORE wxTextEntryHintData
- {
- public:
- wxTextEntryHintData(wxTextEntryBase *entry, wxWindow *win)
- : m_entry(entry),
- m_win(win),
- m_text(m_entry->GetValue())
- {
- win->Bind(wxEVT_SET_FOCUS, &wxTextEntryHintData::OnSetFocus, this);
- win->Bind(wxEVT_KILL_FOCUS, &wxTextEntryHintData::OnKillFocus, this);
- win->Bind(wxEVT_TEXT, &wxTextEntryHintData::OnTextChanged, this);
- }
- // default dtor is ok
- // Get the real text of the control such as it was before we replaced it
- // with the hint.
- const wxString& GetText() const { return m_text; }
- // Set the hint to show, shouldn't be empty normally.
- //
- // This should be called after creating a new wxTextEntryHintData object
- // and may be called more times in the future.
- void SetHintString(const wxString& hint)
- {
- m_hint = hint;
- if ( !m_win->HasFocus() )
- ShowHintIfAppropriate();
- //else: The new hint will be shown later when we lose focus.
- }
- const wxString& GetHintString() const { return m_hint; }
- // This is called whenever the text control contents changes.
- //
- // We call it ourselves when this change generates an event but it's also
- // necessary to call it explicitly from wxTextEntry::ChangeValue() as it,
- // by design, does not generate any events.
- void HandleTextUpdate(const wxString& text)
- {
- m_text = text;
- // If we're called because of a call to Set or ChangeValue(), the
- // control may still have the hint text colour, reset it in this case.
- RestoreTextColourIfNecessary();
- }
- private:
- // Show the hint in the window if we should do it, i.e. if the window
- // doesn't have any text of its own.
- void ShowHintIfAppropriate()
- {
- // Never overwrite existing window text.
- if ( !m_text.empty() )
- return;
- // Save the old text colour and set a more inconspicuous one for the
- // hint.
- m_colFg = m_win->GetForegroundColour();
- m_win->SetForegroundColour(*wxLIGHT_GREY);
- m_entry->DoSetValue(m_hint, wxTextEntryBase::SetValue_NoEvent);
- }
- // Restore the original text colour if we had changed it to show the hint
- // and not restored it yet.
- void RestoreTextColourIfNecessary()
- {
- if ( m_colFg.IsOk() )
- {
- m_win->SetForegroundColour(m_colFg);
- m_colFg = wxColour();
- }
- }
- void OnSetFocus(wxFocusEvent& event)
- {
- // If we had been showing the hint before, remove it now and restore
- // the normal colour.
- if ( m_text.empty() )
- {
- RestoreTextColourIfNecessary();
- m_entry->DoSetValue(wxString(), wxTextEntryBase::SetValue_NoEvent);
- }
- event.Skip();
- }
- void OnKillFocus(wxFocusEvent& event)
- {
- // Restore the hint if the user didn't enter anything.
- ShowHintIfAppropriate();
- event.Skip();
- }
- void OnTextChanged(wxCommandEvent& event)
- {
- // Update the stored window text.
- //
- // Notice that we can't use GetValue() nor wxCommandEvent::GetString()
- // which uses it internally because this would just forward back to us
- // so go directly to the private method which returns the real control
- // contents.
- HandleTextUpdate(m_entry->DoGetValue());
- event.Skip();
- }
- // the text control we're associated with (as its interface and its window)
- wxTextEntryBase * const m_entry;
- wxWindow * const m_win;
- // the original foreground colour of m_win before we changed it
- wxColour m_colFg;
- // The hint passed to wxTextEntry::SetHint(), never empty.
- wxString m_hint;
- // The real text of the window.
- wxString m_text;
- wxDECLARE_NO_COPY_CLASS(wxTextEntryHintData);
- };
- // ============================================================================
- // wxTextEntryBase implementation
- // ============================================================================
- wxTextEntryBase::~wxTextEntryBase()
- {
- delete m_hintData;
- }
- // ----------------------------------------------------------------------------
- // text accessors
- // ----------------------------------------------------------------------------
- wxString wxTextEntryBase::GetValue() const
- {
- return m_hintData ? m_hintData->GetText() : DoGetValue();
- }
- wxString wxTextEntryBase::GetRange(long from, long to) const
- {
- wxString sel;
- wxString value = GetValue();
- if ( from < to && (long)value.length() >= to )
- {
- sel = value.substr(from, to - from);
- }
- return sel;
- }
- // ----------------------------------------------------------------------------
- // text operations
- // ----------------------------------------------------------------------------
- void wxTextEntryBase::ChangeValue(const wxString& value)
- {
- DoSetValue(value, SetValue_NoEvent);
- // As we didn't generate any events for wxTextEntryHintData to catch,
- // notify it explicitly about our changed contents.
- if ( m_hintData )
- m_hintData->HandleTextUpdate(value);
- }
- void wxTextEntryBase::AppendText(const wxString& text)
- {
- SetInsertionPointEnd();
- WriteText(text);
- }
- void wxTextEntryBase::DoSetValue(const wxString& value, int flags)
- {
- if ( value != DoGetValue() )
- {
- EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent));
- SelectAll();
- WriteText(value);
- SetInsertionPoint(0);
- }
- else // Same value, no need to do anything.
- {
- // Except that we still need to generate the event for consistency with
- // the normal case when the text does change.
- if ( flags & SetValue_SendEvent )
- SendTextUpdatedEvent(GetEditableWindow());
- }
- }
- void wxTextEntryBase::Replace(long from, long to, const wxString& value)
- {
- {
- EventsSuppressor noevents(this);
- Remove(from, to);
- }
- SetInsertionPoint(from);
- WriteText(value);
- }
- // ----------------------------------------------------------------------------
- // selection
- // ----------------------------------------------------------------------------
- bool wxTextEntryBase::HasSelection() const
- {
- long from, to;
- GetSelection(&from, &to);
- return from < to;
- }
- void wxTextEntryBase::RemoveSelection()
- {
- long from, to;
- GetSelection(& from, & to);
- if (from != -1 && to != -1)
- Remove(from, to);
- }
- wxString wxTextEntryBase::GetStringSelection() const
- {
- long from, to;
- GetSelection(&from, &to);
- return GetRange(from, to);
- }
- // ----------------------------------------------------------------------------
- // clipboard
- // ----------------------------------------------------------------------------
- bool wxTextEntryBase::CanCopy() const
- {
- return HasSelection();
- }
- bool wxTextEntryBase::CanCut() const
- {
- return CanCopy() && IsEditable();
- }
- bool wxTextEntryBase::CanPaste() const
- {
- if ( IsEditable() )
- {
- #if wxUSE_CLIPBOARD
- // check if there is any text on the clipboard
- if ( wxTheClipboard->IsSupported(wxDF_TEXT)
- #if wxUSE_UNICODE
- || wxTheClipboard->IsSupported(wxDF_UNICODETEXT)
- #endif // wxUSE_UNICODE
- )
- {
- return true;
- }
- #endif // wxUSE_CLIPBOARD
- }
- return false;
- }
- // ----------------------------------------------------------------------------
- // input restrictions
- // ----------------------------------------------------------------------------
- #ifndef wxHAS_NATIVE_TEXT_FORCEUPPER
- namespace
- {
- // Poor man's lambda: helper for binding ConvertToUpperCase() to the event
- struct ForceUpperFunctor
- {
- explicit ForceUpperFunctor(wxTextEntryBase* entry)
- : m_entry(entry)
- {
- }
- void operator()(wxCommandEvent& event)
- {
- event.Skip();
- m_entry->ConvertToUpperCase();
- }
- wxTextEntryBase* const m_entry;
- };
- } // anonymous namespace
- #endif // !wxHAS_NATIVE_TEXT_FORCEUPPER
- void wxTextEntryBase::ConvertToUpperCase()
- {
- const wxString& valueOld = GetValue();
- const wxString& valueNew = valueOld.Upper();
- if ( valueNew != valueOld )
- {
- long from, to;
- GetSelection(&from, &to);
- ChangeValue(valueNew);
- SetSelection(from, to);
- }
- }
- void wxTextEntryBase::ForceUpper()
- {
- // Do nothing if this method is never called because a native override is
- // provided: this is just a tiny size-saving optimization, nothing else.
- #ifndef wxHAS_NATIVE_TEXT_FORCEUPPER
- wxWindow* const win = GetEditableWindow();
- wxCHECK_RET( win, wxS("can't be called before creating the window") );
- // Convert the current control contents to upper case
- ConvertToUpperCase();
- // And ensure that any text entered in the future is converted too
- win->Bind(wxEVT_TEXT, ForceUpperFunctor(this));
- #endif // !wxHAS_NATIVE_TEXT_FORCEUPPER
- }
- // ----------------------------------------------------------------------------
- // hints support
- // ----------------------------------------------------------------------------
- bool wxTextEntryBase::SetHint(const wxString& hint)
- {
- if ( !hint.empty() )
- {
- if ( !m_hintData )
- m_hintData = new wxTextEntryHintData(this, GetEditableWindow());
- m_hintData->SetHintString(hint);
- }
- else if ( m_hintData )
- {
- // Setting empty hint removes any currently set one.
- delete m_hintData;
- m_hintData = NULL;
- }
- //else: Setting empty hint when we don't have any doesn't do anything.
- return true;
- }
- wxString wxTextEntryBase::GetHint() const
- {
- return m_hintData ? m_hintData->GetHintString() : wxString();
- }
- // ----------------------------------------------------------------------------
- // margins support
- // ----------------------------------------------------------------------------
- bool wxTextEntryBase::DoSetMargins(const wxPoint& WXUNUSED(pt))
- {
- return false;
- }
- wxPoint wxTextEntryBase::DoGetMargins() const
- {
- return wxPoint(-1, -1);
- }
- // ----------------------------------------------------------------------------
- // events
- // ----------------------------------------------------------------------------
- /* static */
- bool wxTextEntryBase::SendTextUpdatedEvent(wxWindow *win)
- {
- wxCHECK_MSG( win, false, "can't send an event without a window" );
- wxCommandEvent event(wxEVT_TEXT, win->GetId());
- // do not do this as it could be very inefficient if the text control
- // contains a lot of text and we're not using ref-counted wxString
- // implementation -- instead, event.GetString() will query the control for
- // its current text if needed
- //event.SetString(win->GetValue());
- event.SetEventObject(win);
- return win->HandleWindowEvent(event);
- }
- // ----------------------------------------------------------------------------
- // auto-completion stubs
- // ----------------------------------------------------------------------------
- wxTextCompleter::~wxTextCompleter()
- {
- }
- bool wxTextCompleterSimple::Start(const wxString& prefix)
- {
- m_index = 0;
- m_completions.clear();
- GetCompletions(prefix, m_completions);
- return !m_completions.empty();
- }
- wxString wxTextCompleterSimple::GetNext()
- {
- if ( m_index == m_completions.size() )
- return wxString();
- return m_completions[m_index++];
- }
- bool wxTextEntryBase::DoAutoCompleteCustom(wxTextCompleter *completer)
- {
- // We don't do anything here but we still need to delete the completer for
- // consistency with the ports that do implement this method and take
- // ownership of the pointer.
- delete completer;
- return false;
- }
- #endif // wxUSE_TEXTCTRL || wxUSE_COMBOBOX