X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c83576039c3233069eea000078750a03755276da..bd412bc6b6b4d824e83a8eff5c694d5692b46f45:/src/propgrid/propgrid.cpp?ds=sidebyside diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index 0df955818d..021f77cd5f 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -4,7 +4,7 @@ // Author: Jaakko Salli // Modified by: // Created: 2004-09-25 -// RCS-ID: $Id: +// RCS-ID: $Id$ // Copyright: (c) Jaakko Salli // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// @@ -16,6 +16,8 @@ #pragma hdrstop #endif +#if wxUSE_PROPGRID + #ifndef WX_PRECOMP #include "wx/defs.h" #include "wx/object.h" @@ -38,7 +40,6 @@ #include "wx/stattext.h" #include "wx/scrolwin.h" #include "wx/dirdlg.h" - #include "wx/layout.h" #include "wx/sizer.h" #include "wx/textdlg.h" #include "wx/filedlg.h" @@ -51,26 +52,24 @@ // This define is necessary to prevent macro clearing #define __wxPG_SOURCE_FILE__ -#include -#include +#include "wx/propgrid/propgrid.h" +#include "wx/propgrid/editors.h" #if wxPG_USE_RENDERER_NATIVE - #include + #include "wx/renderer.h" #endif -#include +#include "wx/odcombo.h" #include "wx/timer.h" #include "wx/dcbuffer.h" -#include -#include +#include "wx/clipbrd.h" +#include "wx/dataobj.h" #ifdef __WXMSW__ - #include + #include "wx/msw/private.h" #endif -#include - // Two pics for the expand / collapse buttons. // Files are not supplied with this project (since it is // recommended to use either custom or native rendering). @@ -139,18 +138,9 @@ const wxChar *wxPropertyGridNameStr = wxT("wxPropertyGrid"); // ----------------------------------------------------------------------- // Statics in one class for easy destruction. -// NB: We prefer to use wxModule, as it offers more consistent behavior -// across platforms. However, for those rare problem situations, we -// also need to offer option to use simpler approach. // ----------------------------------------------------------------------- -#ifndef wxPG_USE_WXMODULE - #define wxPG_USE_WXMODULE 1 -#endif - -#if wxPG_USE_WXMODULE - -#include +#include "wx/module.h" class wxPGGlobalVarsClassManager : public wxModule { @@ -163,19 +153,6 @@ public: IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager, wxModule) -#else // !wxPG_USE_WXMODULE - -class wxPGGlobalVarsClassManager -{ -public: - wxPGGlobalVarsClassManager() {} - ~wxPGGlobalVarsClassManager() { delete wxPGGlobalVars; } -}; - -static wxPGGlobalVarsClassManager gs_pgGlobalVarsClassManager; - -#endif - wxPGGlobalVarsClass* wxPGGlobalVars = (wxPGGlobalVarsClass*) NULL; @@ -199,37 +176,6 @@ wxPGGlobalVarsClass::wxPGGlobalVarsClass() wxVariant v; - v = (long)0; - wxVariantClassInfo_long = wxPGVariantDataGetClassInfo(v.GetData()); - - v = wxString(); - wxVariantClassInfo_string = wxPGVariantDataGetClassInfo(v.GetData()); - - v = (double)0.0; - wxVariantClassInfo_double = wxPGVariantDataGetClassInfo(v.GetData()); - - v = (bool)false; - wxVariantClassInfo_bool = wxPGVariantDataGetClassInfo(v.GetData()); - - v = wxArrayString(); - wxVariantClassInfo_arrstring = wxPGVariantDataGetClassInfo(v.GetData()); - - wxColour col; - wxVariant v2((wxObject*)&col); - wxVariantClassInfo_wxobject = wxPGVariantDataGetClassInfo(v2.GetData()); - - wxVariantList list; - v = wxVariant(list); - wxVariantClassInfo_list = wxPGVariantDataGetClassInfo(v.GetData()); - - v << *wxRED; - wxVariantClassInfo_wxColour = wxPGVariantDataGetClassInfo(v.GetData()); - -#if wxUSE_DATETIME - v = wxVariant(wxDateTime::Now()); - wxVariantClassInfo_datetime = wxPGVariantDataGetClassInfo(v.GetData()); -#endif - // Prepare some shared variants m_vEmptyString = wxString(); m_vZero = (long) 0; @@ -238,6 +184,10 @@ wxPGGlobalVarsClass::wxPGGlobalVarsClass() m_vFalse = false; // Prepare cached string constants + m_strstring = wxS("string"); + m_strlong = wxS("long"); + m_strbool = wxS("bool"); + m_strlist = wxS("list"); m_strMin = wxS("Min"); m_strMax = wxS("Max"); m_strUnits = wxS("Units"); @@ -277,6 +227,10 @@ wxPGGlobalVarsClass::~wxPGGlobalVarsClass() delete wxPGProperty::sm_wxPG_LABEL; } +void wxPropertyGridInitGlobalsIfNeeded() +{ +} + // ----------------------------------------------------------------------- // wxPGBrush // ----------------------------------------------------------------------- @@ -460,19 +414,21 @@ protected: pg->OnKeyUp( event ); } - void OnNavigationKey( wxNavigationKeyEvent& event ) - { - wxPropertyGrid* pg = wxStaticCast(GetParent(), wxPropertyGrid); - pg->OnNavigationKey( event ); - } - void OnPaint( wxPaintEvent& event ); + + // Always be focussable, even with child windows + virtual void SetCanFocus(bool WXUNUSED(canFocus)) + { wxPanel::SetCanFocus(true); } + private: DECLARE_EVENT_TABLE() + DECLARE_ABSTRACT_CLASS(wxPGCanvas) }; +IMPLEMENT_ABSTRACT_CLASS(wxPGCanvas,wxPanel) + BEGIN_EVENT_TABLE(wxPGCanvas, wxPanel) EVT_MOTION(wxPGCanvas::OnMouseMove) EVT_PAINT(wxPGCanvas::OnPaint) @@ -483,7 +439,6 @@ BEGIN_EVENT_TABLE(wxPGCanvas, wxPanel) EVT_KEY_DOWN(wxPGCanvas::OnKey) EVT_KEY_UP(wxPGCanvas::OnKeyUp) EVT_CHAR(wxPGCanvas::OnKey) - EVT_NAVIGATION_KEY(wxPGCanvas::OnNavigationKey) END_EVENT_TABLE() @@ -527,7 +482,6 @@ BEGIN_EVENT_TABLE(wxPropertyGrid, wxScrolledWindow) EVT_CHILD_FOCUS(wxPropertyGrid::OnChildFocusEvent) EVT_SET_FOCUS(wxPropertyGrid::OnFocusEvent) EVT_KILL_FOCUS(wxPropertyGrid::OnFocusEvent) - EVT_TEXT_ENTER(wxPG_SUBID1,wxPropertyGrid::OnCustomEditorEvent) EVT_SYS_COLOUR_CHANGED(wxPropertyGrid::OnSysColourChanged) END_EVENT_TABLE() @@ -596,14 +550,9 @@ bool wxPropertyGrid::Create( wxWindow *parent, // void wxPropertyGrid::Init1() { -#if !wxPG_USE_WXMODULE - if ( !wxPGGlobalVars ) - wxPGGlobalVars = new wxPGGlobalVarsClass(); -#endif - // Register editor classes, if necessary. if ( wxPGGlobalVars->m_mapEditorClasses.empty() ) - RegisterDefaultEditors(); + wxPropertyGrid::RegisterDefaultEditors(); m_iFlags = 0; m_pState = (wxPropertyGridPageState*) NULL; @@ -636,6 +585,8 @@ void wxPropertyGrid::Init1() AddActionTrigger( wxPG_ACTION_COPY, WXK_INSERT, wxMOD_CONTROL ); AddActionTrigger( wxPG_ACTION_PASTE, 'V', wxMOD_CONTROL ); AddActionTrigger( wxPG_ACTION_PASTE, WXK_INSERT, wxMOD_SHIFT ); + AddActionTrigger( wxPG_ACTION_PRESS_BUTTON, WXK_DOWN, wxMOD_ALT ); + AddActionTrigger( wxPG_ACTION_PRESS_BUTTON, WXK_F4 ); m_coloursCustomized = 0; m_frozen = 0; @@ -646,8 +597,6 @@ void wxPropertyGrid::Init1() m_doubleBuffer = (wxBitmap*) NULL; #endif - m_windowsToDelete = NULL; - #ifndef wxPG_ICON_WIDTH m_expandbmp = NULL; m_collbmp = NULL; @@ -666,10 +615,6 @@ void wxPropertyGrid::Init1() m_width = m_height = 0; - SetButtonShortcut(0); - - m_keyComboConsumed = 0; - m_commonValues.push_back(new wxPGCommonValue(_("Unspecified"), wxPGGlobalVars->m_defaultRenderer) ); m_cvUnspecified = 0; @@ -805,8 +750,6 @@ wxPropertyGrid::~wxPropertyGrid() delete m_doubleBuffer; #endif - delete m_windowsToDelete; - //m_selected = (wxPGProperty*) NULL; if ( m_iFlags & wxPG_FL_CREATEDSTATE ) @@ -1060,7 +1003,6 @@ void wxPropertyGrid::CalculateFontAndBitmapStuff( int vspacing ) GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont); m_lineHeight = m_fontHeight+(2*m_spacingy)+1; - m_visPropArray.SetCount((m_height/m_lineHeight)+10); // button spacing m_buttonSpacingY = (m_lineHeight - m_iconHeight) / 2; @@ -1232,7 +1174,8 @@ bool wxPropertyGrid::SetFont( const wxFont& font ) // TODO: Following code is disabled with wxMac because // it is reported to fail. I (JMS) cannot debug it // personally right now. -#if !defined(__WXMAC__) + // CS: should be fixed now, leaving old code in just in case, TODO: REMOVE +#if 1 // !defined(__WXMAC__) bool res = wxScrolledWindow::SetFont( font ); if ( res ) { @@ -1544,18 +1487,6 @@ void wxPropertyGrid::DoSetPropertyValueUnspecified( wxPGProperty* p ) // wxPropertyGrid property operations // ----------------------------------------------------------------------- -void wxPropertyGrid::DoSetPropertyName( wxPGProperty* p, const wxString& newname ) -{ - wxCHECK_RET( p, wxT("invalid property id") ); - - if ( p->GetBaseName().Len() ) m_pState->m_dictName.erase( p->GetBaseName() ); - if ( newname.Len() ) m_pState->m_dictName[newname] = (void*) p; - - p->DoSetName(newname); -} - -// ----------------------------------------------------------------------- - bool wxPropertyGrid::EnsureVisible( wxPGPropArg id ) { wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) @@ -2089,7 +2020,11 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, wxPropertyGridConstIterator it( state, wxPG_ITERATE_VISIBLE, firstItem ); int endScanBottomY = lastItemBottomY + lh; int y = firstItemTopY; - unsigned int arrInd = 0; + + // + // Pregenerate list of visible properties. + wxArrayPGProperty visPropArray; + visPropArray.reserve((m_height/m_lineHeight)+6); for ( ; !it.AtEnd(); it.Next() ) { @@ -2097,8 +2032,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, if ( !p->HasFlag(wxPG_PROP_HIDDEN) ) { - m_visPropArray[arrInd] = (wxPGProperty*)p; - arrInd++; + visPropArray.push_back((wxPGProperty*)p); if ( y > endScanBottomY ) break; @@ -2107,17 +2041,19 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, } } - m_visPropArray[arrInd] = NULL; + visPropArray.push_back(NULL); + + wxPGProperty* nextP = visPropArray[0]; int gridWidth = state->m_width; y = firstItemTopY; - for ( arrInd=0; - m_visPropArray[arrInd] != NULL && y <= lastItemBottomY; + for ( unsigned int arrInd=1; + nextP && y <= lastItemBottomY; arrInd++ ) { - wxPGProperty* p =(wxPGProperty*) m_visPropArray[arrInd]; - wxPGProperty* nextP = (wxPGProperty*) m_visPropArray[arrInd+1]; + wxPGProperty* p = nextP; + nextP = visPropArray[arrInd]; int rowHeight = m_fontHeight+(m_spacingy*2)+1; int textMarginHere = x; @@ -2700,24 +2636,6 @@ wxPGProperty* wxPropertyGrid::GetNearestPaintVisible( wxPGProperty* p ) const } -// ----------------------------------------------------------------------- - -void wxPropertyGrid::SetButtonShortcut( int keycode, bool ctrlDown, bool altDown ) -{ - if ( keycode ) - { - m_pushButKeyCode = keycode; - m_pushButKeyCodeNeedsCtrl = ctrlDown ? 1 : 0; - m_pushButKeyCodeNeedsAlt = altDown ? 1 : 0; - } - else - { - m_pushButKeyCode = WXK_DOWN; - m_pushButKeyCodeNeedsCtrl = 0; - m_pushButKeyCodeNeedsAlt = 1; - } -} - // ----------------------------------------------------------------------- // Methods related to change in value, value modification and sending events // ----------------------------------------------------------------------- @@ -2813,7 +2731,8 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags ) // ----------------------------------------------------------------------- -bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue ) +bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue, + int flags ) { // // Runs all validation functionality. @@ -2822,7 +2741,7 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue m_validationInfo.m_failureBehavior = m_permanentValidationFailureBehavior; - if ( !wxPGIsVariantType(pendingValue, list) ) + if ( pendingValue.GetType() == wxPG_VARIANT_TYPE_LIST ) { if ( !p->ValidateValue(pendingValue, m_validationInfo) ) return false; @@ -2845,13 +2764,13 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue wxVariant bcpPendingList; listValue = pendingValue; - listValue.SetName(p->GetLabel()); + listValue.SetName(p->GetBaseName()); while ( pwc && (pwc->HasFlag(wxPG_PROP_AGGREGATE) || pwc->HasFlag(wxPG_PROP_COMPOSED_VALUE)) ) { wxVariantList tempList; - wxVariant lv(tempList, pwc->GetLabel()); + wxVariant lv(tempList, pwc->GetBaseName()); lv.Append(listValue); listValue = lv; pPendingValue = &listValue; @@ -2869,7 +2788,7 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue wxVariant value; wxPGProperty* evtChangingProperty = changedProperty; - if ( !wxPGIsVariantType(*pPendingValue, list) ) + if ( pPendingValue->GetType() != wxPG_VARIANT_TYPE_LIST ) { value = *pPendingValue; } @@ -2882,33 +2801,37 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue wxVariant evtChangingValue = value; - // FIXME: After proper ValueToString()s added, remove - // this. It is just a temporary fix, as evt_changing - // will simply not work for wxPG_PROP_COMPOSED_VALUE - // (unless it is selected, and textctrl editor is open). - if ( changedProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) ) + if ( flags & SendEvtChanging ) { - evtChangingProperty = baseChangedProperty; - if ( evtChangingProperty != p ) - { - evtChangingProperty->AdaptListToValue( bcpPendingList, &evtChangingValue ); - } - else + // FIXME: After proper ValueToString()s added, remove + // this. It is just a temporary fix, as evt_changing + // will simply not work for wxPG_PROP_COMPOSED_VALUE + // (unless it is selected, and textctrl editor is open). + if ( changedProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) ) { - evtChangingValue = pendingValue; + evtChangingProperty = baseChangedProperty; + if ( evtChangingProperty != p ) + { + evtChangingProperty->AdaptListToValue( bcpPendingList, &evtChangingValue ); + } + else + { + evtChangingValue = pendingValue; + } } - } - if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) ) - { - if ( changedProperty == m_selected ) + if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) ) { - wxASSERT( m_wndEditor->IsKindOf(CLASSINFO(wxTextCtrl)) ); - evtChangingValue = ((wxTextCtrl*)m_wndEditor)->GetValue(); - } - else - { - wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value.")); + if ( changedProperty == m_selected ) + { + wxWindow* editor = GetEditorControl(); + wxASSERT( editor->IsKindOf(CLASSINFO(wxTextCtrl)) ); + evtChangingValue = wxStaticCast(editor, wxTextCtrl)->GetValue(); + } + else + { + wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value.")); + } } } @@ -2924,15 +2847,26 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue // If changedProperty is not property which value was edited, // then call wxPGProperty::ValidateValue() for that as well. - if ( p != changedProperty && !wxPGIsVariantType(value, list) ) + if ( p != changedProperty && value.GetType() != wxPG_VARIANT_TYPE_LIST ) { if ( !changedProperty->ValidateValue(value, m_validationInfo) ) return false; } - // SendEvent returns true if event was vetoed - if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty, &evtChangingValue, 0 ) ) - return false; + if ( flags & SendEvtChanging ) + { + // SendEvent returns true if event was vetoed + if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty, &evtChangingValue, 0 ) ) + return false; + } + + if ( flags & IsStandaloneValidation ) + { + // If called in 'generic' context, we need to reset + // m_chgInfo_changedProperty and write back translated value. + m_chgInfo_changedProperty = NULL; + pendingValue = value; + } return true; } @@ -3051,6 +2985,8 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags ) if ( m_inDoPropertyChanged ) return true; + wxWindow* editor = GetEditorControl(); + m_pState->m_anyModified = 1; m_inDoPropertyChanged = 1; @@ -3070,7 +3006,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags ) topPaintedProperty = topPaintedProperty->GetParent(); } - changedProperty->SetValue(value, &m_chgInfo_valueList); + changedProperty->SetValue(value, &m_chgInfo_valueList, wxPG_SETVAL_BY_USER); // Set as Modified (not if dragging just began) if ( !(p->m_flags & wxPG_PROP_MODIFIED) ) @@ -3078,7 +3014,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags ) p->m_flags |= wxPG_PROP_MODIFIED; if ( p == m_selected && (m_windowStyle & wxPG_BOLD_MODIFIED) ) { - if ( m_wndEditor ) + if ( editor ) SetCurControlBoldFont(); } } @@ -3095,7 +3031,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags ) if ( pwc == m_selected && (m_windowStyle & wxPG_BOLD_MODIFIED) ) { - if ( m_wndEditor ) + if ( editor ) SetCurControlBoldFont(); } @@ -3111,8 +3047,8 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags ) // control. if ( selFlags & wxPG_SEL_DIALOGVAL ) { - if ( m_wndEditor ) - p->GetEditorClass()->UpdateControl(p, m_wndEditor); + if ( editor ) + p->GetEditorClass()->UpdateControl(p, editor); } else { @@ -3168,50 +3104,33 @@ bool wxPropertyGrid::ChangePropertyValue( wxPGPropArg id, wxVariant newValue ) // ----------------------------------------------------------------------- -// Runs wxValidator for the selected property -bool wxPropertyGrid::DoEditorValidate() +wxVariant wxPropertyGrid::GetUncommittedPropertyValue() { -#if wxUSE_VALIDATORS - // With traditional validator style, we dont need to more - if ( !(GetExtraStyle() & wxPG_EX_LEGACY_VALIDATORS) ) - return true; + wxPGProperty* prop = GetSelectedProperty(); - if ( m_iFlags & wxPG_FL_VALIDATION_FAILED ) - { - return false; - } + if ( !prop ) + return wxNullVariant; - wxWindow* wnd = GetEditorControl(); + wxTextCtrl* tc = GetEditorTextCtrl(); + wxVariant value = prop->GetValue(); - wxValidator* validator = m_selected->GetValidator(); - if ( validator && wnd ) - { - // Use TextCtrl of ODComboBox instead - if ( wnd->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) - { - wnd = ((wxOwnerDrawnComboBox*)wnd)->GetTextCtrl(); + if ( !tc || !IsEditorsValueModified() ) + return value; - if ( !wnd ) - return true; - } + if ( !prop->StringToValue(value, tc->GetValue()) ) + return value; - validator->SetWindow(wnd); + if ( !PerformValidation(prop, value, IsStandaloneValidation) ) + return prop->GetValue(); - // Instead setting the flag after the failure, we set - // it before checking and then clear afterwards if things - // went fine. This trick is necessary since focus events - // may be triggered while in Validate. - m_iFlags |= wxPG_FL_VALIDATION_FAILED; - if ( !validator->Validate(this) ) - { - // If you dpm't want to display message multiple times per change, - // comment the following line. - m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED); - return false; - } - m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED); - } -#endif + return value; +} + +// ----------------------------------------------------------------------- + +// Runs wxValidator for the selected property +bool wxPropertyGrid::DoEditorValidate() +{ return true; } @@ -3243,7 +3162,6 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) { wxPGProperty* selected = m_selected; - // // Somehow, event is handled after property has been deselected. // Possibly, but very rare. if ( !selected ) @@ -3303,20 +3221,23 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) if ( !buttonWasHandled ) { - // First call editor class' event handler. - const wxPGEditor* editor = selected->GetEditorClass(); - - if ( editor->OnEvent( this, selected, wnd, event ) ) + if ( wnd ) { - // If changes, validate them - if ( DoEditorValidate() ) - { - if ( editor->GetValueFromControl( pendingValue, m_selected, wnd ) ) - valueIsPending = true; - } - else + // First call editor class' event handler. + const wxPGEditor* editor = selected->GetEditorClass(); + + if ( editor->OnEvent( this, selected, wnd, event ) ) { - validationFailure = true; + // If changes, validate them + if ( DoEditorValidate() ) + { + if ( editor->GetValueFromControl( pendingValue, m_selected, wnd ) ) + valueIsPending = true; + } + else + { + validationFailure = true; + } } } @@ -3339,7 +3260,7 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) if ( !PerformValidation(m_selected, pendingValue) ) validationFailure = true; - if ( validationFailure ) + if ( validationFailure) { OnValidationFailure(selected, pendingValue); } @@ -3349,10 +3270,24 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) DoPropertyChanged(selected, selFlags); EditorsValueWasNotModified(); + + // Regardless of editor type, unfocus editor on + // text-editing related enter press. + if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER ) + { + SetFocusOnCanvas(); + } } else { // No value after all + + // Regardless of editor type, unfocus editor on + // text-editing related enter press. + if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER ) + { + SetFocusOnCanvas(); + } // Let unhandled button click events go to the parent if ( !buttonWasHandled && event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED ) @@ -3416,7 +3351,7 @@ wxSize wxPropertyGrid::GetImageSize( wxPGProperty* p, int item ) const wxSize cis = p->OnMeasureImage(item); - int choiceCount = p->GetChoiceCount(); + int choiceCount = p->m_choices.GetCount(); int comVals = p->GetDisplayedCommonValueCount(); if ( item >= choiceCount && comVals > 0 ) { @@ -3490,52 +3425,51 @@ void wxPropertyGrid::CustomSetCursor( int type, bool override ) // wxPropertyGrid property selection // ----------------------------------------------------------------------- -#define CONNECT_CHILD(EVT,FUNCTYPE,FUNC) \ - wnd->Connect(id, EVT, \ - (wxObjectEventFunction) (wxEventFunction) \ - FUNCTYPE (&wxPropertyGrid::FUNC), \ - NULL, this ); - // Setups event handling for child control -void wxPropertyGrid::SetupEventHandling( wxWindow* argWnd, int id ) +void wxPropertyGrid::SetupChildEventHandling( wxWindow* argWnd ) { - wxWindow* wnd = argWnd; + wxWindowID id = argWnd->GetId(); if ( argWnd == m_wndEditor ) { - CONNECT_CHILD(wxEVT_MOTION,(wxMouseEventFunction),OnMouseMoveChild) - CONNECT_CHILD(wxEVT_LEFT_UP,(wxMouseEventFunction),OnMouseUpChild) - CONNECT_CHILD(wxEVT_LEFT_DOWN,(wxMouseEventFunction),OnMouseClickChild) - CONNECT_CHILD(wxEVT_RIGHT_UP,(wxMouseEventFunction),OnMouseRightClickChild) - CONNECT_CHILD(wxEVT_ENTER_WINDOW,(wxMouseEventFunction),OnMouseEntry) - CONNECT_CHILD(wxEVT_LEAVE_WINDOW,(wxMouseEventFunction),OnMouseEntry) + argWnd->Connect(id, wxEVT_MOTION, + wxMouseEventHandler(wxPropertyGrid::OnMouseMoveChild), + NULL, this); + argWnd->Connect(id, wxEVT_LEFT_UP, + wxMouseEventHandler(wxPropertyGrid::OnMouseUpChild), + NULL, this); + argWnd->Connect(id, wxEVT_LEFT_DOWN, + wxMouseEventHandler(wxPropertyGrid::OnMouseClickChild), + NULL, this); + argWnd->Connect(id, wxEVT_RIGHT_UP, + wxMouseEventHandler(wxPropertyGrid::OnMouseRightClickChild), + NULL, this); + argWnd->Connect(id, wxEVT_ENTER_WINDOW, + wxMouseEventHandler(wxPropertyGrid::OnMouseEntry), + NULL, this); + argWnd->Connect(id, wxEVT_LEAVE_WINDOW, + wxMouseEventHandler(wxPropertyGrid::OnMouseEntry), + NULL, this); + argWnd->Connect(id, wxEVT_KEY_DOWN, + wxCharEventHandler(wxPropertyGrid::OnChildKeyDown), + NULL, this); } - else - { - CONNECT_CHILD(wxEVT_NAVIGATION_KEY,(wxNavigationKeyEventFunction),OnNavigationKey) - } - CONNECT_CHILD(wxEVT_KEY_DOWN,(wxCharEventFunction),OnChildKeyDown) - CONNECT_CHILD(wxEVT_KEY_UP,(wxCharEventFunction),OnChildKeyUp) - CONNECT_CHILD(wxEVT_KILL_FOCUS,(wxFocusEventFunction),OnFocusEvent) } void wxPropertyGrid::FreeEditors() { // Do not free editors immediately if processing events - if ( !m_windowsToDelete ) - m_windowsToDelete = new wxArrayPtrVoid; - if ( m_wndEditor2 ) { - m_windowsToDelete->push_back(m_wndEditor2); m_wndEditor2->Hide(); + wxPendingDelete.Append( m_wndEditor2 ); m_wndEditor2 = (wxWindow*) NULL; } if ( m_wndEditor ) { - m_windowsToDelete->push_back(m_wndEditor); m_wndEditor->Hide(); + wxPendingDelete.Append( m_wndEditor ); m_wndEditor = (wxWindow*) NULL; } } @@ -3543,6 +3477,8 @@ void wxPropertyGrid::FreeEditors() // Call with NULL to de-select property bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) { + wxPanel* canvas = GetPanel(); + /* if (p) wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(), @@ -3558,25 +3494,24 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) wxPGProperty* prev = m_selected; - // - // Delete windows pending for deletion - if ( m_windowsToDelete && !m_inDoPropertyChanged && m_windowsToDelete->size() ) - { - unsigned int i; - - for ( i=0; isize(); i++ ) - delete ((wxWindow*)((*m_windowsToDelete)[i])); - - m_windowsToDelete->clear(); - } - if ( !m_pState ) { m_inDoSelectProperty = 0; return false; } - // +/* + if (m_selected) + wxPrintf( "Selected %s\n", m_selected->GetClassInfo()->GetClassName() ); + else + wxPrintf( "None selected\n" ); + + if (p) + wxPrintf( "P = %s\n", p->GetClassInfo()->GetClassName() ); + else + wxPrintf( "P = NULL\n" ); +*/ + // If we are frozen, then just set the values. if ( m_frozen ) { @@ -3611,8 +3546,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) } else { - wxScrolledWindow::SetFocus(); - m_editorFocused = 0; + SetFocusOnCanvas(); } } @@ -3709,25 +3643,27 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) m_wndEditor = wndList.m_primary; m_wndEditor2 = wndList.m_secondary; + wxWindow* primaryCtrl = GetEditorControl(); + + // + // Essentially, primaryCtrl == m_wndEditor + // // NOTE: It is allowed for m_wndEditor to be NULL - in this case // value is drawn as normal, and m_wndEditor2 is assumed - // to be a right-aligned button that triggers a separate editor + // to be a right-aligned button that triggers a separate editorCtrl // window. if ( m_wndEditor ) { - wxASSERT_MSG( m_wndEditor->GetParent() == m_canvas, + wxASSERT_MSG( m_wndEditor->GetParent() == canvas, wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); // Set validator, if any #if wxUSE_VALIDATORS - if ( !(GetExtraStyle() & wxPG_EX_LEGACY_VALIDATORS) ) - { - wxValidator* validator = p->GetValidator(); - if ( validator ) - m_wndEditor->SetValidator(*validator); - } + wxValidator* validator = p->GetValidator(); + if ( validator ) + primaryCtrl->SetValidator(*validator); #endif if ( m_wndEditor->GetSize().y > (m_lineHeight+6) ) @@ -3742,10 +3678,10 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) // Fix TextCtrl indentation #if defined(__WXMSW__) && !defined(__WXWINCE__) wxTextCtrl* tc = NULL; - if ( m_wndEditor->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) - tc = ((wxOwnerDrawnComboBox*)m_wndEditor)->GetTextCtrl(); + if ( primaryCtrl->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) + tc = ((wxOwnerDrawnComboBox*)primaryCtrl)->GetTextCtrl(); else - tc = wxDynamicCast(m_wndEditor, wxTextCtrl); + tc = wxDynamicCast(primaryCtrl, wxTextCtrl); if ( tc ) ::SendMessage(GetHwndOf(tc), EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0)); #endif @@ -3771,8 +3707,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) m_wndEditor->Move( goodPos ); #endif - wxWindow* primaryCtrl = GetEditorControl(); - SetupEventHandling(primaryCtrl, wxPG_SUBID1); + SetupChildEventHandling(primaryCtrl); // Focus and select all (wxTextCtrl, wxComboBox etc) if ( flags & wxPG_SEL_FOCUS ) @@ -3785,7 +3720,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) if ( m_wndEditor2 ) { - wxASSERT_MSG( m_wndEditor2->GetParent() == m_canvas, + wxASSERT_MSG( m_wndEditor2->GetParent() == canvas, wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); // Get proper id for wndSecondary @@ -3812,7 +3747,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) #endif m_wndEditor2->Show(); - SetupEventHandling(m_wndEditor2,wxPG_SUBID2); + SetupChildEventHandling(m_wndEditor2); // If no primary editor, focus to button to allow // it to interprete ENTER etc. @@ -3830,8 +3765,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) } else { - // wxGTK atleast seems to need this (wxMSW not) - SetFocus(); + // Make sure focus is in grid canvas (important for wxGTK, at least) + SetFocusOnCanvas(); } EditorsValueWasNotModified(); @@ -3851,6 +3786,11 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) DrawItems(p, p); } + else + { + // Make sure focus is in grid canvas + SetFocusOnCanvas(); + } ClearInternalFlag(wxPG_FL_IN_SELECT_PROPERTY); } @@ -3918,7 +3858,7 @@ bool wxPropertyGrid::UnfocusEditor() if ( !CommitChangesFromEditor(0) ) return false; - m_canvas->SetFocusIgnoringChildren(); + SetFocusOnCanvas(); DrawItem(m_selected); return true; @@ -3973,7 +3913,7 @@ bool wxPropertyGrid::DoCollapse( wxPGProperty* p, bool sendEvents ) } // Clear dont-center-splitter flag if it wasn't set - m_iFlags = m_iFlags & ~(wxPG_FL_DONT_CENTER_SPLITTER) | old_flag; + m_iFlags = (m_iFlags & ~wxPG_FL_DONT_CENTER_SPLITTER) | old_flag; return res; } @@ -4140,8 +4080,6 @@ void wxPropertyGrid::OnResize( wxSizeEvent& event ) m_width = width; m_height = height; - m_visPropArray.SetCount((height/m_lineHeight)+10); - #if wxPG_DOUBLE_BUFFER if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING) ) { @@ -4205,6 +4143,12 @@ void wxPropertyGrid::SetVirtualWidth( int width ) m_pState->SetVirtualWidth( width ); } +void wxPropertyGrid::SetFocusOnCanvas() +{ + m_canvas->SetFocusIgnoringChildren(); + m_editorFocused = 0; +} + // ----------------------------------------------------------------------- // wxPropertyGrid mouse event handling // ----------------------------------------------------------------------- @@ -4241,7 +4185,7 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even // Need to set focus? if ( !(m_iFlags & wxPG_FL_FOCUSED) ) { - m_canvas->SetFocus(); + SetFocusOnCanvas(); } wxPropertyGridPageState* state = m_pState; @@ -4724,13 +4668,13 @@ bool wxPropertyGrid::OnMouseCommon( wxMouseEvent& event, int* px, int* py ) int ux = event.m_x; int uy = event.m_y; - wxWindow* wnd = m_wndEditor; + wxWindow* wnd = GetEditorControl(); // Hide popup on clicks if ( event.GetEventType() != wxEVT_MOTION ) if ( wnd && wnd->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) { - ((wxOwnerDrawnComboBox*)m_wndEditor)->HidePopup(); + ((wxOwnerDrawnComboBox*)wnd)->HidePopup(); } wxRect r; @@ -4879,8 +4823,6 @@ bool wxPropertyGrid::OnMouseChildCommon( wxMouseEvent &event, int* px, int *py ) int x, y; event.GetPosition(&x,&y); - AdjustPosForClipperWindow( topCtrlWnd, &x, &y ); - int splitterX = GetSplitterPosition(); wxRect r = topCtrlWnd->GetRect(); @@ -4949,17 +4891,6 @@ void wxPropertyGrid::OnMouseUpChild( wxMouseEvent &event ) // wxPropertyGrid keyboard event handling // ----------------------------------------------------------------------- -void wxPropertyGrid::SendNavigationKeyEvent( int dir ) -{ - wxNavigationKeyEvent evt; - evt.SetFlags(wxNavigationKeyEvent::FromTab| - (dir?wxNavigationKeyEvent::IsForward: - wxNavigationKeyEvent::IsBackward)); - evt.SetEventObject(this); - m_canvas->GetEventHandler()->AddPendingEvent(evt); -} - - int wxPropertyGrid::KeyEventToActions(wxKeyEvent &event, int* pSecond) const { // Translates wxKeyEvent to wxPG_ACTION_XXX @@ -5046,7 +4977,8 @@ void wxPropertyGrid::HandleKeyEvent(wxKeyEvent &event) if ( keycode == WXK_TAB ) { - SendNavigationKeyEvent( event.ShiftDown()?0:1 ); + if (m_selected) + DoSelectProperty( m_selected, wxPG_SEL_FOCUS ); return; } @@ -5065,7 +4997,7 @@ void wxPropertyGrid::HandleKeyEvent(wxKeyEvent &event) { // Show dialog? - if ( ButtonTriggerKeyTest(event) ) + if ( ButtonTriggerKeyTest(action, event) ) return; wxPGProperty* p = m_selected; @@ -5161,14 +5093,13 @@ bool wxPropertyGrid::HandleChildKey( wxKeyEvent& event ) // Update the control as well m_selected->GetEditorClass()->SetControlStringValue( m_selected, - m_wndEditor, + GetEditorControl(), m_selected->GetDisplayedString() ); } OnValidationFailureReset(m_selected); res = false; - UnfocusEditor(); } else if ( action == wxPG_ACTION_COPY ) @@ -5237,133 +5168,31 @@ bool wxPropertyGrid::HandleChildKey( wxKeyEvent& event ) void wxPropertyGrid::OnKey( wxKeyEvent &event ) { - - // - // Events to editor controls should get relayed here. - // - wxWindow* focused = wxWindow::FindFocus(); - - wxWindow* primaryCtrl = GetEditorControl(); - - if ( primaryCtrl && - (focused==primaryCtrl - || m_editorFocused) ) - { - // Child key must be processed here, since it can - // destroy the control which is referred by its own - // event handling. - HandleChildKey( event ); - } - else - HandleKeyEvent( event ); + HandleKeyEvent( event ); } // ----------------------------------------------------------------------- void wxPropertyGrid::OnKeyUp(wxKeyEvent &event) { - m_keyComboConsumed = 0; - event.Skip(); } // ----------------------------------------------------------------------- -void wxPropertyGrid::OnNavigationKey( wxNavigationKeyEvent& event ) +bool wxPropertyGrid::ButtonTriggerKeyTest( int action, wxKeyEvent& event ) { - // Ignore events that occur very close to focus set - if ( m_iFlags & wxPG_FL_IGNORE_NEXT_NAVKEY ) + if ( action == -1 ) { - m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY); - event.Skip(); - return; + int secondAction; + action = KeyEventToActions(event, &secondAction); } - wxPGProperty* next = (wxPGProperty*) NULL; - - int dir = event.GetDirection()?1:-1; - - if ( m_selected ) - { - if ( dir == 1 && (m_wndEditor || m_wndEditor2) ) - { - wxWindow* focused = wxWindow::FindFocus(); - - wxWindow* wndToCheck = GetEditorControl(); - - // ODComboBox focus goes to its text ctrl, so we need to use it instead - if ( wndToCheck && wndToCheck->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) - { - wxTextCtrl* comboTextCtrl = ((wxOwnerDrawnComboBox*)wndToCheck)->GetTextCtrl(); - if ( comboTextCtrl ) - wndToCheck = comboTextCtrl; - } - - /* - // Because of problems navigating from wxButton, do not go to it. - if ( !wndToCheck ) - { - // No primary, use secondary - wndToCheck = m_wndEditor2; - } - // If it has editor button, focus to it after the primary editor. - // NB: Doesn't work since wxButton on wxMSW doesn't seem to propagate - // key events (yes, I'm using wxWANTS_CHARS with it, and yes I - // have somewhat debugged in window.cpp itself). - else if ( focused == wndToCheck && - m_wndEditor2 && - !(GetExtraStyle() & wxPG_EX_NO_TAB_TO_BUTTON) ) - { - wndToCheck = m_wndEditor2; - wxLogDebug(wxT("Exp1")); - } - */ - - if ( focused != wndToCheck && - wndToCheck ) - { - wndToCheck->SetFocus(); - - // Select all text in wxTextCtrl etc. - if ( m_wndEditor && wndToCheck == m_wndEditor ) - m_selected->GetEditorClass()->OnFocus(m_selected,wndToCheck); - - m_editorFocused = 1; - next = m_selected; - } - } - - if ( !next ) - { - next = wxPropertyGridIterator::OneStep(m_pState, wxPG_ITERATE_VISIBLE, m_selected, dir); - - if ( next ) - { - // This allows preventing NavigateOut to occur - DoSelectProperty( next, wxPG_SEL_FOCUS ); - } - } - } - - if ( !next ) - event.Skip(); -} - -// ----------------------------------------------------------------------- - -bool wxPropertyGrid::ButtonTriggerKeyTest( wxKeyEvent &event ) -{ - int keycode = event.GetKeyCode(); - // Does the keycode trigger button? - if ( keycode == m_pushButKeyCode && - m_wndEditor2 && - (!m_pushButKeyCodeNeedsAlt || event.AltDown()) && - (!m_pushButKeyCodeNeedsCtrl || event.ControlDown()) ) + if ( action == wxPG_ACTION_PRESS_BUTTON && + m_wndEditor2 ) { - m_keyComboConsumed = 1; - - wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED,m_wndEditor2->GetId()); + wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, m_wndEditor2->GetId()); GetEventHandler()->AddPendingEvent(evt); return true; } @@ -5385,7 +5214,7 @@ void wxPropertyGrid::OnChildKeyDown( wxKeyEvent &event ) return; } - if ( ButtonTriggerKeyTest(event) ) + if ( ButtonTriggerKeyTest(-1, event) ) return; if ( HandleChildKey(event) == true ) @@ -5396,8 +5225,6 @@ void wxPropertyGrid::OnChildKeyDown( wxKeyEvent &event ) void wxPropertyGrid::OnChildKeyUp( wxKeyEvent &event ) { - m_keyComboConsumed = 0; - GetEventHandler()->AddPendingEvent(event); event.Skip(); @@ -5444,13 +5271,8 @@ void wxPropertyGrid::HandleFocusChange( wxWindow* newFocused ) if ( (m_iFlags & wxPG_FL_FOCUSED) != (oldFlags & wxPG_FL_FOCUSED) ) { - // On each focus kill, mark the next nav key event - // to be ignored (can't do on set focus since the - // event would occur before it). if ( !(m_iFlags & wxPG_FL_FOCUSED) ) { - m_iFlags |= wxPG_FL_IGNORE_NEXT_NAVKEY; - // Need to store changed value CommitChangesFromEditor(); } @@ -5483,8 +5305,6 @@ void wxPropertyGrid::HandleFocusChange( wxWindow* newFocused ) } */ - - m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY); } // Redraw selected @@ -5541,20 +5361,43 @@ void wxPropertyGrid::OnCaptureChange( wxMouseCaptureChangedEvent& WXUNUSED(event // ----------------------------------------------------------------------- // noDefCheck = true prevents infinite recursion. -wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorclass, - const wxString& name, +wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorClass, bool noDefCheck ) { - wxASSERT( editorclass ); + wxASSERT( editorClass ); if ( !noDefCheck && wxPGGlobalVars->m_mapEditorClasses.empty() ) RegisterDefaultEditors(); - wxPGGlobalVars->m_mapEditorClasses[name] = (void*)editorclass; + wxString name = editorClass->GetName(); - return editorclass; + // Existing editor under this name? + wxPGHashMapS2P::iterator vt_it = wxPGGlobalVars->m_mapEditorClasses.find(name); + + if ( vt_it != wxPGGlobalVars->m_mapEditorClasses.end() ) + { + // If this name was already used, try class name. + name = editorClass->GetClassInfo()->GetClassName(); + vt_it = wxPGGlobalVars->m_mapEditorClasses.find(name); + } + + wxCHECK_MSG( vt_it == wxPGGlobalVars->m_mapEditorClasses.end(), + (wxPGEditor*) vt_it->second, + "Editor with given name was already registered" ); + + wxPGGlobalVars->m_mapEditorClasses[name] = (void*)editorClass; + + return editorClass; } +// Use this in RegisterDefaultEditors. +#define wxPGRegisterDefaultEditorClass(EDITOR) \ + if ( wxPGEditor_##EDITOR == (wxPGEditor*) NULL ) \ + { \ + wxPGEditor_##EDITOR = wxPropertyGrid::RegisterEditorClass( \ + new wxPG##EDITOR##Editor, true ); \ + } + // Registers all default editor classes void wxPropertyGrid::RegisterDefaultEditors() { @@ -5686,11 +5529,7 @@ void wxPGChoicesData::Clear() delete Item(i); } -#if wxUSE_STL - m_items.resize(0); -#else - m_items.Empty(); -#endif + m_items.clear(); } void wxPGChoicesData::CopyDataFrom( wxPGChoicesData* data ) @@ -5835,7 +5674,8 @@ void wxPGChoices::RemoveAt(size_t nIndex, size_t count) unsigned int i; for ( i=nIndex; i<(nIndex+count); i++) delete m_data->Item(i); - m_data->m_items.RemoveAt(nIndex, count); + m_data->m_items.erase(m_data->m_items.begin()+nIndex, + m_data->m_items.begin()+nIndex+count); } // ----------------------------------------------------------------------- @@ -6031,11 +5871,6 @@ wxEvent* wxPropertyGridEvent::Clone() const return new wxPropertyGridEvent( *this ); } -void wxPropertyGrid::SetPropertyAttributeAll( const wxString& attrName, wxVariant value ) -{ - DoSetPropertyAttribute(GetRoot(), attrName, value, wxPG_RECURSE); -} - // ----------------------------------------------------------------------- // wxPropertyGridPopulator // ----------------------------------------------------------------------- @@ -6323,3 +6158,5 @@ void wxPropertyGridPopulator::ProcessError( const wxString& msg ) } // ----------------------------------------------------------------------- + +#endif // wxUSE_PROPGRID