KiCad PCB EDA Suite
Loading...
Searching...
No Matches
edit_table_tool_base.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef EDIT_TABLE_TOOL_BASE_H
21#define EDIT_TABLE_TOOL_BASE_H
22
23#include <tool/tool_base.h>
24#include <tool/selection.h>
25#include <tool/actions.h>
26#include <wx/translation.h>
27
28class BASE_SCREEN;
29
30
35
36
37template<typename T_TABLE, typename T_TABLECELL, typename T_COMMIT>
39{
40protected:
41 void addMenus( CONDITIONAL_MENU& selToolMenu )
42 {
43 auto cellSelection = SELECTION_CONDITIONS::MoreThan( 0 )
45
46 auto cellBlockSelection = []( const SELECTION& sel )
47 {
48 if( sel.Size() < 2 )
49 return false;
50
51 int colMin = std::numeric_limits<int>::max();
52 int colMax = 0;
53 int rowMin = std::numeric_limits<int>::max();
54 int rowMax = 0;
55 int selectedArea = 0;
56
57 for( EDA_ITEM* item : sel )
58 {
59 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
60 {
61 colMin = std::min( colMin, cell->GetColumn() );
62 colMax = std::max( colMax, cell->GetColumn() + cell->GetColSpan() );
63 rowMin = std::min( rowMin, cell->GetRow() );
64 rowMax = std::max( rowMax, cell->GetRow() + cell->GetRowSpan() );
65
66 selectedArea += cell->GetColSpan() * cell->GetRowSpan();
67 }
68 }
69
70 return selectedArea == ( colMax - colMin ) * ( rowMax - rowMin );
71 };
72
73 auto mergedCellsSelection = []( const SELECTION& sel )
74 {
75 for( EDA_ITEM* item : sel )
76 {
77 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
78 {
79 if( cell->GetColSpan() > 1 || cell->GetRowSpan() > 1 )
80 return true;
81 }
82 }
83
84 return false;
85 };
86
87 //
88 // Add editing actions to the selection tool menu
89 //
90 selToolMenu.AddSeparator( 100 );
91 selToolMenu.AddItem( ACTIONS::addRowAbove, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
92 selToolMenu.AddItem( ACTIONS::addRowBelow, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
93 selToolMenu.AddItem( ACTIONS::addColBefore, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
94 selToolMenu.AddItem( ACTIONS::addColAfter, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
95
96 selToolMenu.AddSeparator( 100 );
97 selToolMenu.AddItem( ACTIONS::deleteRows, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
98 selToolMenu.AddItem( ACTIONS::deleteColumns, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
99
100 selToolMenu.AddSeparator( 100 );
101 selToolMenu.AddItem( ACTIONS::mergeCells, cellSelection && cellBlockSelection, 100 );
102 selToolMenu.AddItem( ACTIONS::unmergeCells, cellSelection && mergedCellsSelection, 100 );
103
104 selToolMenu.AddSeparator( 100 );
105 selToolMenu.AddItem( ACTIONS::editTable, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
106
107 selToolMenu.AddSeparator( 100 );
108 selToolMenu.AddItem( ACTIONS::exportTableCSV, cellSelection && SELECTION_CONDITIONS::Idle, 100 );
109
110 selToolMenu.AddSeparator( 100 );
111 }
112
113 int doAddRowAbove( const TOOL_EVENT& aEvent )
114 {
115 const SELECTION& selection = getTableCellSelection();
116 T_TABLECELL* topmost = nullptr;
117
118 for( EDA_ITEM* item : selection )
119 {
120 T_TABLECELL* cell = static_cast<T_TABLECELL*>( item );
121
122 if( !topmost || cell->GetRow() < topmost->GetRow() )
123 topmost = cell;
124 }
125
126 if( !topmost )
127 return 0;
128
129 int row = topmost->GetRow();
130 T_TABLE* table = static_cast<T_TABLE*>( topmost->GetParent() );
131 T_COMMIT commit( getToolMgr() );
132 VECTOR2I pos = table->GetPosition();
133
134 // Make a copy of the source row before things start moving around
135 std::vector<T_TABLECELL*> sources;
136 sources.reserve( table->GetColCount() );
137
138 for( int col = 0; col < table->GetColCount(); ++col )
139 sources.push_back( table->GetCell( row, col ) );
140
141 commit.Modify( table, getScreen() );
142
143 for( int col = 0; col < table->GetColCount(); ++col )
144 {
145 T_TABLECELL* cell = copyCell( sources[col] );
146 table->InsertCell( row * table->GetColCount(), cell );
147 }
148
149 for( int afterRow = table->GetRowCount() - 1; afterRow > row; afterRow-- )
150 table->SetRowHeight( afterRow, table->GetRowHeight( afterRow - 1 ) );
151
152 table->SetPosition( pos );
153 table->Normalize();
154
156
157 commit.Push( _( "Add Row Above" ) );
158
159 return 0;
160 }
161
162 int doAddRowBelow( const TOOL_EVENT& aEvent )
163 {
164 const SELECTION& selection = getTableCellSelection();
165 T_TABLECELL* bottommost = nullptr;
166
167 if( selection.Empty() )
168 return 0;
169
170 for( EDA_ITEM* item : selection )
171 {
172 T_TABLECELL* cell = static_cast<T_TABLECELL*>( item );
173
174 if( !bottommost || cell->GetRow() > bottommost->GetRow() )
175 bottommost = cell;
176 }
177
178 if( !bottommost )
179 return 0;
180
181 int row = bottommost->GetRow();
182 T_TABLE* table = static_cast<T_TABLE*>( bottommost->GetParent() );
183 T_COMMIT commit( getToolMgr() );
184 VECTOR2I pos = table->GetPosition();
185
186 // Make a copy of the source row before things start moving around
187 std::vector<T_TABLECELL*> sources;
188 sources.reserve( table->GetColCount() );
189
190 for( int col = 0; col < table->GetColCount(); ++col )
191 sources.push_back( table->GetCell( row, col ) );
192
193 commit.Modify( table, getScreen() );
194
195 for( int col = 0; col < table->GetColCount(); ++col )
196 {
197 T_TABLECELL* cell = copyCell( sources[col] );
198 table->InsertCell( ( row + 1 ) * table->GetColCount(), cell );
199 }
200
201 for( int afterRow = table->GetRowCount() - 1; afterRow > row; afterRow-- )
202 table->SetRowHeight( afterRow, table->GetRowHeight( afterRow - 1 ) );
203
204 table->SetPosition( pos );
205 table->Normalize();
206
208
209 commit.Push( _( "Add Row Below" ) );
210
211 return 0;
212 }
213
214 int doAddColumnBefore( const TOOL_EVENT& aEvent )
215 {
216 const SELECTION& selection = getTableCellSelection();
217 T_TABLECELL* leftmost = nullptr;
218
219 for( EDA_ITEM* item : selection )
220 {
221 T_TABLECELL* cell = static_cast<T_TABLECELL*>( item );
222
223 if( !leftmost || cell->GetColumn() < leftmost->GetColumn() )
224 leftmost = cell;
225 }
226
227 if( !leftmost )
228 return 0;
229
230 int col = leftmost->GetColumn();
231 T_TABLE* table = static_cast<T_TABLE*>( leftmost->GetParent() );
232 int rowCount = table->GetRowCount();
233 T_COMMIT commit( getToolMgr() );
234 VECTOR2I pos = table->GetPosition();
235
236 // Make a copy of the source column before things start moving around
237 std::vector<T_TABLECELL*> sources;
238 sources.reserve( rowCount );
239
240 for( int row = 0; row < rowCount; ++row )
241 sources.push_back( table->GetCell( row, col ) );
242
243 commit.Modify( table, getScreen() );
244 table->SetColCount( table->GetColCount() + 1 );
245
246 for( int row = 0; row < rowCount; ++row )
247 {
248 T_TABLECELL* cell = copyCell( sources[row] );
249 table->InsertCell( row * table->GetColCount() + col, cell );
250 }
251
252 for( int afterCol = table->GetColCount() - 1; afterCol > col; afterCol-- )
253 table->SetColWidth( afterCol, table->GetColWidth( afterCol - 1 ) );
254
255 table->SetPosition( pos );
256 table->Normalize();
257
259
260 commit.Push( _( "Add Column Before" ) );
261
262 return 0;
263 }
264
265 int doAddColumnAfter( const TOOL_EVENT& aEvent )
266 {
267 const SELECTION& selection = getTableCellSelection();
268 T_TABLECELL* rightmost = nullptr;
269
270 for( EDA_ITEM* item : selection )
271 {
272 T_TABLECELL* cell = static_cast<T_TABLECELL*>( item );
273
274 if( !rightmost || cell->GetColumn() > rightmost->GetColumn() )
275 rightmost = cell;
276 }
277
278 if( !rightmost )
279 return 0;
280
281 int col = rightmost->GetColumn();
282 T_TABLE* table = static_cast<T_TABLE*>( rightmost->GetParent() );
283 int rowCount = table->GetRowCount();
284 T_COMMIT commit( getToolMgr() );
285 VECTOR2I pos = table->GetPosition();
286
287 // Make a copy of the source column before things start moving around
288 std::vector<T_TABLECELL*> sources;
289 sources.reserve( rowCount );
290
291 for( int row = 0; row < rowCount; ++row )
292 sources.push_back( table->GetCell( row, col ) );
293
294 commit.Modify( table, getScreen() );
295 table->SetColCount( table->GetColCount() + 1 );
296
297 for( int row = 0; row < rowCount; ++row )
298 {
299 T_TABLECELL* cell = copyCell( sources[row] );
300 table->InsertCell( row * table->GetColCount() + col + 1, cell );
301 }
302
303 for( int afterCol = table->GetColCount() - 1; afterCol > col; afterCol-- )
304 table->SetColWidth( afterCol, table->GetColWidth( afterCol - 1 ) );
305
306 table->SetPosition( pos );
307 table->Normalize();
308
310
311 commit.Push( _( "Add Column After" ) );
312
313 return 0;
314 }
315
316 int doDeleteRows( const TOOL_EVENT& aEvent )
317 {
318 const SELECTION& selection = getTableCellSelection();
319
320 if( selection.Empty() )
321 return 0;
322
323 T_TABLE* table = static_cast<T_TABLE*>( selection[0]->GetParent() );
324 std::vector<int> deleted;
325
326 for( T_TABLECELL* cell : table->GetCells() )
327 cell->ClearFlags( STRUCT_DELETED );
328
329 for( int row = 0; row < table->GetRowCount(); ++row )
330 {
331 bool deleteRow = false;
332
333 for( int col = 0; col < table->GetColCount(); ++col )
334 {
335 if( table->GetCell( row, col )->IsSelected() )
336 {
337 deleteRow = true;
338 break;
339 }
340 }
341
342 if( deleteRow )
343 {
344 for( int col = 0; col < table->GetColCount(); ++col )
345 table->GetCell( row, col )->SetFlags( STRUCT_DELETED );
346
347 deleted.push_back( row );
348 }
349 }
350
351 T_COMMIT commit( getToolMgr() );
352
353 if( deleted.size() == (unsigned) table->GetRowCount() )
354 {
355 commit.Remove( table, getScreen() );
356 }
357 else
358 {
359 commit.Modify( table, getScreen() );
360
361 VECTOR2I pos = table->GetPosition();
362
363 // Save old row heights BEFORE deleting cells
364 std::map<int, int> oldRowHeights;
365 for( int row = 0; row < table->GetRowCount(); ++row )
366 oldRowHeights[row] = table->GetRowHeight( row );
367
369 table->DeleteMarkedCells();
370
371 for( int row = 0; row < table->GetRowCount(); ++row )
372 {
373 int old_row = row;
374
375 for( int deletedRow : deleted )
376 {
377 if( deletedRow <= old_row )
378 old_row++;
379 }
380
381 // Use saved old heights instead of querying the modified table
382 int height = ( oldRowHeights.count( old_row ) ) ? oldRowHeights[old_row] : 0;
383 table->SetRowHeight( row, height );
384 }
385
386 table->SetPosition( pos );
387 table->Normalize();
388
390 }
391
392 if( deleted.size() > 1 )
393 commit.Push( _( "Delete Rows" ) );
394 else
395 commit.Push( _( "Delete Row" ) );
396
397 return 0;
398 }
399
400 int doDeleteColumns( const TOOL_EVENT& aEvent )
401 {
402 const SELECTION& selection = getTableCellSelection();
403
404 if( selection.Empty() )
405 return 0;
406
407 T_TABLE* table = static_cast<T_TABLE*>( selection[0]->GetParent() );
408 std::vector<int> deleted;
409
410 for( T_TABLECELL* cell : table->GetCells() )
411 cell->ClearFlags( STRUCT_DELETED );
412
413 for( int col = 0; col < table->GetColCount(); ++col )
414 {
415 bool deleteColumn = false;
416
417 for( int row = 0; row < table->GetRowCount(); ++row )
418 {
419 if( table->GetCell( row, col )->IsSelected() )
420 {
421 deleteColumn = true;
422 break;
423 }
424 }
425
426 if( deleteColumn )
427 {
428 for( int row = 0; row < table->GetRowCount(); ++row )
429 table->GetCell( row, col )->SetFlags( STRUCT_DELETED );
430
431 deleted.push_back( col );
432 }
433 }
434
435 T_COMMIT commit( getToolMgr() );
436
437 if( deleted.size() == (unsigned) table->GetColCount() )
438 {
439 commit.Remove( table, getScreen() );
440 }
441 else
442 {
443 commit.Modify( table, getScreen() );
444
445 VECTOR2I pos = table->GetPosition();
446
448 table->DeleteMarkedCells();
449 table->SetColCount( table->GetColCount() - deleted.size() );
450
451 for( int col = 0; col < table->GetColCount(); ++col )
452 {
453 int old_col = col;
454
455 for( int deletedCol : deleted )
456 {
457 if( deletedCol <= old_col )
458 old_col++;
459 }
460
461 table->SetColWidth( col, table->GetColWidth( old_col ) );
462 }
463
464 table->SetPosition( pos );
465 table->Normalize();
466
468 }
469
470 if( deleted.size() > 1 )
471 commit.Push( _( "Delete Columns" ) );
472 else
473 commit.Push( _( "Delete Column" ) );
474
475 return 0;
476 }
477
478 int doMergeCells( const TOOL_EVENT& aEvent )
479 {
480 const SELECTION& sel = getTableCellSelection();
481
482 if( sel.Empty() )
483 return 0;
484
485 int colMin = std::numeric_limits<int>::max();
486 int colMax = 0;
487 int rowMin = std::numeric_limits<int>::max();
488 int rowMax = 0;
489
490 T_COMMIT commit( getToolMgr() );
491 T_TABLE* table = static_cast<T_TABLE*>( sel[0]->GetParent() );
492
493 for( EDA_ITEM* item : sel )
494 {
495 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
496 {
497 colMin = std::min( colMin, cell->GetColumn() );
498 colMax = std::max( colMax, cell->GetColumn() + cell->GetColSpan() );
499 rowMin = std::min( rowMin, cell->GetRow() );
500 rowMax = std::max( rowMax, cell->GetRow() + cell->GetRowSpan() );
501 }
502 }
503
504 wxString content;
505 VECTOR2I extents;
506
507 for( int row = rowMin; row < rowMax; ++row )
508 {
509 extents.y += table->GetRowHeight( row );
510 extents.x = 0;
511
512 for( int col = colMin; col < colMax; ++col )
513 {
514 extents.x += table->GetColWidth( col );
515
516 T_TABLECELL* cell = table->GetCell( row, col );
517
518 if( !cell->GetText().IsEmpty() )
519 {
520 if( !content.IsEmpty() )
521 content += "\n";
522
523 content += cell->GetText();
524 }
525
526 commit.Modify( cell, getScreen() );
527 cell->SetColSpan( 0 );
528 cell->SetRowSpan( 0 );
529 cell->SetText( wxEmptyString );
530 }
531 }
532
533 T_TABLECELL* topLeft = table->GetCell( rowMin, colMin );
534 topLeft->SetColSpan( colMax - colMin );
535 topLeft->SetRowSpan( rowMax - rowMin );
536 topLeft->SetText( content );
537 topLeft->SetEnd( topLeft->GetStart() + extents );
538
539 table->Normalize();
540 commit.Push( _( "Merge Cells" ) );
541
543
544 return 0;
545 }
546
547 int doUnmergeCells( const TOOL_EVENT& aEvent )
548 {
549 const SELECTION& sel = getTableCellSelection();
550
551 if( sel.Empty() )
552 return 0;
553
554 T_COMMIT commit( getToolMgr() );
555 T_TABLE* table = static_cast<T_TABLE*>( sel[0]->GetParent() );
556
557 for( EDA_ITEM* item : sel )
558 {
559 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
560 {
561 int rowSpan = cell->GetRowSpan();
562 int colSpan = cell->GetColSpan();
563
564 for( int row = cell->GetRow(); row < cell->GetRow() + rowSpan; ++row )
565 {
566 for( int col = cell->GetColumn(); col < cell->GetColumn() + colSpan; ++col )
567 {
568 T_TABLECELL* target = table->GetCell( row, col );
569 commit.Modify( target, getScreen() );
570 target->SetColSpan( 1 );
571 target->SetRowSpan( 1 );
572
573 VECTOR2I extents( table->GetColWidth( col ), table->GetRowHeight( row ) );
574 target->SetEnd( target->GetStart() + extents );
575 }
576 }
577 }
578 }
579
580 table->Normalize();
581 commit.Push( _( "Unmerge Cells" ) );
582
584
585 return 0;
586 }
587
588public:
598 bool getCellBlockBounds( const SELECTION& aSel, int& aColMin, int& aColMax, int& aRowMin, int& aRowMax )
599 {
600 if( aSel.Size() < 1 )
601 return false;
602
603 aColMin = std::numeric_limits<int>::max();
604 aColMax = 0;
605 aRowMin = std::numeric_limits<int>::max();
606 aRowMax = 0;
607 int selectedArea = 0;
608
609 for( EDA_ITEM* item : aSel )
610 {
611 if( T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item ) )
612 {
613 aColMin = std::min( aColMin, cell->GetColumn() );
614 aColMax = std::max( aColMax, cell->GetColumn() + cell->GetColSpan() );
615 aRowMin = std::min( aRowMin, cell->GetRow() );
616 aRowMax = std::max( aRowMax, cell->GetRow() + cell->GetRowSpan() );
617
618 selectedArea += cell->GetColSpan() * cell->GetRowSpan();
619 }
620 }
621
622 // Check if selection is contiguous (for single cell, we allow it)
623 if( aSel.Size() == 1 )
624 return true;
625
626 return selectedArea == ( aColMax - aColMin ) * ( aRowMax - aRowMin );
627 }
628
635 bool validatePasteIntoSelection( const SELECTION& aSel, wxString& aErrorMsg )
636 {
637 if( aSel.Empty() )
638 {
639 aErrorMsg = _( "No cells selected" );
640 return false;
641 }
642
643 // Check if all selected items are table cells from the same table
644 T_TABLE* table = nullptr;
645
646 for( EDA_ITEM* item : aSel )
647 {
648 T_TABLECELL* cell = dynamic_cast<T_TABLECELL*>( item );
649
650 if( !cell )
651 {
652 aErrorMsg = _( "Selection contains non-cell items" );
653 return false;
654 }
655
656 if( !table )
657 {
658 table = static_cast<T_TABLE*>( cell->GetParent() );
659 }
660 else if( cell->GetParent() != table )
661 {
662 aErrorMsg = _( "Selected cells are from different tables" );
663 return false;
664 }
665
666 // Check for merged cells (block paste-into for now)
667 if( cell->GetColSpan() > 1 || cell->GetRowSpan() > 1 )
668 {
669 aErrorMsg = _( "Cannot paste into merged cells" );
670 return false;
671 }
672 }
673
674 // Check if selection is contiguous
675 int colMin, colMax, rowMin, rowMax;
676
677 if( !getCellBlockBounds( aSel, colMin, colMax, rowMin, rowMax ) )
678 {
679 aErrorMsg = _( "Selected cells must form a contiguous block" );
680 return false;
681 }
682
683 return true;
684 }
685
693 bool pasteCellsIntoSelection( const SELECTION& aSel, T_TABLE* aSourceTable, T_COMMIT& aCommit )
694 {
695 if( !aSourceTable || aSel.Empty() )
696 return false;
697
698 // Get target cell range
699 int targetColMin, targetColMax, targetRowMin, targetRowMax;
700
701 if( !getCellBlockBounds( aSel, targetColMin, targetColMax, targetRowMin, targetRowMax ) )
702 return false;
703
704 T_TABLE* targetTable = static_cast<T_TABLE*>( static_cast<T_TABLECELL*>( aSel[0] )->GetParent() );
705
706 // Get source table dimensions
707 int sourceRows = aSourceTable->GetRowCount();
708 int sourceCols = aSourceTable->GetColCount();
709
710 int pasteEndRow = targetRowMin + sourceRows;
711 int pasteEndCol = targetColMin + sourceCols;
712
713 if( pasteEndRow > targetTable->GetRowCount() || pasteEndCol > targetTable->GetColCount() )
714 {
715 int rowsToAdd = std::max( 0, pasteEndRow - targetTable->GetRowCount() );
716 int colsToAdd = std::max( 0, pasteEndCol - targetTable->GetColCount() );
717
718 VECTOR2I pos = targetTable->GetPosition();
719 aCommit.Modify( targetTable, getScreen() );
720
721 for( int i = 0; i < rowsToAdd; ++i )
722 {
723 int insertRow = targetTable->GetRowCount();
724 int clipboardRow = insertRow - targetRowMin;
725
726 std::vector<T_TABLECELL*> sources;
727 sources.reserve( aSourceTable->GetColCount() );
728
729 for( int col = 0; col < aSourceTable->GetColCount(); ++col )
730 sources.push_back( aSourceTable->GetCell( clipboardRow, col ) );
731
732 for( int col = 0; col < targetTable->GetColCount(); ++col )
733 {
734 T_TABLECELL* sourceCell = ( col < aSourceTable->GetColCount() ) ? sources[col] : sources[0];
735 T_TABLECELL* cell = copyCell( sourceCell );
736 targetTable->InsertCell( insertRow * targetTable->GetColCount(), cell );
737 }
738
739 for( int afterRow = targetTable->GetRowCount() - 1; afterRow > insertRow; afterRow-- )
740 targetTable->SetRowHeight( afterRow, targetTable->GetRowHeight( afterRow - 1 ) );
741
742 targetTable->SetRowHeight( insertRow, aSourceTable->GetRowHeight( clipboardRow ) );
743 }
744
745 for( int i = 0; i < colsToAdd; ++i )
746 {
747 int insertCol = targetTable->GetColCount();
748 int clipboardCol = insertCol - targetColMin;
749 int rowCount = targetTable->GetRowCount();
750
751 targetTable->SetColCount( targetTable->GetColCount() + 1 );
752
753 std::vector<T_TABLECELL*> sources;
754 sources.reserve( aSourceTable->GetRowCount() );
755
756 for( int row = 0; row < aSourceTable->GetRowCount(); ++row )
757 sources.push_back( aSourceTable->GetCell( row, clipboardCol ) );
758
759 for( int row = 0; row < rowCount; ++row )
760 {
761 T_TABLECELL* sourceCell = ( row < aSourceTable->GetRowCount() ) ? sources[row] : sources[0];
762 T_TABLECELL* cell = copyCell( sourceCell );
763 targetTable->InsertCell( row * targetTable->GetColCount() + insertCol, cell );
764 }
765
766 for( int afterCol = targetTable->GetColCount() - 1; afterCol > insertCol; afterCol-- )
767 targetTable->SetColWidth( afterCol, targetTable->GetColWidth( afterCol - 1 ) );
768
769 targetTable->SetColWidth( insertCol, aSourceTable->GetColWidth( clipboardCol ) );
770 }
771
772 targetTable->SetPosition( pos );
773 targetTable->Normalize();
774 }
775
776 for( int srcRow = 0; srcRow < sourceRows; ++srcRow )
777 {
778 for( int srcCol = 0; srcCol < sourceCols; ++srcCol )
779 {
780 int destRow = targetRowMin + srcRow;
781 int destCol = targetColMin + srcCol;
782
783 if( destRow >= targetTable->GetRowCount() || destCol >= targetTable->GetColCount() )
784 continue;
785
786 T_TABLECELL* sourceCell = aSourceTable->GetCell( srcRow, srcCol );
787 T_TABLECELL* targetCell = targetTable->GetCell( destRow, destCol );
788
789 aCommit.Modify( targetCell, getScreen() );
790
791 targetCell->SetText( sourceCell->GetText() );
792 targetCell->SetAttributes( *sourceCell, false );
793 targetCell->SetStroke( sourceCell->GetStroke() );
794 targetCell->SetFillMode( sourceCell->GetFillMode() );
795 targetCell->SetFillColor( sourceCell->GetFillColor() );
796 }
797 }
798
799 targetTable->Normalize();
800 return true;
801 }
802
803 virtual TOOL_MANAGER* getToolMgr() = 0;
804 virtual BASE_SCREEN* getScreen() = 0;
805
806 virtual const SELECTION& getTableCellSelection() = 0;
807 virtual void clearSelection() = 0;
808
809 virtual T_TABLECELL* copyCell( T_TABLECELL* aSource ) = 0;
810};
811
812#endif //EDIT_TABLE_TOOL_BASE_H
static TOOL_ACTION addRowAbove
Definition actions.h:100
static TOOL_ACTION addColBefore
Definition actions.h:102
static TOOL_ACTION deleteRows
Definition actions.h:104
static TOOL_ACTION addRowBelow
Definition actions.h:101
static TOOL_ACTION deleteColumns
Definition actions.h:105
static TOOL_ACTION unmergeCells
Definition actions.h:107
static TOOL_ACTION mergeCells
Definition actions.h:106
static TOOL_ACTION addColAfter
Definition actions.h:103
static TOOL_ACTION editTable
Definition actions.h:108
static TOOL_ACTION exportTableCSV
Definition actions.h:109
Handles how to draw a screen (a board, a schematic ...)
Definition base_screen.h:37
void AddItem(const TOOL_ACTION &aAction, const SELECTION_CONDITION &aCondition, int aOrder=ANY_ORDER)
Add a menu entry to run a TOOL_ACTION on selected items.
void AddSeparator(int aOrder=ANY_ORDER)
Add a separator to the menu.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
SCH_TABLE_EDIT_TOOL and PCB_TABLE_EDIT_TOOL share most of their algorithms, which are implemented her...
virtual TOOL_MANAGER * getToolMgr()=0
int doDeleteColumns(const TOOL_EVENT &aEvent)
int doAddColumnAfter(const TOOL_EVENT &aEvent)
int doAddRowBelow(const TOOL_EVENT &aEvent)
int doAddColumnBefore(const TOOL_EVENT &aEvent)
bool getCellBlockBounds(const SELECTION &aSel, int &aColMin, int &aColMax, int &aRowMin, int &aRowMax)
Get the bounding box of a cell block selection.
int doAddRowAbove(const TOOL_EVENT &aEvent)
int doMergeCells(const TOOL_EVENT &aEvent)
virtual const SELECTION & getTableCellSelection()=0
virtual BASE_SCREEN * getScreen()=0
bool validatePasteIntoSelection(const SELECTION &aSel, wxString &aErrorMsg)
Validate if paste-into-cells is possible for the given selection.
int doDeleteRows(const TOOL_EVENT &aEvent)
virtual T_TABLECELL * copyCell(T_TABLECELL *aSource)=0
void addMenus(CONDITIONAL_MENU &selToolMenu)
bool pasteCellsIntoSelection(const SELECTION &aSel, T_TABLE *aSourceTable, T_COMMIT &aCommit)
Paste text content from source table into selected cells.
virtual void clearSelection()=0
int doUnmergeCells(const TOOL_EVENT &aEvent)
static const TOOL_EVENT SelectedEvent
Definition actions.h:341
static SELECTION_CONDITION MoreThan(int aNumber)
Create a functor that tests if the number of selected items is greater than the value given as parame...
static bool Idle(const SELECTION &aSelection)
Test if there no items selected or being edited.
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
int Size() const
Returns the number of selected parts.
Definition selection.h:117
bool Empty() const
Checks if there is anything selected.
Definition selection.h:111
Generic, UI-independent tool event.
Definition tool_event.h:167
Master controller class:
void PostEvent(const TOOL_EVENT &aEvent)
Put an event to the event queue to be processed at the end of event processing cycle.
#define _(s)
#define STRUCT_DELETED
flag indication structures to be erased
std::vector< std::vector< std::string > > table
@ SCH_TABLECELL_T
Definition typeinfo.h:163
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:88
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683