Fix bugs to enable read-only grid cells to be copied.

Fixes: lp:1791129
* https://bugs.launchpad.net/kicad/+bug/1791129
This commit is contained in:
Jeff Young 2018-09-12 13:59:33 +01:00
parent 8b064e1ee2
commit 806b1fc63d
8 changed files with 126 additions and 69 deletions

View File

@ -27,6 +27,7 @@
#include <grid_tricks.h>
#include <wx/tokenzr.h>
#include <wx/clipbrd.h>
#include <widgets/grid_readonly_text_helpers.h>
// It works for table data on clipboard for an Excell spreadsheet,
@ -98,7 +99,7 @@ bool GRID_TRICKS::showEditor( int aRow, int aCol )
{
if( m_grid->IsEditable() && !m_grid->IsReadOnly( aRow, aCol ) )
{
if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectionModes::wxGridSelectRows )
if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
m_grid->SelectRow( aRow );
m_grid->SetGridCursor( aRow, aCol );
@ -151,8 +152,20 @@ void GRID_TRICKS::onMouseUp( wxMouseEvent& aEvent )
// it sometimes fails. Activating the control here seems to avoid those issues.
if( m_grid->CanEnableCellControl() )
{
// Yes, the first of these also shows the control. Well, at least sometimes.
// The second call corrects those (as yet undefined) "other times".
m_grid->EnableCellEditControl();
m_grid->ShowCellEditControl();
// Yet another wxWidgets hack: setting the control to readonly results in the
// selection not getting shown. Set it again in the hopes it will get rendered.
wxGridCellEditor* editor = m_grid->GetCellEditor( m_grid->GetCursorRow(), m_grid->GetCursorColumn() );
auto readonly = dynamic_cast<GRID_CELL_READONLY_TEXT_EDITOR*>( editor );
if( readonly )
{
readonly->GetControl()->Refresh();
}
editor->DecRef();
}
m_showEditorOnMouseUp = false;
}
@ -443,7 +456,7 @@ void GRID_TRICKS::onUpdateUI( wxUpdateUIEvent& event )
{
// Respect ROW selectionMode when moving cursor
if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectionModes::wxGridSelectRows )
if( m_grid->GetSelectionMode() == wxGrid::wxGridSelectRows )
{
int cursorRow = m_grid->GetGridCursorRow();
bool cursorInSelectedRow = false;

View File

@ -37,6 +37,7 @@
#include <lib_edit_frame.h>
#include <viewlib_frame.h>
#include <kiway.h>
#include <widgets/grid_readonly_text_helpers.h>
/**
* Build a wxGridTableBase by wrapping an #SYMBOL_LIB_TABLE object.
@ -162,15 +163,16 @@ PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent,
m_project_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *aProject ), true );
// Give a bit more room for combobox editors
m_global_grid->SetDefaultRowSize( m_global_grid->GetDefaultRowSize() + 4 );
m_project_grid->SetDefaultRowSize( m_project_grid->GetDefaultRowSize() + 4 );
m_global_grid->SetDefaultRowSize( m_global_grid->GetDefaultRowSize() + 2 );
m_project_grid->SetDefaultRowSize( m_project_grid->GetDefaultRowSize() + 2 );
// add Cut, Copy, and Paste to wxGrids
m_global_grid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, m_global_grid ) );
m_project_grid->PushEventHandler( new SYMBOL_GRID_TRICKS( m_parent, m_project_grid ) );
m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
m_global_grid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
m_project_grid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
m_global_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_project_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_global_grid->AutoSizeColumns( false );
m_project_grid->AutoSizeColumns( false );
@ -182,10 +184,8 @@ PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent,
populateEnvironReadOnlyTable();
for( int i=0; i<2; ++i )
for( wxGrid* g : { m_global_grid, m_project_grid } )
{
wxGrid* g = i==0 ? m_global_grid : m_project_grid;
// Set special attributes
wxGridCellAttr* attr;
@ -244,19 +244,18 @@ PANEL_SYM_LIB_TABLE::~PANEL_SYM_LIB_TABLE()
// Any additional event handlers should be popped before the window is deleted.
m_global_grid->PopEventHandler( true );
m_project_grid->PopEventHandler( true );
m_path_subs_grid->PopEventHandler( true );
}
bool PANEL_SYM_LIB_TABLE::verifyTables()
{
for( int t=0; t<2; ++t )
for( SYMBOL_LIB_TABLE_GRID* model : { global_model(), project_model() } )
{
SYMBOL_LIB_TABLE_GRID& model = t==0 ? *global_model() : *project_model();
for( int r = 0; r < model.GetNumberRows(); )
for( int r = 0; r < model->GetNumberRows(); )
{
wxString nick = model.GetValue( r, COL_NICKNAME ).Trim( false ).Trim();
wxString uri = model.GetValue( r, COL_URI ).Trim( false ).Trim();
wxString nick = model->GetValue( r, COL_NICKNAME ).Trim( false ).Trim();
wxString uri = model->GetValue( r, COL_URI ).Trim( false ).Trim();
unsigned illegalCh = 0;
if( !nick || !uri )
@ -265,7 +264,7 @@ bool PANEL_SYM_LIB_TABLE::verifyTables()
// This also updates the UI which could be slow, but there should only be a few
// rows to delete, unless the user fell asleep on the Add Row
// button.
model.DeleteRows( r, 1 );
model->DeleteRows( r, 1 );
}
else if( ( illegalCh = LIB_ID::FindIllegalLibNicknameChar( nick, LIB_ID::ID_SCH ) ) )
{
@ -274,8 +273,8 @@ bool PANEL_SYM_LIB_TABLE::verifyTables()
nick );
// show the tabbed panel holding the grid we have flunked:
if( &model != cur_model() )
m_auinotebook->SetSelection( &model == global_model() ? 0 : 1 );
if( model != cur_model() )
m_auinotebook->SetSelection( model == global_model() ? 0 : 1 );
m_cur_grid->MakeCellVisible( r, 0 );
m_cur_grid->SetGridCursor( r, 1 );
@ -287,33 +286,31 @@ bool PANEL_SYM_LIB_TABLE::verifyTables()
else
{
// set the trimmed values back into the table so they get saved to disk.
model.SetValue( r, COL_NICKNAME, nick );
model.SetValue( r, COL_URI, uri );
model->SetValue( r, COL_NICKNAME, nick );
model->SetValue( r, COL_URI, uri );
++r; // this row was OK.
}
}
}
// check for duplicate nickNames, separately in each table.
for( int t=0; t<2; ++t )
for( SYMBOL_LIB_TABLE_GRID* model : { global_model(), project_model() } )
{
SYMBOL_LIB_TABLE_GRID& model = t==0 ? *global_model() : *project_model();
for( int r1 = 0; r1 < model.GetNumberRows() - 1; ++r1 )
for( int r1 = 0; r1 < model->GetNumberRows() - 1; ++r1 )
{
wxString nick1 = model.GetValue( r1, COL_NICKNAME );
wxString nick1 = model->GetValue( r1, COL_NICKNAME );
for( int r2=r1+1; r2 < model.GetNumberRows(); ++r2 )
for( int r2=r1+1; r2 < model->GetNumberRows(); ++r2 )
{
wxString nick2 = model.GetValue( r2, COL_NICKNAME );
wxString nick2 = model->GetValue( r2, COL_NICKNAME );
if( nick1 == nick2 )
{
wxString msg = wxString::Format( _( "Duplicate Nickname: \"%s\"." ), nick1 );
// show the tabbed panel holding the grid we have flunked:
if( &model != cur_model() )
m_auinotebook->SetSelection( &model == global_model() ? 0 : 1 );
if( model != cur_model() )
m_auinotebook->SetSelection( model == global_model() ? 0 : 1 );
// go to the lower of the two rows, it is technically the duplicate:
m_cur_grid->MakeCellVisible( r2, 0 );
@ -604,10 +601,8 @@ void PANEL_SYM_LIB_TABLE::populateEnvironReadOnlyTable()
// clear the table
m_path_subs_grid->DeleteRows( 0, m_path_subs_grid->GetNumberRows() );
for( int i = 0; i < 2; ++i )
for( SYMBOL_LIB_TABLE_GRID* tbl : { global_model(), project_model() } )
{
SYMBOL_LIB_TABLE_GRID* tbl = i == 0 ? global_model() : project_model();
for( int row = 0; row < tbl->GetNumberRows(); ++row )
{
wxString uri = tbl->GetValue( row, COL_URI );
@ -641,15 +636,17 @@ void PANEL_SYM_LIB_TABLE::populateEnvironReadOnlyTable()
m_path_subs_grid->AppendRows( 1 );
m_path_subs_grid->SetCellValue( row, 0, wxT( "${" ) + evName + wxT( "}" ) );
m_path_subs_grid->SetCellEditor( row, 0, new GRID_CELL_READONLY_TEXT_EDITOR() );
wxString evValue;
wxGetEnv( evName, &evValue );
m_path_subs_grid->SetCellValue( row, 1, evValue );
m_path_subs_grid->SetCellEditor( row, 1, new GRID_CELL_READONLY_TEXT_EDITOR() );
}
// No combobox editors here, but it looks better if its consistent with the other
// grids in the dialog.
m_path_subs_grid->SetDefaultRowSize( m_path_subs_grid->GetDefaultRowSize() + 4 );
m_path_subs_grid->SetDefaultRowSize( m_path_subs_grid->GetDefaultRowSize() + 2 );
adjustPathSubsGridColumns( m_path_subs_grid->GetRect().GetWidth() );
}

View File

@ -164,7 +164,7 @@ PANEL_SYM_LIB_TABLE_BASE::PANEL_SYM_LIB_TABLE_BASE( wxWindow* parent, wxWindowID
// Grid
m_path_subs_grid->CreateGrid( 1, 2 );
m_path_subs_grid->EnableEditing( false );
m_path_subs_grid->EnableEditing( true );
m_path_subs_grid->EnableGridLines( true );
m_path_subs_grid->EnableDragGridSize( false );
m_path_subs_grid->SetMargins( 0, 0 );

View File

@ -1557,7 +1557,7 @@
<property name="drag_col_size">1</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">1</property>
<property name="editing">0</property>
<property name="editing">1</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>

View File

@ -0,0 +1,50 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef GRID_READONLY_TEXT_HELPERS_H
#define GRID_READONLY_TEXT_HELPERS_H
#include <wx/textctrl.h>
#include <wx/generic/gridctrl.h>
#include <wx/generic/grideditors.h>
class GRID_CELL_READONLY_TEXT_EDITOR : public wxGridCellTextEditor
{
public:
GRID_CELL_READONLY_TEXT_EDITOR() {};
void Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler)
{
DoCreate(parent, id, evtHandler);
Text()->SetEditable( false );
}
wxDECLARE_NO_COPY_CLASS( GRID_CELL_READONLY_TEXT_EDITOR );
};
#endif // GRID_READONLY_TEXT_HELPERS_H

View File

@ -57,6 +57,7 @@
#include <footprint_viewer_frame.h>
#include <footprint_edit_frame.h>
#include <kiway.h>
#include <widgets/grid_readonly_text_helpers.h>
// Filters for the file picker
static constexpr int FILTER_COUNT = 4;
@ -280,16 +281,17 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent,
m_global_grid->SetTable( new FP_LIB_TABLE_GRID( *aGlobal ), true );
m_project_grid->SetTable( new FP_LIB_TABLE_GRID( *aProject ), true );
// Give a bit more room for combobox editors
m_global_grid->SetDefaultRowSize( m_global_grid->GetDefaultRowSize() + 4 );
m_project_grid->SetDefaultRowSize( m_project_grid->GetDefaultRowSize() + 4 );
// Give a bit more room for wxChoice editors
m_global_grid->SetDefaultRowSize( m_global_grid->GetDefaultRowSize() + 2 );
m_project_grid->SetDefaultRowSize( m_project_grid->GetDefaultRowSize() + 2 );
// add Cut, Copy, and Paste to wxGrids
m_global_grid->PushEventHandler( new FP_GRID_TRICKS( m_parent, m_global_grid ) );
m_project_grid->PushEventHandler( new FP_GRID_TRICKS( m_parent, m_project_grid ) );
m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
m_global_grid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
m_project_grid->SetSelectionMode( wxGrid::wxGridSelectionModes::wxGridSelectRows );
m_global_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_project_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
m_global_grid->AutoSizeColumns( false );
m_project_grid->AutoSizeColumns( false );
@ -308,10 +310,8 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent,
populateEnvironReadOnlyTable();
for( int i=0; i<2; ++i )
for( wxGrid* g : { m_global_grid, m_project_grid } )
{
wxGrid* g = i==0 ? m_global_grid : m_project_grid;
wxGridCellAttr* attr;
attr = new wxGridCellAttr;
@ -368,19 +368,18 @@ PANEL_FP_LIB_TABLE::~PANEL_FP_LIB_TABLE()
// Any additional event handlers should be popped before the window is deleted.
m_global_grid->PopEventHandler( true );
m_project_grid->PopEventHandler( true );
m_path_subs_grid->PopEventHandler( true );
}
bool PANEL_FP_LIB_TABLE::verifyTables()
{
for( int t=0; t<2; ++t )
for( FP_LIB_TABLE_GRID* model : { global_model(), project_model() } )
{
FP_LIB_TABLE_GRID& model = t==0 ? *global_model() : *project_model();
for( int r = 0; r < model.GetNumberRows(); )
for( int r = 0; r < model->GetNumberRows(); )
{
wxString nick = model.GetValue( r, COL_NICKNAME ).Trim( false ).Trim();
wxString uri = model.GetValue( r, COL_URI ).Trim( false ).Trim();
wxString nick = model->GetValue( r, COL_NICKNAME ).Trim( false ).Trim();
wxString uri = model->GetValue( r, COL_URI ).Trim( false ).Trim();
unsigned illegalCh = 0;
if( !nick || !uri )
@ -389,7 +388,7 @@ bool PANEL_FP_LIB_TABLE::verifyTables()
// This also updates the UI which could be slow, but there should only be a few
// rows to delete, unless the user fell asleep on the Add Row
// button.
model.DeleteRows( r, 1 );
model->DeleteRows( r, 1 );
}
else if( ( illegalCh = LIB_ID::FindIllegalLibNicknameChar( nick, LIB_ID::ID_PCB ) ) )
{
@ -398,8 +397,8 @@ bool PANEL_FP_LIB_TABLE::verifyTables()
nick );
// show the tabbed panel holding the grid we have flunked:
if( &model != cur_model() )
m_auinotebook->SetSelection( &model == global_model() ? 0 : 1 );
if( model != cur_model() )
m_auinotebook->SetSelection( model == global_model() ? 0 : 1 );
m_cur_grid->MakeCellVisible( r, 0 );
m_cur_grid->SetGridCursor( r, 1 );
@ -411,33 +410,31 @@ bool PANEL_FP_LIB_TABLE::verifyTables()
else
{
// set the trimmed values back into the table so they get saved to disk.
model.SetValue( r, COL_NICKNAME, nick );
model.SetValue( r, COL_URI, uri );
model->SetValue( r, COL_NICKNAME, nick );
model->SetValue( r, COL_URI, uri );
++r; // this row was OK.
}
}
}
// check for duplicate nickNames, separately in each table.
for( int t=0; t<2; ++t )
for( FP_LIB_TABLE_GRID* model : { global_model(), project_model() } )
{
FP_LIB_TABLE_GRID& model = t==0 ? *global_model() : *project_model();
for( int r1 = 0; r1 < model.GetNumberRows() - 1; ++r1 )
for( int r1 = 0; r1 < model->GetNumberRows() - 1; ++r1 )
{
wxString nick1 = model.GetValue( r1, COL_NICKNAME );
wxString nick1 = model->GetValue( r1, COL_NICKNAME );
for( int r2=r1+1; r2 < model.GetNumberRows(); ++r2 )
for( int r2 = r1 + 1; r2 < model->GetNumberRows(); ++r2 )
{
wxString nick2 = model.GetValue( r2, COL_NICKNAME );
wxString nick2 = model->GetValue( r2, COL_NICKNAME );
if( nick1 == nick2 )
{
wxString msg = wxString::Format( _( "Duplicate Nicknames \"%s\"." ), nick1 );
// show the tabbed panel holding the grid we have flunked:
if( &model != cur_model() )
m_auinotebook->SetSelection( &model == global_model() ? 0 : 1 );
if( model != cur_model() )
m_auinotebook->SetSelection( model == global_model() ? 0 : 1 );
// go to the lower of the two rows, it is technically the duplicate:
m_cur_grid->MakeCellVisible( r2, 0 );
@ -739,10 +736,8 @@ void PANEL_FP_LIB_TABLE::populateEnvironReadOnlyTable()
// clear the table
m_path_subs_grid->DeleteRows( 0, m_path_subs_grid->GetNumberRows() );
for( int i = 0; i < 2; ++i )
for( FP_LIB_TABLE_GRID* tbl : { global_model(), project_model() } )
{
FP_LIB_TABLE_GRID* tbl = i == 0 ? global_model() : project_model();
for( int row = 0; row < tbl->GetNumberRows(); ++row )
{
wxString uri = tbl->GetValue( row, COL_URI );
@ -778,15 +773,17 @@ void PANEL_FP_LIB_TABLE::populateEnvironReadOnlyTable()
m_path_subs_grid->AppendRows( 1 );
m_path_subs_grid->SetCellValue( row, 0, wxT( "${" ) + evName + wxT( "}" ) );
m_path_subs_grid->SetCellEditor( row, 0, new GRID_CELL_READONLY_TEXT_EDITOR() );
wxString evValue;
wxGetEnv( evName, &evValue );
m_path_subs_grid->SetCellValue( row, 1, evValue );
m_path_subs_grid->SetCellEditor( row, 1, new GRID_CELL_READONLY_TEXT_EDITOR() );
}
// No combobox editors here, but it looks better if its consistent with the other
// grids in the dialog.
m_path_subs_grid->SetDefaultRowSize( m_path_subs_grid->GetDefaultRowSize() + 4 );
m_path_subs_grid->SetDefaultRowSize( m_path_subs_grid->GetDefaultRowSize() + 2 );
adjustPathSubsGridColumns( m_path_subs_grid->GetRect().GetWidth() );
}

View File

@ -163,7 +163,7 @@ PANEL_FP_LIB_TABLE_BASE::PANEL_FP_LIB_TABLE_BASE( wxWindow* parent, wxWindowID i
// Grid
m_path_subs_grid->CreateGrid( 1, 2 );
m_path_subs_grid->EnableEditing( false );
m_path_subs_grid->EnableEditing( true );
m_path_subs_grid->EnableGridLines( true );
m_path_subs_grid->EnableDragGridSize( false );
m_path_subs_grid->SetMargins( 0, 0 );

View File

@ -1557,7 +1557,7 @@
<property name="drag_col_size">1</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">1</property>
<property name="editing">0</property>
<property name="editing">1</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>