+ // NB: We must copy the selection.
+ wxArrayPGProperty selection = m_pState->m_selection;
+ DoSetSelection(selection, wxPG_SEL_FORCE | wxPG_SEL_NONVISIBLE);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::DoAddToSelection( wxPGProperty* prop, int selFlags )
+{
+ wxCHECK( prop, false );
+
+ if ( !(GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION) )
+ return DoSelectProperty(prop, selFlags);
+
+ wxArrayPGProperty& selection = m_pState->m_selection;
+
+ if ( !selection.size() )
+ {
+ return DoSelectProperty(prop, selFlags);
+ }
+ else
+ {
+ // For categories, only one can be selected at a time
+ if ( prop->IsCategory() || selection[0]->IsCategory() )
+ return true;
+
+ selection.push_back(prop);
+
+ if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+ {
+ SendEvent( wxEVT_PG_SELECTED, prop, NULL );
+ }
+
+ DrawItem(prop);
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::DoRemoveFromSelection( wxPGProperty* prop, int selFlags )
+{
+ wxCHECK( prop, false );
+ bool res;
+
+ wxArrayPGProperty& selection = m_pState->m_selection;
+ if ( selection.size() <= 1 )
+ {
+ res = DoSelectProperty(NULL, selFlags);
+ }
+ else
+ {
+ m_pState->DoRemoveFromSelection(prop);
+ DrawItem(prop);
+ res = true;
+ }
+
+ return res;
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::DoSelectAndEdit( wxPGProperty* prop,
+ unsigned int colIndex,
+ unsigned int selFlags )
+{
+ //
+ // NB: Enable following if label editor background colour is
+ // ever changed to any other than m_colSelBack.
+ //
+ // We use this workaround to prevent visible flicker when editing
+ // a cell. Atleast on wxMSW, there is a difficult to find
+ // (and perhaps prevent) redraw somewhere between making property
+ // selected and enabling label editing.
+ //
+ //wxColour prevColSelBack = m_colSelBack;
+ //m_colSelBack = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
+
+ bool res;
+
+ if ( colIndex == 1 )
+ {
+ res = DoSelectProperty(prop, selFlags);
+ }
+ else
+ {
+ // send event
+ DoClearSelection(false, wxPG_SEL_NO_REFRESH);
+
+ if ( m_pState->m_editableColumns.Index(colIndex) == wxNOT_FOUND )
+ {
+ res = DoAddToSelection(prop, selFlags);
+ }
+ else
+ {
+ res = DoAddToSelection(prop, selFlags|wxPG_SEL_NO_REFRESH);
+
+ DoBeginLabelEdit(colIndex, selFlags);
+ }
+ }
+
+ //m_colSelBack = prevColSelBack;
+ return res;
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::AddToSelectionFromInputEvent( wxPGProperty* prop,
+ unsigned int colIndex,
+ wxMouseEvent* mouseEvent,
+ int selFlags )
+{
+ const wxArrayPGProperty& selection = GetSelectedProperties();
+ bool alreadySelected = m_pState->DoIsPropertySelected(prop);
+ bool res = true;
+
+ // Set to 2 if also add all items in between
+ int addToExistingSelection = 0;
+
+ if ( GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION )
+ {
+ if ( mouseEvent )
+ {
+ if ( mouseEvent->GetEventType() == wxEVT_RIGHT_DOWN ||
+ mouseEvent->GetEventType() == wxEVT_RIGHT_UP )
+ {
+ // Allow right-click for context menu without
+ // disturbing the selection.
+ if ( GetSelectedProperties().size() <= 1 ||
+ !alreadySelected )
+ return DoSelectAndEdit(prop, colIndex, selFlags);
+ return true;
+ }
+ else
+ {
+ if ( mouseEvent->ControlDown() )
+ {
+ addToExistingSelection = 1;
+ }
+ else if ( mouseEvent->ShiftDown() )
+ {
+ if ( selection.size() > 0 && !prop->IsCategory() )
+ addToExistingSelection = 2;
+ else
+ addToExistingSelection = 1;
+ }
+ }
+ }
+ }
+
+ if ( addToExistingSelection == 1 )
+ {
+ // Add/remove one
+ if ( !alreadySelected )
+ {
+ res = DoAddToSelection(prop, selFlags);
+ }
+ else if ( GetSelectedProperties().size() > 1 )
+ {
+ res = DoRemoveFromSelection(prop, selFlags);
+ }
+ }
+ else if ( addToExistingSelection == 2 )
+ {
+ // Add this, and all in between
+
+ // Find top selected property
+ wxPGProperty* topSelProp = selection[0];
+ int topSelPropY = topSelProp->GetY();
+ for ( unsigned int i=1; i<selection.size(); i++ )
+ {
+ wxPGProperty* p = selection[i];
+ int y = p->GetY();
+ if ( y < topSelPropY )
+ {
+ topSelProp = p;
+ topSelPropY = y;
+ }
+ }
+
+ wxPGProperty* startFrom;
+ wxPGProperty* stopAt;
+
+ if ( prop->GetY() <= topSelPropY )
+ {
+ // Property is above selection (or same)
+ startFrom = prop;
+ stopAt = topSelProp;
+ }
+ else
+ {
+ // Property is below selection
+ startFrom = topSelProp;
+ stopAt = prop;
+ }
+
+ // Iterate through properties in-between, and select them
+ wxPropertyGridIterator it;
+
+ for ( it = GetIterator(wxPG_ITERATE_VISIBLE, startFrom);
+ !it.AtEnd();
+ it++ )
+ {
+ wxPGProperty* p = *it;
+
+ if ( !p->IsCategory() &&
+ !m_pState->DoIsPropertySelected(p) )
+ {
+ DoAddToSelection(p, selFlags);
+ }
+
+ if ( p == stopAt )
+ break;
+ }
+ }
+ else
+ {
+ res = DoSelectAndEdit(prop, colIndex, selFlags);
+ }
+
+ return res;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoSetSelection( const wxArrayPGProperty& newSelection,
+ int selFlags )
+{
+ if ( newSelection.size() > 0 )
+ {
+ if ( !DoSelectProperty(newSelection[0], selFlags) )
+ return;
+ }
+ else
+ {
+ DoClearSelection(false, selFlags);
+ }
+
+ for ( unsigned int i = 1; i < newSelection.size(); i++ )
+ {
+ DoAddToSelection(newSelection[i], selFlags);
+ }
+
+ Refresh();
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::MakeColumnEditable( unsigned int column,
+ bool editable )
+{
+ wxASSERT( column != 1 );
+
+ wxArrayInt& cols = m_pState->m_editableColumns;
+
+ if ( editable )
+ {
+ cols.push_back(column);
+ }
+ else
+ {
+ for ( int i = cols.size() - 1; i > 0; i-- )
+ {
+ if ( cols[i] == (int)column )
+ cols.erase( cols.begin() + i );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoBeginLabelEdit( unsigned int colIndex,
+ int selFlags )
+{
+ wxPGProperty* selected = GetSelection();
+ wxCHECK_RET(selected, wxT("No property selected"));
+ wxCHECK_RET(colIndex != 1, wxT("Do not use this for column 1"));
+
+ if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+ {
+ if ( SendEvent( wxEVT_PG_LABEL_EDIT_BEGIN,
+ selected, NULL, 0,
+ colIndex ) )
+ return;
+ }
+
+ wxString text;
+ const wxPGCell* cell = NULL;
+ if ( selected->HasCell(colIndex) )
+ {
+ cell = &selected->GetCell(colIndex);
+ if ( !cell->HasText() && colIndex == 0 )
+ text = selected->GetLabel();
+ }
+
+ if ( !cell )
+ {
+ if ( colIndex == 0 )
+ text = selected->GetLabel();
+ else
+ cell = &selected->GetOrCreateCell(colIndex);
+ }
+
+ if ( cell && cell->HasText() )
+ text = cell->GetText();
+
+ DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE); // send event
+
+ m_selColumn = colIndex;
+
+ wxRect r = GetEditorWidgetRect(selected, m_selColumn);
+
+ wxWindow* tc = GenerateEditorTextCtrl(r.GetPosition(),
+ r.GetSize(),
+ text,
+ NULL,
+ wxTE_PROCESS_ENTER,
+ 0,
+ colIndex);
+
+ wxWindowID id = tc->GetId();
+ tc->Connect(id, wxEVT_COMMAND_TEXT_ENTER,
+ wxCommandEventHandler(wxPropertyGrid::OnLabelEditorEnterPress),
+ NULL, this);
+ tc->Connect(id, wxEVT_KEY_DOWN,
+ wxKeyEventHandler(wxPropertyGrid::OnLabelEditorKeyPress),
+ NULL, this);
+
+ tc->SetFocus();
+
+ m_labelEditor = wxStaticCast(tc, wxTextCtrl);
+ m_labelEditorProperty = selected;
+}
+
+// -----------------------------------------------------------------------
+
+void
+wxPropertyGrid::OnLabelEditorEnterPress( wxCommandEvent& WXUNUSED(event) )
+{
+ DoEndLabelEdit(true);
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnLabelEditorKeyPress( wxKeyEvent& event )
+{
+ int keycode = event.GetKeyCode();
+
+ if ( keycode == WXK_ESCAPE )
+ {
+ DoEndLabelEdit(false);
+ }
+ else
+ {
+ HandleKeyEvent(event, true);
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoEndLabelEdit( bool commit, int selFlags )
+{
+ if ( !m_labelEditor )
+ return;
+
+ wxPGProperty* prop = m_labelEditorProperty;
+ wxASSERT(prop);
+
+ if ( commit )
+ {
+ if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+ {
+ // wxPG_SEL_NOVALIDATE is passed correctly in selFlags
+ if ( SendEvent( wxEVT_PG_LABEL_EDIT_ENDING,
+ prop, NULL, selFlags,
+ m_selColumn ) )
+ return;
+ }
+
+ wxString text = m_labelEditor->GetValue();
+ wxPGCell* cell = NULL;
+ if ( prop->HasCell(m_selColumn) )
+ {
+ cell = &prop->GetCell(m_selColumn);
+ }
+ else
+ {
+ if ( m_selColumn == 0 )
+ prop->SetLabel(text);
+ else
+ cell = &prop->GetOrCreateCell(m_selColumn);
+ }
+
+ if ( cell )
+ cell->SetText(text);