KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_sheet_properties.cpp
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 (C) 2009 Wayne Stambaugh <[email protected]>
5 * Copyright The KiCad Developers, see CHANGELOG.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
26
27#include <kiface_base.h>
28#include <wx/string.h>
29#include <wx/log.h>
30#include <wx/tooltip.h>
31#include <common.h>
32#include <confirm.h>
33#include <kidialog.h>
34#include <validators.h>
35#include <wx_filename.h>
38#include <kiplatform/ui.h>
39#include <sch_commit.h>
40#include <sch_edit_frame.h>
41#include <sch_io/sch_io.h>
42#include <sch_sheet.h>
43#include <schematic.h>
44#include <bitmaps.h>
45#include <eeschema_settings.h>
47#include <trace_helpers.h>
49#include "wx/dcclient.h"
50#include "string_utils.h"
51
53 bool* aIsUndoable, bool* aClearAnnotationNewItems,
54 bool* aUpdateHierarchyNavigator,
55 wxString* aSourceSheetFilename ) :
57 m_frame( aParent ),
58 m_isUndoable( aIsUndoable ),
59 m_clearAnnotationNewItems( aClearAnnotationNewItems ),
60 m_updateHierarchyNavigator( aUpdateHierarchyNavigator ),
61 m_sourceSheetFilename( aSourceSheetFilename ),
63 m_dummySheet( *aSheet ),
65{
66 m_sheet = aSheet;
67 m_fields = new FIELDS_GRID_TABLE( this, aParent, m_grid, m_sheet );
70
71 m_grid->SetTable( m_fields );
72 m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this, { &aParent->Schematic() },
73 [&]( wxCommandEvent& aEvent )
74 {
75 OnAddField( aEvent );
76 } ) );
77 m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
78 m_grid->ShowHideColumns( "0 1 2 3 4 5 6 7" );
79 m_shownColumns = m_grid->GetShownColumns();
80
81 if( m_frame->GetColorSettings()->GetOverrideSchItemColors() )
82 m_infoBar->ShowMessage( _( "Note: individual item colors overridden in Preferences." ) );
83
84 wxSize minSize = m_pageNumberTextCtrl->GetMinSize();
85 int minWidth = m_pageNumberTextCtrl->GetTextExtent( wxT( "XXX.XXX" ) ).GetWidth();
86
87 m_pageNumberTextCtrl->SetMinSize( wxSize( minWidth, minSize.GetHeight() ) );
88
89 wxToolTip::Enable( true );
91
92 // Configure button logos
97
98 // Set font sizes
100 m_hierarchicalPath->SetFont( KIUI::GetSmallInfoFont( this ) );
101
102 // wxFormBuilder doesn't include this event...
103 m_grid->Connect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( DIALOG_SHEET_PROPERTIES::OnGridCellChanging ),
104 nullptr, this );
105
107}
108
109
111{
112 // Prevents crash bug in wxGrid's d'tor
113 m_grid->DestroyTable( m_fields );
114
115 m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING, wxGridEventHandler( DIALOG_SHEET_PROPERTIES::OnGridCellChanging ),
116 nullptr, this );
117
118 // Delete the GRID_TRICKS.
119 m_grid->PopEventHandler( true );
120}
121
122
124{
125 if( !wxDialog::TransferDataToWindow() )
126 return false;
127
128 SCH_SHEET_PATH instance = m_frame->GetCurrentSheet();
129 wxString variantName = m_frame->Schematic().GetCurrentVariant();
130
131 // Push a copy of each field into m_updateFields
132 for( SCH_FIELD& field : m_sheet->GetFields() )
133 {
134 SCH_FIELD field_copy( field );
135
136#ifdef __WINDOWS__
137 // Filenames are stored using unix notation, so convert to Windows notation
138 if( field_copy.GetId() == FIELD_T::SHEET_FILENAME )
139 {
140 wxString filename = field_copy.GetText();
141 filename.Replace( wxT( "/" ), wxT( "\\" ) );
142 field_copy.SetText( filename );
143 }
144#endif
145
146 if( !field_copy.IsMandatory() )
147 field_copy.SetText( m_sheet->GetFieldText( field.GetName(), &instance, variantName ) );
148
149 // change offset to be symbol-relative
150 field_copy.Offset( -m_sheet->GetPosition() );
151
152 m_fields->push_back( field_copy );
153 }
154
155 // notify the grid
156 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->size() );
157 m_grid->ProcessTableMessage( msg );
158
159 // border width
160 m_borderWidth.SetValue( m_sheet->GetBorderWidth() );
161
162 // set up color swatches
163 KIGFX::COLOR4D borderColor = m_sheet->GetBorderColor();
164 KIGFX::COLOR4D backgroundColor = m_sheet->GetBackgroundColor();
165
166 m_borderSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
167 m_backgroundSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
168
169 m_borderSwatch->SetSwatchColor( borderColor, false );
170 m_backgroundSwatch->SetSwatchColor( backgroundColor, false );
171
172 KIGFX::COLOR4D canvas = m_frame->GetColorSettings()->GetColor( LAYER_SCHEMATIC_BACKGROUND );
173 m_borderSwatch->SetSwatchBackground( canvas );
174 m_backgroundSwatch->SetSwatchBackground( canvas );
175
176 m_cbExcludeFromSim->SetValue( m_sheet->GetExcludedFromSim( &instance, variantName ) );
177 m_cbExcludeFromBom->SetValue( m_sheet->GetExcludedFromBOM( &instance, variantName ) );
178 m_cbExcludeFromBoard->SetValue( m_sheet->GetExcludedFromBoard( &instance, variantName ) );
179 m_cbDNP->SetValue( m_sheet->GetDNP( &instance, variantName ) );
180
181 instance.push_back( m_sheet );
182 m_pageNumberTextCtrl->ChangeValue( instance.GetPageNumber() );
183
184 return true;
185}
186
187
189{
190 if( !m_grid->CommitPendingChanges() || !m_grid->Validate() )
191 return false;
192
193 // Check for missing field names.
194 for( size_t i = 0; i < m_fields->size(); ++i )
195 {
196 SCH_FIELD& field = m_fields->at( i );
197
198 if( field.IsMandatory() )
199 continue;
200
201 if( field.GetName( false ).empty() && !field.GetText().empty() )
202 {
203 DisplayErrorMessage( this, _( "Fields must have a name." ) );
204
206 m_delayedFocusRow = (int) i;
207
208 return false;
209 }
210 }
211
212 return true;
213}
214
215
216static bool positioningChanged( const SCH_FIELD& a, const SCH_FIELD& b )
217{
218 if( a.GetPosition() != b.GetPosition() )
219 return true;
220
221 if( a.GetHorizJustify() != b.GetHorizJustify() )
222 return true;
223
224 if( a.GetVertJustify() != b.GetVertJustify() )
225 return true;
226
227 if( a.GetTextAngle() != b.GetTextAngle() )
228 return true;
229
230 return false;
231}
232
233
235{
237 return true;
238
240 return true;
241
242 return false;
243}
244
245
247{
248 wxCHECK( m_sheet && m_frame, false );
249
250 if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
251 return false;
252
253 if( m_isUndoable )
254 *m_isUndoable = true;
255
256 // Sheet file names can be relative or absolute.
257 wxString sheetFileName = m_fields->GetField( FIELD_T::SHEET_FILENAME )->GetText();
258
259 // Ensure filepath is not empty. (In normal use will be caught by grid validators,
260 // but unedited data from existing files can be bad.)
261 if( sheetFileName.IsEmpty() )
262 {
263 DisplayError( this, _( "A sheet must have a valid file name." ) );
264 return false;
265 }
266
267 // Ensure the filename extension is OK. (In normal use will be caught by grid validators,
268 // but unedited data from existing files can be bad.)
269 sheetFileName = EnsureFileExtension( sheetFileName, FILEEXT::KiCadSchematicFileExtension );
270
271 // Ensure sheetFileName is legal
272 if( !IsFullFileNameValid( sheetFileName ) )
273 {
274 DisplayError( this, _( "A sheet must have a valid file name." ) );
275 return false;
276 }
277
278 wxFileName fn( sheetFileName );
279
280 wxString newRelativeFilename = fn.GetFullPath();
281
282 // Inside Eeschema, filenames are stored using unix notation
283 newRelativeFilename.Replace( wxT( "\\" ), wxT( "/" ) );
284
285 wxString oldFilename = m_sheet->GetField( FIELD_T::SHEET_FILENAME )->GetText();
286 oldFilename.Replace( wxT( "\\" ), wxT( "/" ) );
287
288 bool filename_changed = oldFilename != newRelativeFilename;
289
290 if( filename_changed || m_sheet->IsNew() )
291 {
292 SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
293
294 wxCHECK( currentScreen, false );
295
296 bool clearFileName = false;
297
298 // This can happen for the root sheet when opening Eeschema in the stand alone mode.
299 if( currentScreen->GetFileName().IsEmpty() )
300 {
301 clearFileName = true;
302 currentScreen->SetFileName( m_frame->Prj().AbsolutePath( wxT( "noname.kicad_sch" ) ) );
303 }
304
305 wxFileName tmp( fn );
306 wxFileName screenFileName = currentScreen->GetFileName();
307
308 if( fn.IsAbsolute() && fn.MakeRelativeTo( screenFileName.GetPath() ) )
309 {
310 KICAD_MESSAGE_DIALOG makeRelDlg( this, _( "Use relative path for sheet file?" ),
311 _( "Sheet File Path" ),
312 wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION | wxCENTER );
313
314 makeRelDlg.SetExtendedMessage( _( "Using relative hierarchical sheet file name paths improves "
315 "schematic portability across systems and platforms. Using "
316 "absolute paths can result in portability issues." ) );
317 makeRelDlg.SetYesNoLabels( KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Use Relative Path" ) ),
318 KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Use Absolute Path" ) ) );
319
320 if( makeRelDlg.ShowModal() == wxID_YES )
321 {
322 wxLogTrace( tracePathsAndFiles, "\n Converted absolute path: '%s'"
323 "\n to relative path: '%s'",
324 tmp.GetPath(),
325 fn.GetPath() );
326 m_fields->GetField( FIELD_T::SHEET_FILENAME )->SetText( fn.GetFullPath() );
327 newRelativeFilename = fn.GetFullPath();
328 }
329 }
330
331 if( !onSheetFilenameChanged( newRelativeFilename ) )
332 {
333 if( clearFileName )
334 currentScreen->SetFileName( wxEmptyString );
335 else
337
338 return false;
339 }
341 {
343 }
344
345 if( clearFileName )
346 currentScreen->SetFileName( wxEmptyString );
347
348 // One last validity check (and potential repair) just to be sure to be sure
349 SCH_SHEET_LIST repairedList;
350 repairedList.BuildSheetList( &m_frame->Schematic().Root(), true );
351 }
352
353 wxString newSheetname = m_fields->GetField( FIELD_T::SHEET_NAME )->GetText();
354
355 if( ( newSheetname != m_sheet->GetName() ) && m_updateHierarchyNavigator )
357
358 if( newSheetname.IsEmpty() )
359 newSheetname = _( "Untitled Sheet" );
360
361 m_fields->GetField( FIELD_T::SHEET_NAME )->SetText( newSheetname );
362
363 m_sheet->SetName( newSheetname );
364 m_sheet->SetFileName( newRelativeFilename );
365
366 // change all field positions from relative to absolute
367 for( SCH_FIELD& m_field : *m_fields)
368 m_field.Offset( m_sheet->GetPosition() );
369
371 m_sheet->SetFieldsAutoplaced( AUTOPLACE_NONE );
372
373 SCH_SHEET_PATH instance = m_frame->GetCurrentSheet();
374 wxString variantName = m_frame->Schematic().GetCurrentVariant();
375
376 for( int ii = m_fields->GetNumberRows() - 1; ii >= 0; ii-- )
377 {
378 SCH_FIELD& field = m_fields->at( ii );
379
380 if( field.IsMandatory() )
381 continue;
382
383 const wxString& fieldName = field.GetCanonicalName();
384
385 if( field.IsEmpty() )
386 m_fields->erase( m_fields->begin() + ii );
387 else if( fieldName.IsEmpty() )
388 field.SetName( _( "untitled" ) );
389
390 SCH_FIELD* existingField = m_sheet->GetField( fieldName );
391 SCH_FIELD* tmp;
392
393 if( !existingField )
394 {
395 m_sheet->AddOptionalField( field );
396 }
397 else
398 {
399 wxString defaultText = m_sheet->Schematic()->ConvertRefsToKIIDs( existingField->GetText() );
400 tmp = const_cast<SCH_FIELD*>( existingField );
401
402 *tmp = field;
403
404 if( !variantName.IsEmpty() )
405 {
406 // Restore the default field text for existing fields.
407 tmp->SetText( defaultText, &instance );
408
409 tmp->SetText( m_sheet->Schematic()->ConvertRefsToKIIDs( field.GetText() ),
410 &instance, variantName );
411 }
412 }
413 }
414
415 m_sheet->SetBorderWidth( m_borderWidth.GetIntValue() );
416
417 COLOR_SETTINGS* colorSettings = m_frame->GetColorSettings();
418
419 if( colorSettings->GetOverrideSchItemColors()
420 && ( m_sheet->GetBorderColor() != m_borderSwatch->GetSwatchColor() ||
421 m_sheet->GetBackgroundColor() != m_backgroundSwatch->GetSwatchColor() ) )
422 {
423 wxPanel temp( this );
424 temp.Hide();
425 PANEL_EESCHEMA_COLOR_SETTINGS prefs( &temp );
426 wxString checkboxLabel = prefs.m_optOverrideColors->GetLabel();
427
428 KIDIALOG dlg( this, _( "Note: item colors are overridden in the current color theme." ),
430 dlg.ShowDetailedText( wxString::Format( _( "To see individual item colors uncheck '%s'\n"
431 "in Preferences > Schematic Editor > Colors." ),
432 checkboxLabel ) );
433 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
434 dlg.ShowModal();
435 }
436
437 m_sheet->SetBorderColor( m_borderSwatch->GetSwatchColor() );
438 m_sheet->SetBackgroundColor( m_backgroundSwatch->GetSwatchColor() );
439
440 m_sheet->SetExcludedFromSim( m_cbExcludeFromSim->GetValue(), &instance, variantName );
441 m_sheet->SetExcludedFromBOM( m_cbExcludeFromBom->GetValue(), &instance, variantName );
442 m_sheet->SetExcludedFromBoard( m_cbExcludeFromBoard->GetValue() );
443 m_sheet->SetDNP( m_cbDNP->GetValue(), &instance, variantName );
444
445 instance.push_back( m_sheet );
446
447 instance.SetPageNumber( m_pageNumberTextCtrl->GetValue() );
448
449 m_frame->TestDanglingEnds();
450
451 // Refresh all sheets in case ordering changed.
452 for( SCH_ITEM* item : m_frame->GetScreen()->Items().OfType( SCH_SHEET_T ) )
453 m_frame->UpdateItem( item );
454
455 return true;
456}
457
458
459bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilename )
460{
461 wxString msg;
462 wxFileName sheetFileName( EnsureFileExtension( aNewFilename, FILEEXT::KiCadSchematicFileExtension ) );
463
464 // Sheet file names are relative to the path of the current sheet. This allows for
465 // nesting of schematic files in subfolders. Screen file names are always absolute.
466 SCHEMATIC& schematic = m_frame->Schematic();
467 SCH_SHEET_LIST fullHierarchy = schematic.Hierarchy();
468 wxFileName screenFileName( sheetFileName );
469 wxFileName tmp( sheetFileName );
470 SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
471
472 wxCHECK( currentScreen, false );
473
474 // SCH_SCREEN file names are always absolute.
475 wxFileName currentScreenFileName = currentScreen->GetFileName();
476
477 if( !screenFileName.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS, currentScreenFileName.GetPath() ) )
478 {
479 msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
480 "'%s'\n"
481 "against parent sheet schematic file path:\n"
482 "'%s'." ),
483 sheetFileName.GetPath(),
484 currentScreenFileName.GetPath() );
485 DisplayError( this, msg );
486 return false;
487 }
488
489 wxString newAbsoluteFilename = screenFileName.GetFullPath();
490
491 // Inside Eeschema, filenames are stored using unix notation
492 newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
493
494 bool renameFile = false;
495 bool loadFromFile = false;
496 bool clearAnnotation = false;
497 bool isExistingSheet = false;
498 SCH_SCREEN* useScreen = nullptr;
499 SCH_SCREEN* oldScreen = nullptr;
500
501 // Search for a schematic file having the same filename already in use in the hierarchy
502 // or on disk, in order to reuse it.
503 if( !schematic.Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
504 {
505 loadFromFile = wxFileExists( newAbsoluteFilename );
506
507 wxLogTrace( tracePathsAndFiles, "\n Sheet requested file '%s', %s",
508 newAbsoluteFilename,
509 loadFromFile ? "found" : "not found" );
510 }
511
512 if( m_sheet->GetScreen() == nullptr ) // New just created sheet.
513 {
514 if( !m_frame->AllowCaseSensitiveFileNameClashes( m_sheet->GetFileName(), newAbsoluteFilename ) )
515 return false;
516
517 if( useScreen || loadFromFile ) // Load from existing file.
518 {
519 clearAnnotation = true;
520
521 if( !IsOK( this, wxString::Format( _( "'%s' already exists." ), sheetFileName.GetFullName() )
522 + wxT( "\n\n" )
523 + wxString::Format( _( "Link '%s' to this file?" ), newAbsoluteFilename ) ) )
524 {
525 return false;
526 }
527 }
528 // If we are drawing a sheet from a design block/sheet import, we need to copy the
529 // sheet to the current directory.
530 else if( m_sourceSheetFilename && !m_sourceSheetFilename->IsEmpty() )
531 {
532 loadFromFile = true;
533
534 if( !wxCopyFile( *m_sourceSheetFilename, newAbsoluteFilename, false ) )
535 {
536 msg.Printf( _( "Failed to copy schematic file '%s' to destination '%s'." ),
537 currentScreenFileName.GetFullPath(),
538 newAbsoluteFilename );
539
540 DisplayError( m_frame, msg );
541
542 return false;
543 }
544 }
545 else // New file.
546 {
547 m_frame->InitSheet( m_sheet, newAbsoluteFilename );
548 }
549 }
550 else // Existing sheet.
551 {
552 isExistingSheet = true;
553
554 if( !m_frame->AllowCaseSensitiveFileNameClashes( m_sheet->GetFileName(), newAbsoluteFilename ) )
555 return false;
556
557 // We are always using here a case insensitive comparison to avoid issues
558 // under Windows, although under Unix filenames are case sensitive.
559 // But many users create schematic under both Unix and Windows
560 // **
561 // N.B. 1: aSheet->GetFileName() will return a relative path
562 // aSheet->GetScreen()->GetFileName() returns a full path
563 //
564 // N.B. 2: newFilename uses the unix notation for separator.
565 // so we must use it also to compare the old and new filenames
566 wxString oldAbsoluteFilename = m_sheet->GetScreen()->GetFileName();
567 oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
568
569 if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
570 {
571 // Sheet file name changes cannot be undone.
572 if( m_isUndoable )
573 *m_isUndoable = false;
574
575 if( useScreen || loadFromFile ) // Load from existing file.
576 {
577 clearAnnotation = true;
578 oldScreen = m_sheet->GetScreen();
579
580 if( !IsOK( this, wxString::Format( _( "Change '%s' link from '%s' to '%s'?" ),
581 newAbsoluteFilename,
582 m_sheet->GetFileName(),
583 sheetFileName.GetFullName() )
584 + wxT( "\n\n" )
585 + _( "This action cannot be undone." ) ) )
586 {
587 return false;
588 }
589
590 if( loadFromFile )
591 m_sheet->SetScreen( nullptr );
592 }
593 else // Save to new file name.
594 {
595 if( m_sheet->GetScreenCount() > 1 )
596 {
597 if( !IsOK( this, wxString::Format( _( "Create new file '%s' with contents of '%s'?" ),
598 sheetFileName.GetFullName(),
599 m_sheet->GetFileName() )
600 + wxT( "\n\n" )
601 + _( "This action cannot be undone." ) ) )
602 {
603 return false;
604 }
605 }
606
607 renameFile = true;
608 }
609 }
610
611 if( renameFile )
612 {
613 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
614
615 // If the associated screen is shared by more than one sheet, do not
616 // change the filename of the corresponding screen here.
617 // (a new screen will be created later)
618 // if it is not shared, update the filename
619 if( m_sheet->GetScreenCount() <= 1 )
620 m_sheet->GetScreen()->SetFileName( newAbsoluteFilename );
621
622 try
623 {
624 pi->SaveSchematicFile( newAbsoluteFilename, m_sheet, &schematic );
625 }
626 catch( const IO_ERROR& ioe )
627 {
628 msg = wxString::Format( _( "Error occurred saving schematic file '%s'." ), newAbsoluteFilename );
629 DisplayErrorMessage( this, msg, ioe.What() );
630
631 msg = wxString::Format( _( "Failed to save schematic '%s'" ), newAbsoluteFilename );
632 m_frame->SetMsgPanel( wxEmptyString, msg );
633 return false;
634 }
635
636 // If the associated screen is shared by more than one sheet, remove the
637 // screen and reload the file to a new screen. Failure to do this will trash
638 // the screen reference counting in complex hierarchies.
639 if( m_sheet->GetScreenCount() > 1 )
640 {
641 oldScreen = m_sheet->GetScreen();
642 m_sheet->SetScreen( nullptr );
643 loadFromFile = true;
644 }
645 }
646 }
647
648 SCH_SHEET_PATH& currentSheet = m_frame->GetCurrentSheet();
649
650 if( useScreen )
651 {
652 // Create a temporary sheet for recursion testing to prevent a possible recursion error.
653 std::unique_ptr< SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &schematic );
654
655 if( SCH_FIELD* srcField = m_fields->GetField( FIELD_T::SHEET_NAME ) )
656 *tmpSheet->GetField( FIELD_T::SHEET_NAME ) = *srcField;
657
658 tmpSheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( sheetFileName.GetFullPath() );
659 tmpSheet->SetScreen( useScreen );
660
661 // No need to check for valid library IDs if we are using an existing screen.
662 if( m_frame->CheckSheetForRecursion( tmpSheet.get(), &currentSheet ) )
663 return false;
664
665 // It's safe to set the sheet screen now.
666 m_sheet->SetScreen( useScreen );
667
668 SCH_SHEET_LIST sheetHierarchy( m_sheet ); // The hierarchy of the loaded file.
669
670 sheetHierarchy.AddNewSymbolInstances( currentSheet, m_frame->Prj().GetProjectName() );
671 sheetHierarchy.AddNewSheetInstances( currentSheet, fullHierarchy.GetLastVirtualPageNumber() );
672 }
673 else if( loadFromFile )
674 {
675 bool restoreSheet = false;
676
677 if( isExistingSheet )
678 {
679 // Temporarily remove the sheet from the current schematic page so that recursion
680 // and symbol library link tests can be performed with the modified sheet settings.
681 restoreSheet = true;
682 currentSheet.LastScreen()->Remove( m_sheet );
683 }
684
685 if( !m_frame->LoadSheetFromFile( m_sheet, &currentSheet, newAbsoluteFilename, false, true )
686 || m_frame->CheckSheetForRecursion( m_sheet, &currentSheet ) )
687 {
688 if( restoreSheet )
689 {
690 // If we cleared the previous screen, restore it before returning to the user
691 if( oldScreen )
692 m_sheet->SetScreen( oldScreen );
693
694 currentSheet.LastScreen()->Append( m_sheet );
695 }
696
697 return false;
698 }
699
700 if( restoreSheet )
701 currentSheet.LastScreen()->Append( m_sheet );
702 }
703
705 *m_clearAnnotationNewItems = clearAnnotation;
706
707 // Rebuild the entire connection graph.
708 m_frame->RecalculateConnections( nullptr, GLOBAL_CLEANUP );
709
710 return true;
711}
712
713
715{
716 bool success = true;
717 wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
718 wxControl* control = editor->GetControl();
719
720 if( control && control->GetValidator() )
721 success = control->GetValidator()->Validate( control );
722
723 if( !success )
724 {
725 event.Veto();
726 m_delayedFocusRow = event.GetRow();
727 m_delayedFocusColumn = event.GetCol();
728 }
729 else if( event.GetCol() == FDC_NAME )
730 {
731 wxString newName = event.GetString();
732
733 for( int i = 0; i < m_grid->GetNumberRows(); ++i )
734 {
735 if( i == event.GetRow() )
736 continue;
737
738 if( newName.CmpNoCase( m_grid->GetCellValue( i, FDC_NAME ) ) == 0 )
739 {
740 DisplayError( this, wxString::Format( _( "Field name '%s' already in use." ),
741 newName ) );
742 event.Veto();
743 m_delayedFocusRow = event.GetRow();
744 m_delayedFocusColumn = event.GetCol();
745 break;
746 }
747 }
748 }
749
750 editor->DecRef();
751}
752
753
754void DIALOG_SHEET_PROPERTIES::OnAddField( wxCommandEvent& event )
755{
756 m_grid->OnAddRow(
757 [&]() -> std::pair<int, int>
758 {
760
761 newField.SetTextAngle( m_fields->GetField( FIELD_T::SHEET_NAME )->GetTextAngle() );
762 newField.SetVisible( false );
763 m_fields->push_back( newField );
764
765 // notify the grid
766 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
767 m_grid->ProcessTableMessage( msg );
768 return { m_fields->size() - 1, FDC_NAME };
769 } );
770}
771
772
773void DIALOG_SHEET_PROPERTIES::OnDeleteField( wxCommandEvent& event )
774{
775 m_grid->OnDeleteRows(
776 [&]( int row )
777 {
778 if( row < m_fields->GetMandatoryRowCount() )
779 {
780 DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
781 m_fields->GetMandatoryRowCount() ) );
782 return false;
783 }
784
785 return true;
786 },
787 [&]( int row )
788 {
789 m_fields->erase( m_fields->begin() + row );
790
791 // notify the grid
792 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
793 m_grid->ProcessTableMessage( msg );
794 } );
795}
796
797
798void DIALOG_SHEET_PROPERTIES::OnMoveUp( wxCommandEvent& event )
799{
800 m_grid->OnMoveRowUp(
801 [&]( int row )
802 {
803 return row > m_fields->GetMandatoryRowCount();
804 },
805 [&]( int row )
806 {
807 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row - 1 ) );
808 m_grid->ForceRefresh();
809 } );
810}
811
812
813void DIALOG_SHEET_PROPERTIES::OnMoveDown( wxCommandEvent& event )
814{
815 m_grid->OnMoveRowUp(
816 [&]( int row )
817 {
818 return row >= m_fields->GetMandatoryRowCount();
819 },
820 [&]( int row )
821 {
822 std::swap( *( m_fields->begin() + row ), *( m_fields->begin() + row + 1 ) );
823 m_grid->ForceRefresh();
824 } );
825}
826
827
828void DIALOG_SHEET_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
829{
830 std::bitset<64> shownColumns = m_grid->GetShownColumns();
831
832 if( shownColumns != m_shownColumns )
833 {
834 m_shownColumns = shownColumns;
835
836 if( !m_grid->IsCellEditControlShown() )
837 m_grid->SetGridWidthsDirty();
838 }
839
840 // Propagate changes in sheetname to displayed hierarchical path
841 int sheetnameRow = m_fields->GetFieldRow( FIELD_T::SHEET_NAME );
842 wxString path = m_frame->GetCurrentSheet().PathHumanReadable( false );
843
844 if( path.Last() != '/' )
845 path.Append( '/' );
846
847 wxGridCellEditor* editor = m_grid->GetCellEditor( sheetnameRow, FDC_VALUE );
848 wxControl* control = editor->GetControl();
849 wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
850 wxString sheetName;
851
852 if( textControl )
853 sheetName = textControl->GetValue();
854 else
855 sheetName = m_grid->GetCellValue( sheetnameRow, FDC_VALUE );
856
857 m_dummySheet.SetFields( *m_fields );
858 m_dummySheetNameField.SetText( sheetName );
859 path += m_dummySheetNameField.GetShownText( false );
860
861 editor->DecRef();
862
863 wxClientDC dc( m_hierarchicalPathLabel );
864 int width = m_sizerBottom->GetSize().x - m_stdDialogButtonSizer->GetSize().x
865 - m_hierarchicalPathLabel->GetSize().x
866 - 30;
867
868 path = wxControl::Ellipsize( path, dc, wxELLIPSIZE_START, width, wxELLIPSIZE_FLAGS_NONE );
869
870 if( m_hierarchicalPath->GetLabel() != path )
871 m_hierarchicalPath->SetLabel( path );
872
873 // Handle a delayed focus
874 if( m_delayedFocusRow >= 0 )
875 {
876 m_grid->SetFocus();
877 m_grid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
879
880 m_grid->EnableCellEditControl( true );
881 m_grid->ShowCellEditControl();
882
885 }
886}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:402
Color settings are a bit different than most of the settings objects in that there can be more than o...
bool GetOverrideSchItemColors() const
wxStdDialogButtonSizer * m_stdDialogButtonSizer
DIALOG_SHEET_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Sheet Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxCAPTION|wxCLOSE_BOX|wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU)
void OnAddField(wxCommandEvent &event) override
void OnMoveDown(wxCommandEvent &event) override
void OnGridCellChanging(wxGridEvent &event)
void OnDeleteField(wxCommandEvent &event) override
bool onSheetFilenameChanged(const wxString &aNewFilename)
void OnUpdateUI(wxUpdateUIEvent &event) override
void OnMoveUp(wxCommandEvent &event) override
DIALOG_SHEET_PROPERTIES(SCH_EDIT_FRAME *aParent, SCH_SHEET *aSheet, bool *aIsUndoable, bool *aClearAnnotationNewItems, bool *aUpdateHierarchyNavigator, wxString *aSourceSheetFilename)
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:147
void Offset(const VECTOR2I &aOffset)
Definition eda_text.cpp:606
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:200
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:398
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:203
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:311
SCH_FIELD * GetField(FIELD_T aFieldId)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
@ KD_WARNING
Definition kidialog.h:47
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
Holds all the data relating to one schematic.
Definition schematic.h:88
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
SCH_SHEET & Root() const
Definition schematic.h:132
Schematic editor (Eeschema) main window.
SCHEMATIC & Schematic() const
bool IsMandatory() const
VECTOR2I GetPosition() const override
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:116
FIELD_T GetId() const
Definition sch_field.h:120
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
bool IsEmpty()
Return true if both the name and value of the field are empty.
Definition sch_field.h:159
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetName(const wxString &aName)
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
const wxString & GetFileName() const
Definition sch_screen.h:153
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void AddNewSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath, const wxString &aProjectName)
Attempt to add new symbol instances for all symbols in this list of sheet paths prefixed with aPrefix...
int GetLastVirtualPageNumber() const
void AddNewSheetInstances(const SCH_SHEET_PATH &aPrefixSheetPath, int aLastVirtualPageNumber)
void BuildSheetList(SCH_SHEET *aSheet, bool aCheckIntegrity)
Build the list of sheets and their sheet path from aSheet.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
wxString GetPageNumber() const
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
Definition common.cpp:629
The common library.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:259
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:52
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
@ FDC_NAME
@ FDC_VALUE
static const std::string KiCadSchematicFileExtension
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
@ LAYER_SCHEMATIC_BACKGROUND
Definition layer_ids.h:488
KICOMMON_API wxFont GetSmallInfoFont(wxWindow *aWindow)
const SCH_FIELD * FindField(const std::vector< SCH_FIELD > &aFields, FIELD_T aFieldId)
Definition sch_field.h:365
@ AUTOPLACE_NONE
Definition sch_item.h:69
@ GLOBAL_CLEANUP
Definition schematic.h:77
bool IsFullFileNameValid(const wxString &aFullFilename)
Checks if a full filename is valid, i.e.
wxString GetUserFieldName(int aFieldNdx, bool aTranslateForHI)
#define DO_TRANSLATE
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
std::string path
wxLogTrace helper definitions.
@ SCH_SHEET_T
Definition typeinfo.h:179
Custom text control validator definitions.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:39