X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1766bf34538723bc34e5e963b6bacc5722b398ef..8ba80c6f8325e61de2e3fc4bbd7cf3d750f432cd:/src/propgrid/propgrid.cpp diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index 80d323e5e5..2fbaf76534 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 ///////////////////////////////////////////////////////////////////////////// @@ -52,22 +52,22 @@ // 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 // Two pics for the expand / collapse buttons. @@ -140,7 +140,7 @@ const wxChar *wxPropertyGridNameStr = wxT("wxPropertyGrid"); // Statics in one class for easy destruction. // ----------------------------------------------------------------------- -#include +#include "wx/module.h" class wxPGGlobalVarsClassManager : public wxModule { @@ -414,12 +414,6 @@ 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 @@ -445,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() @@ -593,6 +586,7 @@ void wxPropertyGrid::Init1() 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; @@ -1180,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 ) { @@ -2736,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. @@ -2805,34 +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 ) + // 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) ) { - evtChangingProperty->AdaptListToValue( bcpPendingList, &evtChangingValue ); - } - else - { - 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) ) { - 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.")); + 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.")); + } } } @@ -2854,9 +2853,20 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue 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; } @@ -3094,6 +3104,30 @@ bool wxPropertyGrid::ChangePropertyValue( wxPGPropArg id, wxVariant newValue ) // ----------------------------------------------------------------------- +wxVariant wxPropertyGrid::GetUncommittedPropertyValue() +{ + wxPGProperty* prop = GetSelectedProperty(); + + if ( !prop ) + return wxNullVariant; + + wxTextCtrl* tc = GetEditorTextCtrl(); + wxVariant value = prop->GetValue(); + + if ( !tc || !IsEditorsValueModified() ) + return value; + + if ( !prop->StringToValue(value, tc->GetValue()) ) + return value; + + if ( !PerformValidation(prop, value, IsStandaloneValidation) ) + return prop->GetValue(); + + return value; +} + +// ----------------------------------------------------------------------- + // Runs wxValidator for the selected property bool wxPropertyGrid::DoEditorValidate() { @@ -3128,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 ) @@ -3227,7 +3260,7 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) if ( !PerformValidation(m_selected, pendingValue) ) validationFailure = true; - if ( validationFailure ) + if ( validationFailure) { OnValidationFailure(selected, pendingValue); } @@ -3238,7 +3271,6 @@ 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 ) @@ -3249,6 +3281,13 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) 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 ) @@ -3411,26 +3450,33 @@ void wxPropertyGrid::SetupChildEventHandling( wxWindow* argWnd ) argWnd->Connect(id, wxEVT_LEAVE_WINDOW, wxMouseEventHandler(wxPropertyGrid::OnMouseEntry), NULL, this); + argWnd->Connect(id, wxEVT_KEY_DOWN, + wxCharEventHandler(wxPropertyGrid::OnChildKeyDown), + NULL, this); } - else - { - argWnd->Connect(id, wxEVT_NAVIGATION_KEY, - wxNavigationKeyEventHandler(wxPropertyGrid::OnNavigationKey)); - } - - argWnd->Connect(id, wxEVT_KEY_DOWN, - wxKeyEventHandler(wxPropertyGrid::OnChildKeyDown), - NULL, this); - argWnd->Connect(id, wxEVT_KEY_UP, - wxKeyEventHandler(wxPropertyGrid::OnChildKeyUp), - NULL, this); - argWnd->Connect(id, wxEVT_KILL_FOCUS, - wxFocusEventHandler(wxPropertyGrid::OnFocusEvent), - NULL, this); } void wxPropertyGrid::FreeEditors() { + // + // Return focus back to canvas from children (this is required at least for + // GTK+, which, unlike Windows, clears focus when control is destroyed + // instead of moving it to closest parent). + wxWindow* focus = wxWindow::FindFocus(); + if ( focus ) + { + wxWindow* parent = focus->GetParent(); + while ( parent ) + { + if ( parent == m_canvas ) + { + SetFocusOnCanvas(); + break; + } + parent = parent->GetParent(); + } + } + // Do not free editors immediately if processing events if ( m_wndEditor2 ) { @@ -3473,7 +3519,18 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) 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 ) { @@ -3603,16 +3660,14 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) goodPos, grect.GetSize()); - // - // Below, bear in mind the difference between primaryCtrl and m_wndEditor: - // m_wndEditor is the actual wxWindow on canvas, and primaryCtrl is - // the actual editor control. They may different if wxPGClipperWindow is - // used for this editor. - // 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 editorCtrl @@ -3661,8 +3716,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) } m_wndEditor->SetSizeHints(3, 3); - if ( m_wndEditor != primaryCtrl ) - primaryCtrl->SetSizeHints(3, 3); #if wxPG_CREATE_CONTROLS_HIDDEN m_wndEditor->Show(false); @@ -4789,8 +4842,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(); @@ -4859,17 +4910,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 @@ -4956,10 +4996,8 @@ void wxPropertyGrid::HandleKeyEvent(wxKeyEvent &event) if ( keycode == WXK_TAB ) { - if ( HasFlag(wxTAB_TRAVERSAL) ) - SendNavigationKeyEvent( event.ShiftDown()?0:1 ); - else - event.Skip(); + if (m_selected) + DoSelectProperty( m_selected, wxPG_SEL_FOCUS ); return; } @@ -5081,7 +5119,6 @@ bool wxPropertyGrid::HandleChildKey( wxKeyEvent& event ) OnValidationFailureReset(m_selected); res = false; - UnfocusEditor(); } else if ( action == wxPG_ACTION_COPY ) @@ -5150,25 +5187,7 @@ 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 ); } // ----------------------------------------------------------------------- @@ -5180,88 +5199,6 @@ void wxPropertyGrid::OnKeyUp(wxKeyEvent &event) // ----------------------------------------------------------------------- -void wxPropertyGrid::OnNavigationKey( wxNavigationKeyEvent& event ) -{ - // Ignore events that occur very close to focus set - if ( m_iFlags & wxPG_FL_IGNORE_NEXT_NAVKEY ) - { - m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY); - event.Skip(); - return; - } - - 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( int action, wxKeyEvent& event ) { if ( action == -1 ) @@ -5353,13 +5290,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(); } @@ -5392,8 +5324,6 @@ void wxPropertyGrid::HandleFocusChange( wxWindow* newFocused ) } */ - - m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY); } // Redraw selected @@ -5463,6 +5393,13 @@ wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* 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" ); @@ -5472,6 +5409,14 @@ wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* 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() { @@ -5749,7 +5694,7 @@ void wxPGChoices::RemoveAt(size_t nIndex, size_t count) for ( i=nIndex; i<(nIndex+count); i++) delete m_data->Item(i); m_data->m_items.erase(m_data->m_items.begin()+nIndex, - m_data->m_items.begin()+nIndex+count-1); + m_data->m_items.begin()+nIndex+count); } // -----------------------------------------------------------------------