+ wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+ if ( text.empty() )
+ return;
+
+#if wxUSE_UNICODE
+ wxWX2MBbuf buf = text.mbc_str();
+ const char *txt = buf;
+ size_t txtlen = strlen(buf);
+#else
+ const char *txt = text;
+ size_t txtlen = text.length();
+#endif
+
+ if ( m_windowStyle & wxTE_MULTILINE )
+ {
+ // After cursor movements, gtk_text_get_point() is wrong by one.
+ gtk_text_set_point( GTK_TEXT(m_text), GET_EDITABLE_POS(m_text) );
+
+ // if we have any special style, use it
+ if ( !m_defaultStyle.IsDefault() )
+ {
+ GetInsertionPoint();
+
+ wxGtkTextInsert(m_text, m_defaultStyle, txt, txtlen);
+ }
+ else // no style
+ {
+ gint len = GET_EDITABLE_POS(m_text);
+ gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len );
+ }
+
+ // Bring editable's cursor back uptodate.
+ SET_EDITABLE_POS(m_text, gtk_text_get_point( GTK_TEXT(m_text) ));
+ }
+ else // single line
+ {
+ // This moves the cursor pos to behind the inserted text.
+ gint len = GET_EDITABLE_POS(m_text);
+ gtk_editable_insert_text( GTK_EDITABLE(m_text), txt, txtlen, &len );
+
+ // Bring editable's cursor uptodate.
+ len += text.Len();
+
+ // Bring entry's cursor uptodate.
+ gtk_entry_set_position( GTK_ENTRY(m_text), len );
+ }
+
+ m_modified = TRUE;
+}
+
+void wxTextCtrl::AppendText( const wxString &text )
+{
+ SetInsertionPointEnd();
+ WriteText( text );
+}
+
+wxString wxTextCtrl::GetLineText( long lineNo ) const
+{
+ if (m_windowStyle & wxTE_MULTILINE)
+ {
+ gint len = gtk_text_get_length( GTK_TEXT(m_text) );
+ char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
+
+ if (text)
+ {
+ wxString buf(wxT(""));
+ long i;
+ int currentLine = 0;
+ for (i = 0; currentLine != lineNo && text[i]; i++ )
+ if (text[i] == '\n')
+ currentLine++;
+ // Now get the text
+ int j;
+ for (j = 0; text[i] && text[i] != '\n'; i++, j++ )
+ buf += text[i];
+
+ g_free( text );
+ return buf;
+ }
+ else
+ {
+ return wxEmptyString;
+ }
+ }
+ else
+ {
+ if (lineNo == 0) return GetValue();
+ return wxEmptyString;
+ }
+}
+
+void wxTextCtrl::OnDropFiles( wxDropFilesEvent &WXUNUSED(event) )
+{
+ /* If you implement this, don't forget to update the documentation!
+ * (file docs/latex/wx/text.tex) */
+ wxFAIL_MSG( wxT("wxTextCtrl::OnDropFiles not implemented") );
+}
+
+bool wxTextCtrl::PositionToXY(long pos, long *x, long *y ) const
+{
+ if ( m_windowStyle & wxTE_MULTILINE )
+ {
+ wxString text = GetValue();
+
+ // cast to prevent warning. But pos really should've been unsigned.
+ if( (unsigned long)pos > text.Len() )
+ return FALSE;
+
+ *x=0; // First Col
+ *y=0; // First Line
+
+ const wxChar* stop = text.c_str() + pos;
+ for ( const wxChar *p = text.c_str(); p < stop; p++ )
+ {
+ if (*p == wxT('\n'))
+ {
+ (*y)++;
+ *x=0;
+ }
+ else
+ (*x)++;
+ }
+ }
+ else // single line control
+ {
+ if ( pos <= GTK_ENTRY(m_text)->text_length )
+ {
+ *y = 0;
+ *x = pos;
+ }
+ else
+ {
+ // index out of bounds
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+long wxTextCtrl::XYToPosition(long x, long y ) const
+{
+ if (!(m_windowStyle & wxTE_MULTILINE)) return 0;
+
+ long pos=0;
+ for( int i=0; i<y; i++ ) pos += GetLineLength(i) + 1; // one for '\n'
+
+ pos += x;
+ return pos;
+}
+
+int wxTextCtrl::GetLineLength(long lineNo) const
+{
+ wxString str = GetLineText (lineNo);
+ return (int) str.Length();
+}
+
+int wxTextCtrl::GetNumberOfLines() const
+{
+ if (m_windowStyle & wxTE_MULTILINE)
+ {
+ gint len = gtk_text_get_length( GTK_TEXT(m_text) );
+ char *text = gtk_editable_get_chars( GTK_EDITABLE(m_text), 0, len );
+
+ if (text)
+ {
+ int currentLine = 0;
+ for (int i = 0; i < len; i++ )
+ {
+ if (text[i] == '\n')
+ currentLine++;
+ }
+ g_free( text );
+
+ // currentLine is 0 based, add 1 to get number of lines
+ return currentLine + 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+void wxTextCtrl::SetInsertionPoint( long pos )
+{
+ wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+ if (m_windowStyle & wxTE_MULTILINE)
+ {
+ /* seems to be broken in GTK 1.0.X:
+ gtk_text_set_point( GTK_TEXT(m_text), (int)pos ); */
+
+ gtk_signal_disconnect_by_func( GTK_OBJECT(m_text),
+ GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
+
+ /* we fake a set_point by inserting and deleting. as the user
+ isn't supposed to get to know about thos non-sense, we
+ disconnect so that no events are sent to the user program. */
+
+ gint tmp = (gint)pos;
+ gtk_editable_insert_text( GTK_EDITABLE(m_text), " ", 1, &tmp );
+ gtk_editable_delete_text( GTK_EDITABLE(m_text), tmp-1, tmp );
+
+ gtk_signal_connect( GTK_OBJECT(m_text), "changed",
+ GTK_SIGNAL_FUNC(gtk_text_changed_callback), (gpointer)this);
+
+ /* bring editable's cursor uptodate. another bug in GTK. */
+
+ SET_EDITABLE_POS(m_text, gtk_text_get_point( GTK_TEXT(m_text) ));
+ }
+ else
+ {
+ gtk_entry_set_position( GTK_ENTRY(m_text), (int)pos );
+
+ /* bring editable's cursor uptodate. bug in GTK. */
+
+ SET_EDITABLE_POS(m_text, (guint32)pos);
+ }
+}
+
+void wxTextCtrl::SetInsertionPointEnd()
+{
+ wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );