// Purpose: wxTextEntryBase implementation
// Author: Vadim Zeitlin
// Created: 2007-09-26
-// RCS-ID: $Id$
// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#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_TEXT,
+ 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;
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();
void wxTextEntryBase::DoSetValue(const wxString& value, int flags)
{
- EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent));
+ if ( value != DoGetValue() )
+ {
+ EventsSuppressor noeventsIf(this, !(flags & SetValue_SendEvent));
- SelectAll();
- WriteText(value);
+ SelectAll();
+ WriteText(value);
- SetInsertionPoint(0);
+ 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)
Remove(from, to);
}
+ SetInsertionPoint(from);
WriteText(value);
}
+// ----------------------------------------------------------------------------
+// selection
+// ----------------------------------------------------------------------------
+
bool wxTextEntryBase::HasSelection() const
{
long from, to;
return GetRange(from, to);
}
+// ----------------------------------------------------------------------------
+// clipboard
+// ----------------------------------------------------------------------------
+
bool wxTextEntryBase::CanCopy() const
{
return HasSelection();
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_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