diff --git a/docs/changes.txt b/docs/changes.txt index 420c69575c..2a25761bfd 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -171,6 +171,7 @@ wxGTK: - Make wxUIActionSimulator work with GTK+ 3 (Scott Talbert). - Make wxBORDER_NONE work for wxTextCtrl with GTK+ 3 (Adrien Tétar). - Apply wxTextCtrl::SetDefaultStyle() to user-entered text (Andreas Falkenhahn). +- Fix wxTextCtrl::GetStyle() with GTK+ 3. - Support background colour in wxDataViewCtrl attributes. - Improve wxSpinCtrl best size calculation. - Implement support for icon locations in wxMimeTypesManager (Hanmac). diff --git a/include/wx/catch_cppunit.h b/include/wx/catch_cppunit.h index 6d14137de3..22ebcf12f9 100644 --- a/include/wx/catch_cppunit.h +++ b/include/wx/catch_cppunit.h @@ -202,22 +202,24 @@ inline std::string wxGetCurrentTestName() public: \ void runTest() wxOVERRIDE \ { \ - struct EatNextSemicolon + using namespace wxPrivate; \ + TempStringAssign setClass(wxTheCurrentTestClass, #testclass) -#define CPPUNIT_TEST(testname) \ - SECTION(#testname " test") \ - { \ - setUp(); \ - try \ - { \ - testname(); \ - } \ - catch ( ... ) \ - { \ - tearDown(); \ - throw; \ - } \ - tearDown(); \ +#define CPPUNIT_TEST(testname) \ + SECTION(#testname) \ + { \ + TempStringAssign setMethod(wxTheCurrentTestMethod, #testname); \ + setUp(); \ + try \ + { \ + testname(); \ + } \ + catch ( ... ) \ + { \ + tearDown(); \ + throw; \ + } \ + tearDown(); \ } #define CPPUNIT_TEST_SUITE_END() \ diff --git a/interface/wx/textctrl.h b/interface/wx/textctrl.h index 150a137ec3..a2c9615d4a 100644 --- a/interface/wx/textctrl.h +++ b/interface/wx/textctrl.h @@ -1033,6 +1033,31 @@ public: correspond to the positions in the value string. + @section textctrl_positions_xy wxTextCtrl Positions and Coordinates + + It is possible to use either linear positions, i.e. roughly (but @e not + always exactly, as explained in the previous section) the index of the + character in the text contained in the control or X-Y coordinates, i.e. + column and line of the character when working with this class and it + provides the functions PositionToXY() and XYToPosition() to convert between + the two. + + Additionally, a position in the control can be converted to its coordinates + in pixels using PositionToCoords() which can be useful to e.g. show a popup + menu near the given character. And, in the other direction, HitTest() can + be used to find the character under, or near, the given pixel coordinates. + + To be more precise, positions actually refer to the gaps between characters + and not the characters themselves. Thus, position 0 is the one before the + very first character in the control and so is a valid position even when + the control is empty. And if the control contains a single character, it + has two valid positions: 0 before this character and 1 -- after it. This, + when the documentation of various functions mentions "invalid position", it + doesn't consider the position just after the last character of the line to + be invalid, only the positions beyond that one (e.g. 2 and greater in the + single character example) are actually invalid. + + @section textctrl_styles wxTextCtrl Styles. Multi-line text controls support styling, i.e. provide a possibility to set diff --git a/src/generic/graphicc.cpp b/src/generic/graphicc.cpp index 12e858d9c9..c83910def7 100644 --- a/src/generic/graphicc.cpp +++ b/src/generic/graphicc.cpp @@ -88,6 +88,7 @@ using namespace std; #ifndef __WXGTK3__ #include "wx/gtk/dc.h" #endif +#include "wx/gtk/private/object.h" #endif #ifdef __WXQT__ @@ -2605,7 +2606,7 @@ void wxCairoContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y) if ( ((wxCairoFontData*)m_font.GetRefData())->Apply(this) ) { #ifdef __WXGTK__ - PangoLayout *layout = pango_cairo_create_layout (m_context); + wxGtkObject layout(pango_cairo_create_layout (m_context)); const wxFont& font = static_cast(m_font.GetRefData())->GetFont(); pango_layout_set_font_description(layout, font.GetNativeFontInfo()->description); pango_layout_set_text(layout, data, data.length()); @@ -2614,8 +2615,6 @@ void wxCairoContext::DoDrawText(const wxString& str, wxDouble x, wxDouble y) cairo_move_to(m_context, x, y); pango_cairo_show_layout (m_context, layout); - g_object_unref (layout); - // Don't use Cairo text API, we already did everything. return; #endif @@ -2644,7 +2643,10 @@ void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDoub if ( externalLeading ) *externalLeading = 0; - if ( str.empty()) + // We can skip computing the string width and height if it is empty, but + // not its descent and/or external leading, which still needs to be + // returned even for an empty string. + if ( str.empty() && !descent && !externalLeading ) return; if ( ((wxCairoFontData*)m_font.GetRefData())->Apply((wxCairoContext*)this) ) @@ -2652,7 +2654,7 @@ void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDoub #ifdef __WXGTK__ int w, h; - PangoLayout *layout = pango_cairo_create_layout (m_context); + wxGtkObject layout(pango_cairo_create_layout (m_context)); const wxFont& font = static_cast(m_font.GetRefData())->GetFont(); pango_layout_set_font_description(layout, font.GetNativeFontInfo()->description); const wxCharBuffer data = str.utf8_str(); @@ -2673,7 +2675,6 @@ void wxCairoContext::GetTextExtent( const wxString &str, wxDouble *width, wxDoub pango_layout_iter_free(iter); *descent = h - PANGO_PIXELS(baseline); } - g_object_unref (layout); return; #endif } @@ -2720,7 +2721,7 @@ void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& int w = 0; if (data.length()) { - PangoLayout* layout = pango_cairo_create_layout(m_context); + wxGtkObject layout(pango_cairo_create_layout(m_context)); const wxFont& font = static_cast(m_font.GetRefData())->GetFont(); pango_layout_set_font_description(layout, font.GetNativeFontInfo()->description); pango_layout_set_text(layout, data, data.length()); @@ -2732,7 +2733,6 @@ void wxCairoContext::GetPartialTextExtents(const wxString& text, wxArrayDouble& widths.Add(PANGO_PIXELS(w)); } while (pango_layout_iter_next_cluster(iter)); pango_layout_iter_free(iter); - g_object_unref(layout); } size_t i = widths.GetCount(); const size_t len = text.length(); diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 6f90877e3d..1ea2442ffa 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -4097,7 +4097,7 @@ void wxListMainWindow::DeleteItem( long lindex ) // with many items, the vertical scroll position may change so that the new // last item is not visible any longer, which is very annoying from the // user point of view. Ensure that whatever happens, this item is visible. - if (count > 1) + if ( count > 1 && m_current != (size_t)-1 ) EnsureVisible(m_current); } diff --git a/src/generic/odcombo.cpp b/src/generic/odcombo.cpp index 1f7c923839..89ec54016b 100644 --- a/src/generic/odcombo.cpp +++ b/src/generic/odcombo.cpp @@ -991,9 +991,7 @@ void wxOwnerDrawnComboBox::DoClear() GetVListBoxComboPopup()->Clear(); - // NB: This really needs to be SetValue() instead of ChangeValue(), - // as wxTextEntry API expects an event to be sent. - SetValue(wxEmptyString); + wxTextEntry::Clear(); } void wxOwnerDrawnComboBox::Clear() diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp index 56f5848901..4aa72d774f 100644 --- a/src/gtk/textctrl.cpp +++ b/src/gtk/textctrl.cpp @@ -1046,7 +1046,12 @@ void wxTextCtrl::WriteText( const wxString &text ) wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") ); if ( text.empty() ) + { + // We don't need to actually do anything, but we still need to generate + // an event expected from this call. + SendTextUpdatedEvent(this); return; + } // we're changing the text programmatically DontMarkDirtyOnNextChange(); @@ -1187,20 +1192,35 @@ long wxTextCtrl::XYToPosition(long x, long y ) const { if ( IsSingleLine() ) { - - if ( y != 0 || x >= GTKGetEntryTextLength(GTK_ENTRY(m_text)) ) + if ( y != 0 || x > GTKGetEntryTextLength(GTK_ENTRY(m_text)) ) return -1; return x; } + const gint numLines = gtk_text_buffer_get_line_count (m_buffer); + GtkTextIter iter; - if (y >= gtk_text_buffer_get_line_count (m_buffer)) + if (y >= numLines) return -1; gtk_text_buffer_get_iter_at_line(m_buffer, &iter, y); - if (x >= gtk_text_iter_get_chars_in_line (&iter)) + + const gint lineLength = gtk_text_iter_get_chars_in_line (&iter); + if (x > lineLength) + { + // This coordinate is always invalid. return -1; + } + + if (x == lineLength) + { + // In this case the coordinate is considered to be valid by wx if this + // is the last line, as it corresponds to the last position beyond the + // last character of the text, and invalid otherwise. + if (y != numLines - 1) + return -1; + } return gtk_text_iter_get_offset(&iter) + x; } @@ -1757,8 +1777,13 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) } else // have custom attributes { +#ifdef __WXGTK3__ + style.SetBackgroundColour(*pattr->appearance.rgba[0]); + style.SetTextColour(*pattr->appearance.rgba[1]); +#else style.SetBackgroundColour(pattr->appearance.bg_color); style.SetTextColour(pattr->appearance.fg_color); +#endif const wxGtkString pangoFontString(pango_font_description_to_string(pattr->font)); diff --git a/tests/controls/textctrltest.cpp b/tests/controls/textctrltest.cpp index 175d46d011..3abcbfe868 100644 --- a/tests/controls/textctrltest.cpp +++ b/tests/controls/textctrltest.cpp @@ -397,7 +397,7 @@ void TextCtrlTestCase::Style() #ifndef __WXOSX__ delete m_text; // We need wxTE_RICH under windows for style support - CreateText(wxTE_RICH); + CreateText(wxTE_MULTILINE|wxTE_RICH); // Red text on a white background m_text->SetDefaultStyle(wxTextAttr(*wxRED, *wxWHITE)); @@ -431,20 +431,21 @@ void TextCtrlTestCase::Style() wxTextAttr style; // We have to check that styles are supported - if(m_text->GetStyle(3, style)) + if ( !m_text->GetStyle(3, style) ) { - CPPUNIT_ASSERT_EQUAL(style.GetTextColour(), *wxRED); - CPPUNIT_ASSERT_EQUAL(style.GetBackgroundColour(), *wxWHITE); + WARN("Retrieving text style not supported, skipping test."); + return; } + CHECK( style.GetTextColour() == *wxRED ); + CHECK( style.GetBackgroundColour() == *wxWHITE ); + // And then setting the style - if(m_text->SetStyle(15, 18, style)) - { - m_text->GetStyle(17, style); + REQUIRE( m_text->SetStyle(15, 18, style) ); - CPPUNIT_ASSERT_EQUAL(style.GetTextColour(), *wxRED); - CPPUNIT_ASSERT_EQUAL(style.GetBackgroundColour(), *wxWHITE); - } + REQUIRE( m_text->GetStyle(17, style) ); + CHECK( style.GetTextColour() == *wxRED ); + CHECK( style.GetBackgroundColour() == *wxWHITE ); #endif } @@ -603,7 +604,7 @@ void TextCtrlTestCase::PositionToCoordsRich2() void TextCtrlTestCase::DoPositionToCoordsTestWithStyle(long style) { delete m_text; - CreateText(style); + CreateText(style|wxTE_MULTILINE); // Asking for invalid index should fail. WX_ASSERT_FAILS_WITH_ASSERT( m_text->PositionToCoords(1) ); @@ -667,11 +668,31 @@ void TextCtrlTestCase::DoPositionToCoordsTestWithStyle(long style) // last position is in its bounds. m_text->SetInsertionPointEnd(); - CPPUNIT_ASSERT( m_text->PositionToCoords(0).y < 0 ); - CPPUNIT_ASSERT - ( - m_text->PositionToCoords(m_text->GetInsertionPoint()).y <= TEXT_HEIGHT - ); + const int pos = m_text->GetInsertionPoint(); + + // wxGTK needs to yield here to update the text control. +#ifdef __WXGTK__ + wxStopWatch sw; + while ( m_text->PositionToCoords(0).y == 0 || + m_text->PositionToCoords(pos).y > TEXT_HEIGHT ) + { + if ( sw.Time() > 1000 ) + { + FAIL("Timed out waiting for wxTextCtrl update."); + break; + } + + wxYield(); + } +#endif // __WXGTK__ + + wxPoint coords = m_text->PositionToCoords(0); + INFO("First position coords = " << coords); + CPPUNIT_ASSERT( coords.y < 0 ); + + coords = m_text->PositionToCoords(pos); + INFO("Position is " << pos << ", coords = " << coords); + CPPUNIT_ASSERT( coords.y <= TEXT_HEIGHT ); } void TextCtrlTestCase::PositionToXYMultiLine() @@ -935,6 +956,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style) for( long x = 0; x < maxLineLength_0+1; x++ ) { long p = m_text->XYToPosition(x, y); + INFO("x=" << x << ", y=" << y); CPPUNIT_ASSERT_EQUAL( pos_0[y][x], p ); } @@ -951,6 +973,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style) for( long x = 0; x < maxLineLength_1+1; x++ ) { long p = m_text->XYToPosition(x, y); + INFO("x=" << x << ", y=" << y); CPPUNIT_ASSERT_EQUAL( pos_1[y][x], p ); } @@ -985,6 +1008,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style) for( long x = 0; x < maxLineLength_2+1; x++ ) { long p = m_text->XYToPosition(x, y); + INFO("x=" << x << ", y=" << y); CPPUNIT_ASSERT_EQUAL( ref_pos_2[y][x], p ); } @@ -1021,6 +1045,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style) for( long x = 0; x < maxLineLength_3+1; x++ ) { long p = m_text->XYToPosition(x, y); + INFO("x=" << x << ", y=" << y); CPPUNIT_ASSERT_EQUAL( ref_pos_3[y][x], p ); } @@ -1061,6 +1086,7 @@ void TextCtrlTestCase::DoXYToPositionMultiLine(long style) for( long x = 0; x < maxLineLength_4+1; x++ ) { long p = m_text->XYToPosition(x, y); + INFO("x=" << x << ", y=" << y); CPPUNIT_ASSERT_EQUAL( ref_pos_4[y][x], p ); } } diff --git a/tests/controls/textentrytest.cpp b/tests/controls/textentrytest.cpp index b5c4fddfe9..96b121de84 100644 --- a/tests/controls/textentrytest.cpp +++ b/tests/controls/textentrytest.cpp @@ -57,6 +57,10 @@ void TextEntryTestCase::TextChangeEvents() CPPUNIT_ASSERT_EQUAL( 1, updated.GetCount() ); updated.Clear(); + entry->SetValue(""); + CPPUNIT_ASSERT_EQUAL( 1, updated.GetCount() ); + updated.Clear(); + entry->ChangeValue("bar"); CPPUNIT_ASSERT_EQUAL( 0, updated.GetCount() ); diff --git a/tests/controls/windowtest.cpp b/tests/controls/windowtest.cpp index 9d6457c905..ffc6fdf228 100644 --- a/tests/controls/windowtest.cpp +++ b/tests/controls/windowtest.cpp @@ -142,7 +142,7 @@ void WindowTestCase::FocusEvent() m_window->SetFocus(); - CPPUNIT_ASSERT_EQUAL(1, setfocus.GetCount()); + WX_ASSERT_EVENT_OCCURS(setfocus, 1); CPPUNIT_ASSERT(m_window->HasFocus()); wxButton* button = new wxButton(wxTheApp->GetTopWindow(), wxID_ANY); diff --git a/tests/events/evthandler.cpp b/tests/events/evthandler.cpp index ac8b59bd0c..b25f4f65aa 100644 --- a/tests/events/evthandler.cpp +++ b/tests/events/evthandler.cpp @@ -127,6 +127,11 @@ private: wxDECLARE_EVENT_TABLE(); }; +// Avoid gcc warning about some of the functions defined by the expansion of +// the event table macros being unused: they are indeed unused, but we still +// want to have them to check that they compile. +wxGCC_WARNING_SUPPRESS(unused-function) + wxBEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler) EVT_IDLE(MyClassWithEventTable::OnIdle) @@ -138,6 +143,8 @@ wxBEGIN_EVENT_TABLE(MyClassWithEventTable, wxEvtHandler) //EVT_IDLE(MyClassWithEventTable::OnAnotherEvent) wxEND_EVENT_TABLE() +wxGCC_WARNING_RESTORE(unused-function) + } // anonymous namespace diff --git a/tests/events/keyboard.cpp b/tests/events/keyboard.cpp index cb54248c35..29f849aab3 100644 --- a/tests/events/keyboard.cpp +++ b/tests/events/keyboard.cpp @@ -16,9 +16,7 @@ #pragma hdrstop #endif -// FIXME: As all the other tests involving wxUIActionSimulator, this one is -// broken under OS X, the test window siply never gets any events. -#if wxUSE_UIACTIONSIMULATOR && !defined(__WXOSX__) +#if wxUSE_UIACTIONSIMULATOR #ifndef WX_PRECOMP #include "wx/app.h" @@ -204,12 +202,12 @@ public: private: CPPUNIT_TEST_SUITE( KeyboardEventTestCase ); - CPPUNIT_TEST( NormalLetter ); - CPPUNIT_TEST( NormalSpecial ); - CPPUNIT_TEST( CtrlLetter ); - CPPUNIT_TEST( CtrlSpecial ); - CPPUNIT_TEST( ShiftLetter ); - CPPUNIT_TEST( ShiftSpecial ); + WXUISIM_TEST( NormalLetter ); + WXUISIM_TEST( NormalSpecial ); + WXUISIM_TEST( CtrlLetter ); + WXUISIM_TEST( CtrlSpecial ); + WXUISIM_TEST( ShiftLetter ); + WXUISIM_TEST( ShiftSpecial ); CPPUNIT_TEST_SUITE_END(); void NormalLetter(); diff --git a/tests/events/propagation.cpp b/tests/events/propagation.cpp index 3f3d1eb8d3..bf2d40e7d0 100644 --- a/tests/events/propagation.cpp +++ b/tests/events/propagation.cpp @@ -37,7 +37,12 @@ // some tests there. But this should be fixed and the tests reenabled // because wxPaintEvent propagation in wxScrolledWindow is a perfect // example of fragile code that could be broken under OS X. -#ifndef __WXOSX__ +// +// FIXME: Under GTK+ 3 the test is broken because a simple wxYield() is not +// enough to map the frame. It should be also fixed there by waiting for +// it to come up, with some timeout, but for now it always fails, so +// it's useless to run it. +#if !defined(__WXOSX__) && !defined(__WXGTK3__) #define CAN_TEST_PAINT_EVENTS #endif diff --git a/tests/test.cpp b/tests/test.cpp index ba853d53ea..5c01d4875a 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -416,10 +416,12 @@ wxTestGLogHandler(const gchar* domain, const gchar* message, gpointer data) { - fprintf(stderr, "** GTK log message while running %s(): ", + fprintf(stderr, "\n*** GTK log message while running %s(): ", wxGetCurrentTestName().c_str()); g_log_default_handler(domain, level, message, data); + + fprintf(stderr, "\n"); } #endif // __WXGTK__ diff --git a/tests/toplevel/toplevel.cpp b/tests/toplevel/toplevel.cpp index 61c52207ed..53ea380960 100644 --- a/tests/toplevel/toplevel.cpp +++ b/tests/toplevel/toplevel.cpp @@ -73,7 +73,7 @@ void TopLevelWindowTestCase::FrameShowTest() void TopLevelWindowTestCase::TopLevelWindowShowTest(wxTopLevelWindow* tlw) { - CPPUNIT_ASSERT(!tlw->IsShown()); + CHECK(!tlw->IsShown()); wxTextCtrl* textCtrl = new wxTextCtrl(tlw, -1, "test"); textCtrl->SetFocus(); @@ -81,19 +81,26 @@ void TopLevelWindowTestCase::TopLevelWindowShowTest(wxTopLevelWindow* tlw) // only run this test on platforms where ShowWithoutActivating is implemented. #if defined(__WXMSW__) || defined(__WXMAC__) tlw->ShowWithoutActivating(); - CPPUNIT_ASSERT(tlw->IsShown()); - CPPUNIT_ASSERT(!tlw->IsActive()); + CHECK(tlw->IsShown()); + CHECK(!tlw->IsActive()); tlw->Hide(); - CPPUNIT_ASSERT(!tlw->IsShown()); - CPPUNIT_ASSERT(!tlw->IsActive()); + CHECK(!tlw->IsShown()); + CHECK(!tlw->IsActive()); #endif tlw->Show(true); - CPPUNIT_ASSERT(tlw->IsActive()); - CPPUNIT_ASSERT(tlw->IsShown()); + + // wxGTK needs many event loop iterations before the TLW becomes active and + // this doesn't happen in this test, so avoid checking for it. +#ifndef __WXGTK__ + CHECK(tlw->IsActive()); +#endif + CHECK(tlw->IsShown()); tlw->Hide(); - CPPUNIT_ASSERT(!tlw->IsShown()); - CPPUNIT_ASSERT(tlw->IsActive()); + CHECK(!tlw->IsShown()); +#ifndef __WXGTK__ + CHECK(tlw->IsActive()); +#endif }