/////////////////////////////////////////////////////////////////////////////// // Name: src/common/textentrycmn.cpp // Purpose: wxTextEntryBase implementation // Author: Vadim Zeitlin // Created: 2007-09-26 // RCS-ID: $Id: textentrycmn.cpp 67515 2011-04-16 17:27:34Z VZ $ // Copyright: (c) 2007 Vadim Zeitlin // 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 wxBIND_OR_CONNECT_HACK_ONLY_BASE_CLASS { public: wxTextEntryHintData(wxTextEntryBase *entry, wxWindow *win) : m_entry(entry), m_win(win), m_text(m_entry->GetValue()) { wxBIND_OR_CONNECT_HACK(win, wxEVT_SET_FOCUS, wxFocusEventHandler, wxTextEntryHintData::OnSetFocus, this); wxBIND_OR_CONNECT_HACK(win, wxEVT_KILL_FOCUS, wxFocusEventHandler, wxTextEntryHintData::OnKillFocus, this); wxBIND_OR_CONNECT_HACK(win, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler, 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) { EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent)); SelectAll(); WriteText(value); SetInsertionPoint(0); } 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; } // ---------------------------------------------------------------------------- // 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_COMMAND_TEXT_UPDATED, 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