+ wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+ if ( text.empty() )
+ return;
+
+ // gtk_text_changed_callback() will set m_modified to true but m_modified
+ // shouldn't be changed by the program writing to the text control itself,
+ // so save the old value and restore when we're done
+ bool oldModified = m_modified;
+
+ if ( m_windowStyle & wxTE_MULTILINE )
+ {
+#ifdef __WXGTK20__
+
+#if wxUSE_UNICODE
+ wxCharBuffer buffer( wxConvUTF8.cWX2MB( text ) );
+#else
+ wxCharBuffer buffer( wxConvUTF8.cWC2MB( wxConvLocal.cWX2WC( text ) ) );
+#endif
+ if ( !buffer )
+ {
+ // what else can we do? at least don't crash...
+ return;
+ }
+
+ GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
+
+ // TODO: Call whatever is needed to delete the selection.
+ wxGtkTextInsert( m_text, text_buffer, m_defaultStyle, buffer );
+
+ GtkAdjustment *adj = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW(m_widget) );
+ // Scroll to cursor, but only if scrollbar thumb is at the very bottom
+ if ( adj->value == adj->upper - adj->page_size )
+ {
+ gtk_text_view_scroll_to_mark( GTK_TEXT_VIEW(m_text),
+ gtk_text_buffer_get_insert( text_buffer ), 0.0, FALSE, 0.0, 1.0 );
+ }
+#else // GTK 1.x
+ // After cursor movements, gtk_text_get_point() is wrong by one.
+ gtk_text_set_point( GTK_TEXT(m_text), GET_EDITABLE_POS(m_text) );
+
+ // always use m_defaultStyle, even if it is empty as otherwise
+ // resetting the style and appending some more text wouldn't work: if
+ // we don't specify the style explicitly, the old style would be used
+ gtk_editable_delete_selection( GTK_EDITABLE(m_text) );
+ wxGtkTextInsert(m_text, m_defaultStyle, text.c_str(), text.Len());
+
+ // we called wxGtkTextInsert with correct font, no need to do anything
+ // in UpdateFontIfNeeded() any longer
+ if ( !text.empty() )
+ {
+ SetUpdateFont(FALSE);
+ }
+
+ // Bring editable's cursor back uptodate.
+ SET_EDITABLE_POS(m_text, gtk_text_get_point( GTK_TEXT(m_text) ));
+#endif // GTK 1.x/2.0
+ }
+ else // single line
+ {
+ // First remove the selection if there is one
+ gtk_editable_delete_selection( GTK_EDITABLE(m_text) );
+
+ // This moves the cursor pos to behind the inserted text.
+ gint len = GET_EDITABLE_POS(m_text);
+
+#ifdef __WXGTK20__
+
+#if wxUSE_UNICODE
+ wxCharBuffer buffer( wxConvUTF8.cWX2MB( text ) );
+#else
+ wxCharBuffer buffer( wxConvUTF8.cWC2MB( wxConvLocal.cWX2WC( text ) ) );
+#endif
+ gtk_editable_insert_text( GTK_EDITABLE(m_text), buffer, strlen(buffer), &len );
+
+#else
+ gtk_editable_insert_text( GTK_EDITABLE(m_text), text.c_str(), text.Len(), &len );
+#endif
+
+ // Bring entry's cursor uptodate.
+ gtk_entry_set_position( GTK_ENTRY(m_text), len );
+ }
+
+ m_modified = oldModified;
+}
+
+void wxTextCtrl::AppendText( const wxString &text )
+{
+ SetInsertionPointEnd();
+ WriteText( text );
+}
+
+wxString wxTextCtrl::GetLineText( long lineNo ) const
+{
+ if (m_windowStyle & wxTE_MULTILINE)
+ {
+#ifndef __WXGTK20__
+ 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
+ GtkTextBuffer *text_buffer;
+ text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(m_text));
+ GtkTextIter line;
+ gtk_text_buffer_get_iter_at_line(text_buffer,&line,lineNo);
+ GtkTextIter end;
+ gtk_text_buffer_get_end_iter(text_buffer,&end );
+ gchar *text = gtk_text_buffer_get_text(text_buffer,&line,&end,TRUE);
+ wxString result(wxGTK_CONV_BACK(text));
+ g_free(text);
+ return result.BeforeFirst(wxT('\n'));
+#endif
+ }
+ 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)
+ {
+#ifdef __WXGTK20__
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
+
+ return gtk_text_buffer_get_line_count( buffer );
+#else
+ 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;
+ }
+#endif
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+void wxTextCtrl::SetInsertionPoint( long pos )
+{
+ wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
+
+ if ( IsMultiLine() )
+ {
+#ifdef __WXGTK20__
+ GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
+ GtkTextIter iter;
+ gtk_text_buffer_get_iter_at_offset( text_buffer, &iter, pos );
+ gtk_text_buffer_place_cursor( text_buffer, &iter );
+ gtk_text_view_scroll_mark_onscreen
+ (
+ GTK_TEXT_VIEW(m_text),
+ gtk_text_buffer_get_insert( text_buffer )
+ );
+#else // GTK+ 1.x
+ 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 this 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. Bug in GTK.
+ SET_EDITABLE_POS(m_text, gtk_text_get_point( GTK_TEXT(m_text) ));
+#endif // GTK+ 2/1
+ }
+ 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") );
+
+ if (m_windowStyle & wxTE_MULTILINE)
+ {
+#ifdef __WXGTK20__
+ GtkTextBuffer *text_buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_text) );
+ GtkTextIter end;
+ gtk_text_buffer_get_end_iter( text_buffer, &end );
+ gtk_text_buffer_place_cursor( text_buffer, &end );
+#else
+ SetInsertionPoint(gtk_text_get_length(GTK_TEXT(m_text)));
+#endif
+ }
+ else
+ {
+ gtk_entry_set_position( GTK_ENTRY(m_text), -1 );
+ }
+}
+
+void wxTextCtrl::SetEditable( bool editable )
+{
+ wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );