KiCad PCB EDA Suite
Loading...
Searching...
No Matches
panel_jobset.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) 2024 Mark Roszko <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "panel_jobset.h"
24#include <wx/aui/auibook.h>
25#include <jobs/jobset.h>
26#include <jobs/job_registry.h>
27#include <eda_list_dialog.h>
28#include <wx/checkbox.h>
29#include <wx/menu.h>
30#include <bitmaps.h>
31#include <i18n_utility.h>
32#include <jobs_runner.h>
34#include <kicad_manager_frame.h>
35#include <vector>
36
39#include <widgets/wx_grid.h>
41#include <kiplatform/ui.h>
42#include <confirm.h>
43
47
48
49extern KICOMMON_API std::map<JOBSET_OUTPUT_TYPE, JOBSET_OUTPUT_TYPE_INFO> JobsetOutputTypeInfos;
50
51
53{
54public:
55 DIALOG_OUTPUT_RUN_RESULTS( wxWindow* aParent, JOBSET* aJobsFile, JOBSET_OUTPUT* aOutput ) :
57 m_jobsFile( aJobsFile ),
58 m_output( aOutput )
59 {
60 m_staticTextOutputName->SetLabel( wxString::Format( _( "Output: %s" ),
61 aOutput->GetDescription() ) );
62
63 int jobBmpColId = m_jobList->AppendColumn( wxT( "" ) );
64 int jobNoColId = m_jobList->AppendColumn( _( "No." ) );
65 int jobDescColId = m_jobList->AppendColumn( _( "Job Description" ) );
66 int jobSourceColId = m_jobList->AppendColumn( wxT( "Source" ) );
67 m_jobList->SetColumnWidth( jobBmpColId, wxLIST_AUTOSIZE_USEHEADER );
68 m_jobList->SetColumnWidth( jobNoColId, wxLIST_AUTOSIZE_USEHEADER );
69 m_jobList->SetColumnWidth( jobDescColId, wxLIST_AUTOSIZE_USEHEADER );
70
71 wxImageList* imageList = new wxImageList( 16, 16, true, 3 );
72 imageList->Add( KiBitmapBundle( BITMAPS::ercerr ).GetBitmap( wxSize( 16, 16 ) ) );
73 imageList->Add( KiBitmapBundle( BITMAPS::checked_ok ).GetBitmap( wxSize( 16, 16 ) ) );
74 m_jobList->SetImageList( imageList, wxIMAGE_LIST_SMALL );
75
76 int num = 1;
77 for( auto& job : aJobsFile->GetJobsForOutput( aOutput ) )
78 {
79 int imageIdx = -1;
80 if( aOutput->m_lastRunSuccessMap.contains( job.m_id ) )
81 {
82 if( aOutput->m_lastRunSuccessMap[job.m_id].value() )
83 imageIdx = 1;
84 else
85 imageIdx = 0;
86 }
87
88 long itemIndex = m_jobList->InsertItem( m_jobList->GetItemCount(), imageIdx );
89
90 m_jobList->SetItem( itemIndex, jobNoColId, wxString::Format( "%d", num++ ) );
91 m_jobList->SetItem( itemIndex, jobDescColId, job.GetDescription() );
92
93 KIWAY::FACE_T iface = JOB_REGISTRY::GetKifaceType( job.m_type );
94 wxString source = wxEmptyString;
95 if( iface < KIWAY::KIWAY_FACE_COUNT )
96 {
97
98 if( iface == KIWAY::FACE_PCB )
99 {
100 source = wxT( "PCB" );
101 }
102 else if( iface == KIWAY::FACE_SCH )
103 {
104 source = wxT( "SCH" );
105 }
106 }
107 m_jobList->SetItem( itemIndex, jobSourceColId, source );
108 }
109
110 SetupStandardButtons( { { wxID_OK, _( "Close" ) } } );
112 }
113
114 void onJobListSize( wxSizeEvent& event ) override
115 {
116 int width = m_jobList->GetSize().x;
117 width -= m_jobList->GetColumnWidth( 0 );
118 width -= m_jobList->GetColumnWidth( 1 );
119
120 m_jobList->SetColumnWidth( 2, width );
121 }
122
123 void OnJobListItemSelected( wxListEvent& event ) override
124 {
125 int itemIndex = event.GetIndex();
126
127 // The index could be negative (it is default -1)
128 if( itemIndex < 0 )
129 return;
130
131 std::vector<JOBSET_JOB> jobs = m_jobsFile->GetJobsForOutput( m_output );
132
133 if( static_cast<size_t>( itemIndex ) < jobs.size() )
134 {
135 JOBSET_JOB& job = jobs[itemIndex];
136
137 if( m_output->m_lastRunReporters.contains( job.m_id ) )
138 {
139 WX_STRING_REPORTER* reporter =
140 static_cast<WX_STRING_REPORTER*>( m_output->m_lastRunReporters[job.m_id] );
141
142 if( reporter )
143 m_textCtrlOutput->SetValue( reporter->GetMessages() );
144 }
145 else
146 {
147 m_textCtrlOutput->SetValue( _( "No output messages" ) );
148 }
149 }
150 }
151
152private:
155};
156
157
159{
160public:
161 PANEL_JOBSET_OUTPUT( wxWindow* aParent, PANEL_JOBSET* aPanelParent, KICAD_MANAGER_FRAME* aFrame,
162 JOBSET* aFile, JOBSET_OUTPUT* aOutput ) :
163 PANEL_JOBSET_OUTPUT_BASE( aParent ),
164 m_jobsFile( aFile ),
165 m_outputId( aOutput->m_id ),
166 m_frame( aFrame ),
167 m_panelParent( aPanelParent )
168 {
169 m_buttonProperties->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
170 m_buttonDelete->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
171
172#if _WIN32
173 // BORDER_RAISED/SUNKEN look pretty on every platform but Windows
174 long style = GetWindowStyleFlag();
175 style &= ~wxBORDER_MASK;
176 style |= wxBORDER_SIMPLE;
177 SetWindowStyleFlag( style );
178#endif // _WIN32
179
180 Connect( wxEVT_MENU, wxCommandEventHandler( PANEL_JOBSET_OUTPUT::onMenu ), nullptr, this );
181
182 if( JobsetOutputTypeInfos.contains( aOutput->m_type ) )
183 {
185 m_textOutputType->SetLabel( aOutput->GetDescription() );
186 m_bitmapOutputType->SetBitmap( KiBitmapBundle( jobTypeInfo.bitmap ) );
187 }
188
189 UpdateStatus();
190 }
191
192
194 {
195 Disconnect( wxEVT_MENU, wxCommandEventHandler( PANEL_JOBSET_OUTPUT::onMenu ), nullptr, this );
196 }
197
199 {
200 JOBSET_OUTPUT* output = GetOutput();
201 wxCHECK( output, /*void*/ );
202
203 output->m_lastRunSuccess = std::nullopt;
204 m_statusBitmap->SetBitmap( wxNullBitmap );
205 }
206
208 {
209 JOBSET_OUTPUT* output = GetOutput();
210 wxCHECK( output, /*void*/ );
211
212 if( output->m_lastRunSuccess.has_value() )
213 {
214 if( output->m_lastRunSuccess.value() )
215 {
216 m_statusBitmap->SetBitmap( KiBitmapBundle( BITMAPS::checked_ok ) );
217 m_statusBitmap->Show();
218 m_statusBitmap->SetToolTip( _( "Last run successful" ) );
219 }
220 else
221 {
222 m_statusBitmap->SetBitmap( KiBitmapBundle( BITMAPS::ercerr ) );
223 m_statusBitmap->Show();
224 m_statusBitmap->SetToolTip( _( "Last run failed" ) );
225 }
226 }
227 else
228 {
229 m_statusBitmap->SetBitmap( wxNullBitmap );
230 }
231
232 m_buttonGenerate->Enable( !m_jobsFile->GetJobsForOutput( output ).empty() );
233 }
234
235 virtual void OnGenerate( wxCommandEvent& event ) override
236 {
237 ClearStatus();
238 Refresh();
239
240 CallAfter(
241 [this]()
242 {
245
246 wxFileName fn = project.GetProjectFullName();
247 wxSetWorkingDirectory( fn.GetPath() );
248
249 JOBS_RUNNER jobRunner( &( m_frame->Kiway() ), m_jobsFile, &project );
250
251 WX_PROGRESS_REPORTER* progressReporter =
252 new WX_PROGRESS_REPORTER( m_frame, _( "Running jobs" ), 1 );
253
254 if( JOBSET_OUTPUT* output = GetOutput() )
255 jobRunner.RunJobsForOutput( output );
256
257 UpdateStatus();
258
259 delete progressReporter;
260
261 // Bring the Kicad manager frame back to the front
262 m_frame->Raise();
263 } );
264 }
265
266 virtual void OnLastStatusClick( wxMouseEvent& aEvent ) override
267 {
268 JOBSET_OUTPUT* output = GetOutput();
269 wxCHECK( output, /*void*/ );
270
272 dialog.ShowModal();
273 }
274
275 void OnRightDown( wxMouseEvent& aEvent ) override
276 {
277 JOBSET_OUTPUT* output = GetOutput();
278 wxCHECK( output, /*void*/ );
279
280 wxMenu menu;
281 menu.Append( wxID_EDIT, _( "Edit Output Options..." ) );
282 menu.Append( wxID_DELETE, _( "Delete Output" ) );
283
284 menu.AppendSeparator();
285 menu.Append( wxID_VIEW_DETAILS, _( "View Last Run Results..." ) );
286
287 menu.Enable( wxID_VIEW_DETAILS, output->m_lastRunSuccess.has_value() );
288
289 PopupMenu( &menu );
290 }
291
292 void OnProperties( wxCommandEvent& aEvent ) override
293 {
294 JOBSET_OUTPUT* output = GetOutput();
295 wxCHECK( output, /*void*/ );
296
298
299 if( dialog.ShowModal() == wxID_OK )
300 {
301 m_textOutputType->SetLabel( output->GetDescription() );
304 }
305 }
306
307 virtual void OnDelete( wxCommandEvent& aEvent ) override
308 {
310 }
311
313 {
315 {
316 if( jobset.m_id == m_outputId )
317 return &jobset;
318 }
319
320 return nullptr;
321 }
322
323private:
324 void onMenu( wxCommandEvent& aEvent )
325 {
326 switch( aEvent.GetId() )
327 {
328 case wxID_EDIT:
329 {
330 wxCommandEvent dummy;
332 }
333 break;
334
335 case wxID_DELETE:
336 {
337 wxCommandEvent dummy;
338 OnDelete( dummy );
339 }
340 break;
341
342 case wxID_VIEW_DETAILS:
343 {
344 wxMouseEvent dummy;
346 }
347 break;
348
349 default:
350 wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
351 }
352 }
353
354private:
356 wxString m_outputId;
359};
360
361
363 GRID_TRICKS( aGrid ),
364 m_parent( aParent )
365{
368}
369
370
371void JOBS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
372{
373 wxArrayInt selectedRows = m_grid->GetSelectedRows();
374
375 menu.Append( JOB_DESCRIPTION, _( "Edit Job Description" ) );
376 menu.Append( JOB_PROPERTIES, _( "Edit Job Settings..." ) );
377 menu.AppendSeparator();
378 menu.Append( GRIDTRICKS_ID_COPY, _( "Copy" ) + "\tCtrl+C",
379 _( "Copy selected cells to clipboard" ) );
380 menu.Append( GRIDTRICKS_ID_DELETE, _( "Delete" ) + "\tDel",
381 _( "Delete selected jobs" ) );
382 menu.Append( GRIDTRICKS_ID_SELECT, _( "Select All" ) + "\tCtrl+A",
383 _( "Select all jobs" ) );
384
385 menu.Enable( JOB_DESCRIPTION, selectedRows.size() == 1 );
386 menu.Enable( JOB_PROPERTIES, selectedRows.size() == 1 );
387 menu.Enable( GRIDTRICKS_ID_DELETE, selectedRows.size() > 0 );
388
389 m_grid->PopupMenu( &menu );
390}
391
392
393void JOBS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
394{
395 wxArrayInt selectedRows = m_grid->GetSelectedRows();
396
397 if( event.GetId() == JOB_DESCRIPTION )
398 {
399 if( selectedRows.size() > 0 )
400 {
401 m_grid->SetGridCursor( selectedRows[0], 2 );
402 m_grid->EnableCellEditControl();
403 }
404 }
405 else if( event.GetId() == JOB_PROPERTIES )
406 {
407 if( selectedRows.size() > 0 )
408 m_parent->OpenJobOptionsForListItem( selectedRows[0] );
409 }
410 else if( event.GetId() == GRIDTRICKS_ID_DELETE )
411 {
412 wxCommandEvent dummy;
414 }
415 else
416 {
418 }
419}
420
421
422bool JOBS_GRID_TRICKS::handleDoubleClick( wxGridEvent& aEvent )
423{
425
426 int curr_col = aEvent.GetCol();
427 int curr_row = aEvent.GetRow();
428
429 if( ( curr_col == 0 || curr_col == 1 || curr_col == 2 )
430 && curr_row >= 0 && curr_row < (int) m_parent->GetJobsFile()->GetJobs().size() )
431 {
432 m_doubleClickRow = curr_row;
434
435 CallAfter(
436 [this]()
437 {
438 // Yes, again. CancelShowEditorOnMouseUp() doesn't appear to be 100%
439 // reliable.
441 int row = m_doubleClickRow;
442 m_doubleClickRow = -1;
443
444 if( row >= 0 && row < (int) m_parent->GetJobsFile()->GetJobs().size() )
446 } );
447
448 return true;
449 }
450
451 return false;
452}
453
454
455PANEL_JOBSET::PANEL_JOBSET( wxAuiNotebook* aParent, KICAD_MANAGER_FRAME* aFrame,
456 std::unique_ptr<JOBSET> aJobsFile ) :
457 PANEL_JOBSET_BASE( aParent ),
458 m_parentBook( aParent ),
459 m_frame( aFrame ),
460 m_jobsFile( std::move( aJobsFile ) )
461{
462 m_jobsGrid->PushEventHandler( new JOBS_GRID_TRICKS( this, m_jobsGrid ) );
463
464 m_jobsGrid->SetDefaultRowSize( m_jobsGrid->GetDefaultRowSize() + 4 );
465 m_jobsGrid->OverrideMinSize( 0.6, 0.3 );
466 m_jobsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
467
468 // 'm' for margins
469 m_jobsGrid->SetColSize( 0, GetTextExtent( wxT( "99m" ) ).x );
470 m_jobsGrid->SetColSize( 1, GetTextExtent( wxT( "PCBm" ) ).x );
471
472 m_buttonAddJob->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
473 m_buttonUp->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
474 m_buttonDown->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
475 m_buttonDelete->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
476 m_buttonOutputAdd->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
477
480
481 m_buttonRunAllOutputs->Enable( !m_jobsFile->GetOutputs().empty()
482 && !m_jobsFile->GetJobs().empty() );
483}
484
485
487{
488 // Delete the GRID_TRICKS.
489 m_jobsGrid->PopEventHandler( true );
490}
491
492
494{
495 JOBSET_OUTPUT* output = aPanel->GetOutput();
496
497 m_outputListSizer->Detach( aPanel );
498 aPanel->Destroy();
499
500 // ensure the window contents get shifted as needed
501 m_outputList->Layout();
502 Layout();
503
504 m_jobsFile->RemoveOutput( output );
505
506 m_buttonRunAllOutputs->Enable( !m_jobsFile->GetOutputs().empty() );
507}
508
509
511{
512 if( m_jobsGrid->GetNumberRows() )
513 m_jobsGrid->DeleteRows( 0, m_jobsGrid->GetNumberRows() );
514
515 m_jobsGrid->AppendRows( m_jobsFile->GetJobs().size() );
516
517 int num = 1;
518
519 for( JOBSET_JOB& job : m_jobsFile->GetJobs() )
520 {
521 m_jobsGrid->SetCellValue( num - 1, 0, wxString::Format( "%d", num ) );
522 m_jobsGrid->SetReadOnly( num - 1, 0 );
523
524 m_jobsGrid->SetCellValue( num - 1, 2, job.GetDescription() );
525
526 m_jobsGrid->SetReadOnly( num - 1, 1 );
527
528 KIWAY::FACE_T iface = JOB_REGISTRY::GetKifaceType( job.m_type );
529 wxString source = wxEmptyString;
530 if( iface < KIWAY::KIWAY_FACE_COUNT )
531 {
532 if( iface == KIWAY::FACE_PCB )
533 {
534 source = wxT( "PCB" );
535 }
536 else if( iface == KIWAY::FACE_SCH )
537 {
538 source = wxT( "SCH" );
539 }
540 }
541
542 m_jobsGrid->SetCellValue( num - 1, 1, source );
543
544 num++;
545 }
546
547 UpdateTitle();
548
549 // Ensure the outputs get their Run-ability status updated
550 for( PANEL_JOBSET_OUTPUT* panel : GetOutputPanels() )
551 panel->UpdateStatus();
552}
553
554
556{
557 wxString tabName = m_jobsFile->GetFullName();
558
559 if( m_jobsFile->GetDirty() )
560 tabName = wxS( "*" ) + tabName;
561
562 int pageIdx = m_parentBook->FindPage( this );
563 m_parentBook->SetPageText( pageIdx, tabName );
564}
565
566
568{
570 m_jobsFile.get(), aOutput );
571
572#if __OSX__
573 m_outputListSizer->Add( outputPanel, 0, wxEXPAND, 5 );
574#else
575 m_outputListSizer->Add( outputPanel, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5 );
576#endif
577
578 m_outputList->Layout();
579}
580
581
582std::vector<PANEL_JOBSET_OUTPUT*> PANEL_JOBSET::GetOutputPanels()
583{
584 std::vector<PANEL_JOBSET_OUTPUT*> panels;
585
586 for( const wxSizerItem* item : m_outputListSizer->GetChildren() )
587 {
588 if( PANEL_JOBSET_OUTPUT* panel = dynamic_cast<PANEL_JOBSET_OUTPUT*>( item->GetWindow() ) )
589 panels.push_back( panel );
590 }
591
592 return panels;
593}
594
595
597{
598 Freeze();
599
600 for( JOBSET_OUTPUT& job : m_jobsFile->GetOutputs() )
601 addJobOutputPanel( &job );
602
603 // ensure the window contents get shifted as needed
604 Layout();
605 Thaw();
606}
607
608
610{
611 bool success = false;
612 JOBSET_JOB& job = m_jobsFile->GetJobs()[aItemIndex];
614
615 if( iface < KIWAY::KIWAY_FACE_COUNT )
616 {
618 success = m_frame->Kiway().ProcessJobConfigDialog( iface, job.m_job.get(), m_frame );
619 }
620 else
621 {
622 // special jobs
623 if( job.m_job->GetType() == "special_execute" )
624 {
625 JOB_SPECIAL_EXECUTE* specialJob = static_cast<JOB_SPECIAL_EXECUTE*>( job.m_job.get() );
626
627 DIALOG_EXECUTECOMMAND_JOB_SETTINGS dialog( m_frame, specialJob );
628
629 if( dialog.ShowModal() == wxID_OK )
630 success = true;
631 }
632 else if( job.m_job->GetType() == "special_copyfiles" )
633 {
634 JOB_SPECIAL_COPYFILES* specialJob =
635 static_cast<JOB_SPECIAL_COPYFILES*>( job.m_job.get() );
636 DIALOG_COPYFILES_JOB_SETTINGS dialog( m_frame, specialJob );
637
638 if( dialog.ShowModal() == wxID_OK )
639 success = true;
640 }
641 }
642
643 if( success )
644 {
645 m_jobsFile->SetDirty();
646 UpdateTitle();
647 }
648
649 // Bring the Kicad manager frame back to the front
650 m_frame->Raise();
651
652 return success;
653}
654
655
656void PANEL_JOBSET::OnGridCellChange( wxGridEvent& aEvent )
657{
658 int row = aEvent.GetRow();
659 int col = aEvent.GetCol();
660
661 if( col == 1 )
662 m_jobsFile->GetJobs()[row].SetDescription( m_jobsGrid->GetCellValue( row, col ) );
663}
664
665
666void PANEL_JOBSET::OnSaveButtonClick( wxCommandEvent& aEvent )
667{
669 return;
670
671 m_jobsFile->SaveToFile( wxEmptyString, true );
672 UpdateTitle();
673}
674
675
676void PANEL_JOBSET::OnAddJobClick( wxCommandEvent& aEvent )
677{
679 return;
680
681 wxArrayString headers;
682 std::vector<wxArrayString> items;
683
684 headers.Add( _( "Job Types" ) );
685
687
688 for( const std::pair<const wxString, JOB_REGISTRY_ENTRY>& entry : jobMap )
689 {
690 wxArrayString item;
691 item.Add( wxGetTranslation( entry.second.title ) );
692 items.emplace_back( item );
693 }
694
695 EDA_LIST_DIALOG dlg( this, _( "Add New Job" ), headers, items );
696 dlg.SetListLabel( _( "Select job type:" ) );
697
698 if( dlg.ShowModal() == wxID_OK )
699 {
700 wxString selectedString = dlg.GetTextSelection();
701
702 wxString jobKey;
703 if( !selectedString.IsEmpty() )
704 {
705 for( const std::pair<const wxString, JOB_REGISTRY_ENTRY>& entry : jobMap )
706 {
707 if( wxGetTranslation( entry.second.title ) == selectedString )
708 {
709 jobKey = entry.first;
710 break;
711 }
712 }
713 }
714
715 if( !jobKey.IsEmpty() )
716 {
717 int row = m_jobsFile->GetJobs().size();
718 bool wasDirty = m_jobsFile->GetDirty();
719 JOB* job = JOB_REGISTRY::CreateInstance<JOB>( jobKey );
720
721 m_jobsFile->AddNewJob( jobKey, job );
722
723 if( OpenJobOptionsForListItem( row ) )
724 {
726
727 m_jobsGrid->SetGridCursor( row, 2 );
728 m_jobsGrid->EnableCellEditControl();
729 }
730 else
731 {
732 m_jobsFile->RemoveJob( row );
733 m_jobsFile->SetDirty( wasDirty );
734 }
735 }
736 }
737}
738
739
740void PANEL_JOBSET::OnJobButtonDelete( wxCommandEvent& aEvent )
741{
743 return;
744
745 wxArrayInt selectedRows = m_jobsGrid->GetSelectedRows();
746
747 if( selectedRows.empty() )
748 return;
749
750 m_jobsGrid->CommitPendingChanges( true /* quiet mode */ );
751 m_jobsGrid->ClearSelection();
752
753 // Reverse sort so deleting a row doesn't change the indexes of the other rows.
754 selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
755
756 int select = selectedRows[0];
757
758 for( int row : selectedRows )
759 m_jobsFile->RemoveJob( row );
760
762
763 if( m_jobsGrid->GetNumberRows() )
764 {
765 m_jobsGrid->MakeCellVisible( std::max( 0, select-1 ), m_jobsGrid->GetGridCursorCol() );
766 m_jobsGrid->SetGridCursor( std::max( 0, select-1 ), m_jobsGrid->GetGridCursorCol() );
767 }
768}
769
770
771void PANEL_JOBSET::OnAddOutputClick( wxCommandEvent& aEvent )
772{
773 wxArrayString headers;
774 std::vector<wxArrayString> items;
775
776 headers.Add( _( "Output Types" ) );
777
778 for( const std::pair<const JOBSET_OUTPUT_TYPE, JOBSET_OUTPUT_TYPE_INFO>& outputType : JobsetOutputTypeInfos )
779 {
780 wxArrayString item;
781 item.Add( wxGetTranslation( outputType.second.name ) );
782 items.emplace_back( item );
783 }
784
785 EDA_LIST_DIALOG dlg( this, _( "Add New Output" ), headers, items );
786 dlg.SetListLabel( _( "Select output type:" ) );
787 dlg.HideFilter();
788
789 if( dlg.ShowModal() == wxID_OK )
790 {
791 wxString selectedString = dlg.GetTextSelection();
792
793 for( const std::pair<const JOBSET_OUTPUT_TYPE, JOBSET_OUTPUT_TYPE_INFO>& jobType : JobsetOutputTypeInfos )
794 {
795 if( wxGetTranslation( jobType.second.name ) == selectedString )
796 {
797 JOBSET_OUTPUT* output = m_jobsFile->AddNewJobOutput( jobType.first );
798
799 DIALOG_JOBSET_OUTPUT_OPTIONS dialog( m_frame, m_jobsFile.get(), output );
800 if (dialog.ShowModal() == wxID_OK)
801 {
802 Freeze();
803 addJobOutputPanel( output );
804 m_buttonRunAllOutputs->Enable( !m_jobsFile->GetOutputs().empty() );
805 Thaw();
806 }
807 else
808 {
809 // canceled
810 m_jobsFile->RemoveOutput( output );
811 }
812 }
813 }
814 }
815}
816
817
819{
820 if( m_jobsFile->GetDirty() )
821 {
822 wxFileName fileName = m_jobsFile->GetFullFilename();
823 wxString msg = _( "Save changes to '%s' before closing?" );
824
825 if( !HandleUnsavedChanges( this, wxString::Format( msg, fileName.GetFullName() ),
826 [&]() -> bool
827 {
828 return m_jobsFile->SaveToFile(wxEmptyString, true);
829 } ) )
830 {
831 return false;
832 }
833 }
834
835 return true;
836}
837
838
840{
842 KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_PCB_EDITOR, false );
843
844 if( !frame )
845 {
846 frame = m_frame->Kiway().Player( FRAME_PCB_EDITOR, true );
847
848 // frame can be null if Cvpcb cannot be run. No need to show a warning
849 // Kiway() generates the error messages
850 if( !frame )
851 return;
852
853 wxFileName boardfn = project.GetProjectFullName();
854 boardfn.SetExt( FILEEXT::PcbFileExtension );
855
856 // Prevent our window from being closed during the open process
857 wxEventBlocker blocker( this );
858
859 frame->OpenProjectFiles( std::vector<wxString>( 1, boardfn.GetFullPath() ) );
860
861 if( !frame->IsVisible() )
862 frame->Show( true );
863 }
864
865 frame = m_frame->Kiway().Player( FRAME_SCH, false );
866
867 if( !frame )
868 {
869 frame = m_frame->Kiway().Player( FRAME_SCH, true );
870
871 // frame can be null if Cvpcb cannot be run. No need to show a warning
872 // Kiway() generates the error messages
873 if( !frame )
874 return;
875
876 wxFileName schFn = project.GetProjectFullName();
878
879 wxEventBlocker blocker( this );
880
881 frame->OpenProjectFiles( std::vector<wxString>( 1, schFn.GetFullPath() ) );
882
883 if( !frame->IsVisible() )
884 frame->Show( true );
885 }
886
887 SetFocus();
888}
889
890
892{
893 return m_jobsFile->GetFullFilename();
894}
895
896
897void PANEL_JOBSET::OnJobButtonUp( wxCommandEvent& aEvent )
898{
900 return;
901
902 int item = m_jobsGrid->GetGridCursorRow();
903
904 if( item > 0 )
905 {
906 m_jobsFile->MoveJobUp( item );
907
909
910 m_jobsGrid->SelectRow( item - 1 );
911 m_jobsGrid->SetGridCursor( item - 1, m_jobsGrid->GetGridCursorCol() );
912 }
913 else
914 {
915 wxBell();
916 }
917}
918
919
920void PANEL_JOBSET::OnJobButtonDown( wxCommandEvent& aEvent )
921{
923 return;
924
925 int item = m_jobsGrid->GetGridCursorRow();
926
927 if( item < m_jobsGrid->GetNumberRows() - 1 )
928 {
929 m_jobsFile->MoveJobDown( item );
930
932
933 m_jobsGrid->SelectRow( item + 1 );
934 m_jobsGrid->SetGridCursor( item + 1, m_jobsGrid->GetGridCursorCol() );
935 }
936 else
937 {
938 wxBell();
939 }
940}
941
942
943void PANEL_JOBSET::OnGenerateAllOutputsClick( wxCommandEvent& event )
944{
946 return;
947
948 // sanity
949 if( m_jobsFile->GetOutputs().empty() )
950 {
951 DisplayError( this, _( "No outputs defined" ) );
952 return;
953 }
954
955 for( PANEL_JOBSET_OUTPUT* panel : GetOutputPanels() )
956 panel->ClearStatus();
957
958 Refresh();
959
960 CallAfter(
961 [this]()
962 {
965
966 wxFileName fn = project.GetProjectFullName();
967 wxSetWorkingDirectory( fn.GetPath() );
968
969 JOBS_RUNNER jobRunner( &( m_frame->Kiway() ), m_jobsFile.get(), &project );
970
971 WX_PROGRESS_REPORTER* progressReporter =
972 new WX_PROGRESS_REPORTER( m_frame, _( "Running jobs" ), 1 );
973
974 jobRunner.RunJobsAllOutputs();
975
976 for( PANEL_JOBSET_OUTPUT* panel : GetOutputPanels() )
977 panel->UpdateStatus();
978
979 delete progressReporter;
980
981 // Bring the Kicad manager frame back to the front
982 m_frame->Raise();
983 } );
984}
985
986
987void PANEL_JOBSET::OnSizeGrid( wxSizeEvent& aEvent )
988{
989 m_jobsGrid->SetColSize( 2, m_jobsGrid->GetSize().x - m_jobsGrid->GetColSize( 1 )
990 - m_jobsGrid->GetColSize( 0 ) );
991
992 // Always propagate for a grid repaint (needed if the height changes, as well as width)
993 aEvent.Skip();
994}
995
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition: bitmap.cpp:110
Class DIALOG_OUTPUT_RUN_RESULTS_BASE.
void OnJobListItemSelected(wxListEvent &event) override
DIALOG_OUTPUT_RUN_RESULTS(wxWindow *aParent, JOBSET *aJobsFile, JOBSET_OUTPUT *aOutput)
void onJobListSize(wxSizeEvent &event) override
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...
int ShowModal() override
A dialog which shows:
wxString GetTextSelection(int aColumn=0)
Return the selected text from aColumn in the wxListCtrl in the dialog.
void SetListLabel(const wxString &aLabel)
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition: grid_tricks.h:61
bool m_multiCellEditEnabled
Definition: grid_tricks.h:139
bool m_enableSingleClickEdit
Definition: grid_tricks.h:138
virtual void doPopupSelection(wxCommandEvent &event)
WX_GRID * m_grid
I don't own the grid, but he owns me.
Definition: grid_tricks.h:125
Definition: jobset.h:105
std::vector< JOBSET_JOB > GetJobsForOutput(JOBSET_OUTPUT *aOutput)
Definition: jobset.cpp:302
void SetDirty(bool aFlag=true)
Definition: jobset.h:124
std::vector< JOBSET_JOB > & GetJobs()
Definition: jobset.h:111
std::vector< JOBSET_OUTPUT > & GetOutputs()
Definition: jobset.h:118
PANEL_JOBSET * m_parent
Definition: panel_jobset.h:54
void showPopupMenu(wxMenu &menu, wxGridEvent &aEvent) override
void doPopupSelection(wxCommandEvent &event) override
bool handleDoubleClick(wxGridEvent &aEvent) override
JOBS_GRID_TRICKS(PANEL_JOBSET *aParent, WX_GRID *aGrid)
bool RunJobsForOutput(JOBSET_OUTPUT *aOutput, bool aBail=false)
bool RunJobsAllOutputs(bool aBail=false)
Definition: jobs_runner.cpp:51
static const REGISTRY_MAP_T & GetRegistry()
Definition: job_registry.h:55
std::unordered_map< wxString, JOB_REGISTRY_ENTRY > REGISTRY_MAP_T
Definition: job_registry.h:37
static KIWAY::FACE_T GetKifaceType(const wxString &aName)
An simple container class that lets us dispatch output jobs to kifaces.
Definition: job.h:182
The main KiCad project manager frame.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:65
virtual bool OpenProjectFiles(const std::vector< wxString > &aFileList, int aCtl=0)
Open a project or set of files given by aFileList.
Definition: kiway_player.h:113
bool ProcessJobConfigDialog(KIWAY::FACE_T aFace, JOB *aJob, wxWindow *aWindow)
Definition: kiway.cpp:719
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:406
FACE_T
Known KIFACE implementations.
Definition: kiway.h:291
@ KIWAY_FACE_COUNT
Definition: kiway.h:301
@ FACE_SCH
eeschema DSO
Definition: kiway.h:292
@ FACE_PCB
pcbnew DSO
Definition: kiway.h:293
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition: kiway.cpp:195
Class PANEL_JOBSET_BASE.
wxBoxSizer * m_outputListSizer
STD_BITMAP_BUTTON * m_buttonDown
wxButton * m_buttonRunAllOutputs
wxScrolledWindow * m_outputList
STD_BITMAP_BUTTON * m_buttonOutputAdd
STD_BITMAP_BUTTON * m_buttonAddJob
STD_BITMAP_BUTTON * m_buttonDelete
STD_BITMAP_BUTTON * m_buttonUp
Class PANEL_JOBSET_OUTPUT_BASE.
wxStaticBitmap * m_bitmapOutputType
STD_BITMAP_BUTTON * m_buttonDelete
STD_BITMAP_BUTTON * m_buttonProperties
wxStaticBitmap * m_statusBitmap
wxStaticText * m_textOutputType
PANEL_JOBSET_OUTPUT(wxWindow *aParent, PANEL_JOBSET *aPanelParent, KICAD_MANAGER_FRAME *aFrame, JOBSET *aFile, JOBSET_OUTPUT *aOutput)
PANEL_JOBSET * m_panelParent
JOBSET_OUTPUT * GetOutput()
virtual void OnLastStatusClick(wxMouseEvent &aEvent) override
KICAD_MANAGER_FRAME * m_frame
void onMenu(wxCommandEvent &aEvent)
virtual void OnDelete(wxCommandEvent &aEvent) override
virtual void OnGenerate(wxCommandEvent &event) override
void OnProperties(wxCommandEvent &aEvent) override
void OnRightDown(wxMouseEvent &aEvent) override
wxString GetFilePath() const
void buildOutputList()
JOBSET * GetJobsFile()
Definition: panel_jobset.h:74
virtual void OnSaveButtonClick(wxCommandEvent &aEvent) override
void OnJobButtonDelete(wxCommandEvent &aEvent) override
virtual void OnJobButtonDown(wxCommandEvent &aEvent) override
void EnsurePcbSchFramesOpen()
bool GetCanClose() override
void rebuildJobList()
virtual void OnGenerateAllOutputsClick(wxCommandEvent &event) override
wxAuiNotebook * m_parentBook
Definition: panel_jobset.h:99
void UpdateTitle()
bool OpenJobOptionsForListItem(size_t aItemIndex)
std::vector< PANEL_JOBSET_OUTPUT * > GetOutputPanels()
KICAD_MANAGER_FRAME * m_frame
Definition: panel_jobset.h:100
PANEL_JOBSET(wxAuiNotebook *aParent, KICAD_MANAGER_FRAME *aFrame, std::unique_ptr< JOBSET > aJobsFile)
void RemoveOutput(PANEL_JOBSET_OUTPUT *aPanel)
virtual void OnAddJobClick(wxCommandEvent &aEvent) override
std::unique_ptr< JOBSET > m_jobsFile
Definition: panel_jobset.h:101
virtual void OnGridCellChange(wxGridEvent &aEvent) override
virtual void OnAddOutputClick(wxCommandEvent &aEvent) override
void addJobOutputPanel(JOBSET_OUTPUT *aOutput)
virtual void OnJobButtonUp(wxCommandEvent &aEvent) override
virtual void OnSizeGrid(wxSizeEvent &aEvent) override
Container for project specific data.
Definition: project.h:64
void SetBitmap(const wxBitmapBundle &aBmp)
void OverrideMinSize(double aXPct, double aYPct)
Grids that have column sizes automatically set to fill the available width don't want to shrink after...
Definition: wx_grid.h:215
bool CancelPendingChanges()
Definition: wx_grid.cpp:616
void CancelShowEditorOnMouseUp()
Definition: wx_grid.h:186
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:644
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
A wrapper for reporting to a wxString object.
Definition: reporter.h:171
const wxString & GetMessages() const
Definition: reporter.cpp:87
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:130
This file is part of the common library.
#define _(s)
@ FRAME_PCB_EDITOR
Definition: frame_type.h:42
@ FRAME_SCH
Definition: frame_type.h:34
@ GRIDTRICKS_ID_SELECT
Definition: grid_tricks.h:46
@ GRIDTRICKS_ID_COPY
Definition: grid_tricks.h:43
@ GRIDTRICKS_ID_DELETE
Definition: grid_tricks.h:44
static const std::string KiCadSchematicFileExtension
Some functions to handle hotkeys in KiCad.
KICOMMON_API std::map< JOBSET_OUTPUT_TYPE, JOBSET_OUTPUT_TYPE_INFO > JobsetOutputTypeInfos
Definition: jobset.cpp:39
PROJECT & Prj()
Definition: kicad.cpp:597
#define KICOMMON_API
Definition: kicommon.h:28
STL namespace.
KICOMMON_API std::map< JOBSET_OUTPUT_TYPE, JOBSET_OUTPUT_TYPE_INFO > JobsetOutputTypeInfos
Definition: jobset.cpp:39
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
std::vector< FAB_LAYER_COLOR > dummy
wxString m_id
Definition: jobset.h:46
std::shared_ptr< JOB > m_job
Definition: jobset.h:49
wxString m_type
Definition: jobset.h:47
wxString GetDescription() const
Definition: jobset.cpp:160
std::unordered_map< wxString, std::optional< bool > > m_lastRunSuccessMap
Definition: jobset.h:96
std::optional< bool > m_lastRunSuccess
Definition: jobset.h:95
std::unordered_map< wxString, REPORTER * > m_lastRunReporters
Definition: jobset.h:97
JOBSET_OUTPUT_TYPE m_type
Definition: jobset.h:86
Definition of file extensions used in Kicad.