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,
56 JOBSET* aJobsFile,
57 JOBSET_OUTPUT* aOutput ) :
59 m_jobsFile( aJobsFile ),
60 m_output( aOutput )
61 {
62 m_staticTextOutputName->SetLabel( wxString::Format( _( "Output: %s" ),
63 aOutput->GetDescription() ) );
64
65 int jobBmpColId = m_jobList->AppendColumn( wxT( "" ) );
66 int jobNoColId = m_jobList->AppendColumn( _( "No." ) );
67 int jobDescColId = m_jobList->AppendColumn( _( "Job Description" ) );
68 m_jobList->SetColumnWidth( jobBmpColId, wxLIST_AUTOSIZE_USEHEADER );
69 m_jobList->SetColumnWidth( jobNoColId, wxLIST_AUTOSIZE_USEHEADER );
70 m_jobList->SetColumnWidth( jobDescColId, wxLIST_AUTOSIZE_USEHEADER );
71
72 wxImageList* imageList = new wxImageList( 16, 16, true, 3 );
73 imageList->Add( KiBitmapBundle( BITMAPS::ercerr ).GetBitmap( wxSize( 16, 16 ) ) );
74 imageList->Add( KiBitmapBundle( BITMAPS::checked_ok ).GetBitmap( wxSize( 16, 16 ) ) );
75 m_jobList->SetImageList( imageList, wxIMAGE_LIST_SMALL );
76
77 int num = 1;
78 for( auto& job : aJobsFile->GetJobsForOutput( aOutput ) )
79 {
80 int imageIdx = -1;
81 if( aOutput->m_lastRunSuccessMap.contains( job.m_id ) )
82 {
83 if( aOutput->m_lastRunSuccessMap[job.m_id].value() )
84 imageIdx = 1;
85 else
86 imageIdx = 0;
87 }
88
89 long itemIndex = m_jobList->InsertItem( m_jobList->GetItemCount(), imageIdx );
90
91 m_jobList->SetItem( itemIndex, jobNoColId, wxString::Format( "%d", num++ ) );
92 m_jobList->SetItem( itemIndex, jobDescColId, job.GetDescription() );
93 }
94
95 SetupStandardButtons( { { wxID_OK, _( "Close" ) } } );
96 }
97
98
99 virtual void OnJobListItemSelected( wxListEvent& event ) override
100 {
101 int itemIndex = event.GetIndex();
102
103 // The index could be negative (it is default -1)
104 if( itemIndex < 0 )
105 return;
106
107 std::vector<JOBSET_JOB> jobs = m_jobsFile->GetJobsForOutput( m_output );
108
109 if( static_cast<size_t>( itemIndex ) < jobs.size() )
110 {
111 JOBSET_JOB& job = jobs[itemIndex];
112 if( m_output->m_lastRunReporters.contains( job.m_id ) )
113 {
114 WX_STRING_REPORTER* reporter =
115 static_cast<WX_STRING_REPORTER*>( m_output->m_lastRunReporters[job.m_id] );
116 m_textCtrlOutput->SetValue( reporter->GetMessages() );
117 }
118 else
119 {
120 m_textCtrlOutput->SetValue( _( "No output messages" ) );
121 }
122 }
123
124 }
125
126private:
129};
130
131
133{
134public:
135 PANEL_JOBSET_OUTPUT( wxWindow* aParent, PANEL_JOBSET* aPanelParent, KICAD_MANAGER_FRAME* aFrame,
136 JOBSET* aFile, JOBSET_OUTPUT* aOutput ) :
137 PANEL_JOBSET_OUTPUT_BASE( aParent ),
138 m_jobsFile( aFile ),
139 m_outputId( aOutput->m_id ),
140 m_frame( aFrame ),
141 m_panelParent( aPanelParent )
142 {
143 m_buttonProperties->SetBitmap( KiBitmapBundle( BITMAPS::config ) );
144 m_buttonDelete->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
145
146#if _WIN32
147 // BORDER_RAISED/SUNKEN look pretty on every platform but Windows
148 long style = GetWindowStyleFlag();
149 style &= ~wxBORDER_MASK;
150 style |= wxBORDER_SIMPLE;
151 SetWindowStyleFlag( style );
152#endif // _WIN32
153
154 Connect( wxEVT_MENU, wxCommandEventHandler( PANEL_JOBSET_OUTPUT::onMenu ), nullptr, this );
155
156 if( JobsetOutputTypeInfos.contains( aOutput->m_type ) )
157 {
159 m_textOutputType->SetLabel( aOutput->GetDescription() );
160 m_bitmapOutputType->SetBitmap( KiBitmapBundle( jobTypeInfo.bitmap ) );
161 }
162
163 UpdateStatus();
164 }
165
166
168 {
169 Disconnect( wxEVT_MENU, wxCommandEventHandler( PANEL_JOBSET_OUTPUT::onMenu ), nullptr, this );
170 }
171
173 {
174 JOBSET_OUTPUT* output = GetOutput();
175 wxCHECK( output, /*void*/ );
176
177 if( output->m_lastRunSuccess.has_value() )
178 {
179 if( output->m_lastRunSuccess.value() )
180 {
181 m_statusBitmap->SetBitmap( KiBitmapBundle( BITMAPS::checked_ok ) );
182 m_statusBitmap->Show();
183 m_statusBitmap->SetToolTip( _( "Last run successful" ) );
184 }
185 else
186 {
187 m_statusBitmap->SetBitmap( KiBitmapBundle( BITMAPS::ercerr ) );
188 m_statusBitmap->Show();
189 m_statusBitmap->SetToolTip( _( "Last run failed" ) );
190 }
191 }
192 else
193 {
194 m_statusBitmap->SetBitmap( wxNullBitmap );
195 }
196
197 m_buttonGenerate->Enable( !m_jobsFile->GetJobsForOutput( output ).empty() );
198 }
199
200 virtual void OnGenerate( wxCommandEvent& event ) override
201 {
202 CallAfter(
203 [this]()
204 {
207
208 wxFileName fn = project.GetProjectFullName();
209 wxSetWorkingDirectory( fn.GetPath() );
210
211 JOBS_RUNNER jobRunner( &( m_frame->Kiway() ), m_jobsFile, &project );
212
213 WX_PROGRESS_REPORTER* progressReporter =
214 new WX_PROGRESS_REPORTER( m_frame, _( "Running jobs" ), 1 );
215
216 if( JOBSET_OUTPUT* output = GetOutput() )
217 jobRunner.RunJobsForOutput( output );
218
219 UpdateStatus();
220
221 delete progressReporter;
222
223 // Bring the Kicad manager frame back to the front
224 m_frame->Raise();
225 } );
226 }
227
228 virtual void OnLastStatusClick( wxMouseEvent& aEvent ) override
229 {
230 JOBSET_OUTPUT* output = GetOutput();
231 wxCHECK( output, /*void*/ );
232
234 dialog.ShowModal();
235 }
236
237 void OnRightDown( wxMouseEvent& aEvent ) override
238 {
239 JOBSET_OUTPUT* output = GetOutput();
240 wxCHECK( output, /*void*/ );
241
242 wxMenu menu;
243 menu.Append( wxID_EDIT, _( "Edit Output Options..." ) );
244 menu.Append( wxID_DELETE, _( "Delete Output" ) );
245
246 menu.AppendSeparator();
247 menu.Append( wxID_VIEW_DETAILS, _( "View Last Run Results..." ) );
248
249 menu.Enable( wxID_VIEW_DETAILS, output->m_lastRunSuccess.has_value() );
250
251 PopupMenu( &menu );
252 }
253
254 void OnProperties( wxCommandEvent& aEvent ) override
255 {
256 JOBSET_OUTPUT* output = GetOutput();
257 wxCHECK( output, /*void*/ );
258
260
261 if( dialog.ShowModal() == wxID_OK )
262 {
263 m_textOutputType->SetLabel( output->GetDescription() );
266 }
267 }
268
269 virtual void OnDelete( wxCommandEvent& aEvent ) override
270 {
272 }
273
275 {
276 for( JOBSET_OUTPUT& jobset : m_jobsFile->GetOutputs() )
277 {
278 if( jobset.m_id == m_outputId )
279 return &jobset;
280 }
281
282 return nullptr;
283 }
284
285private:
286 void onMenu( wxCommandEvent& aEvent )
287 {
288 switch( aEvent.GetId() )
289 {
290 case wxID_EDIT:
291 {
292 wxCommandEvent dummy;
294 }
295 break;
296
297 case wxID_DELETE:
298 {
299 wxCommandEvent dummy;
300 OnDelete( dummy );
301 }
302 break;
303
304 case wxID_VIEW_DETAILS:
305 {
306 wxMouseEvent dummy;
308 }
309 break;
310
311 default:
312 wxFAIL_MSG( wxT( "Unknown ID in context menu event" ) );
313 }
314 }
315
316private:
318 wxString m_outputId;
321};
322
323
325 GRID_TRICKS( aGrid ),
326 m_parent( aParent )
327{
330}
331
332
333void JOBS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
334{
335 wxArrayInt selectedRows = m_grid->GetSelectedRows();
336
337 menu.Append( JOB_DESCRIPTION, _( "Edit Job Description" ) );
338 menu.Append( JOB_PROPERTIES, _( "Edit Job Settings..." ) );
339 menu.AppendSeparator();
340 menu.Append( GRIDTRICKS_ID_COPY, _( "Copy" ) + "\tCtrl+C",
341 _( "Copy selected cells to clipboard" ) );
342 menu.Append( GRIDTRICKS_ID_DELETE, _( "Delete" ) + "\tDel",
343 _( "Delete selected jobs" ) );
344 menu.Append( GRIDTRICKS_ID_SELECT, _( "Select All" ) + "\tCtrl+A",
345 _( "Select all jobs" ) );
346
347 menu.Enable( JOB_DESCRIPTION, selectedRows.size() == 1 );
348 menu.Enable( JOB_PROPERTIES, selectedRows.size() == 1 );
349 menu.Enable( GRIDTRICKS_ID_DELETE, selectedRows.size() > 0 );
350
351 m_grid->PopupMenu( &menu );
352}
353
354
355void JOBS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
356{
357 wxArrayInt selectedRows = m_grid->GetSelectedRows();
358
359 if( event.GetId() == JOB_DESCRIPTION )
360 {
361 if( selectedRows.size() > 0 )
362 {
363 m_grid->SetGridCursor( selectedRows[0], 1 );
364 m_grid->EnableCellEditControl();
365 }
366 }
367 else if( event.GetId() == JOB_PROPERTIES )
368 {
369 if( selectedRows.size() > 0 )
370 m_parent->OpenJobOptionsForListItem( selectedRows[0] );
371 }
372 else if( event.GetId() == GRIDTRICKS_ID_DELETE )
373 {
374 wxCommandEvent dummy;
376 }
377 else
378 {
380 }
381}
382
383
384bool JOBS_GRID_TRICKS::handleDoubleClick( wxGridEvent& aEvent )
385{
387
388 int curr_col = aEvent.GetCol();
389 int curr_row = aEvent.GetRow();
390
391 if( ( curr_col == 0 || curr_col == 1 )
392 && curr_row >= 0 && curr_row < (int) m_parent->GetJobsFile()->GetJobs().size() )
393 {
394 m_doubleClickRow = curr_row;
396
397 CallAfter(
398 [this]()
399 {
400 // Yes, again. CancelShowEditorOnMouseUp() doesn't appear to be 100%
401 // reliable.
403 int row = m_doubleClickRow;
404 m_doubleClickRow = -1;
405
406 if( row >= 0 && row < (int) m_parent->GetJobsFile()->GetJobs().size() )
408 } );
409
410 return true;
411 }
412
413 return false;
414}
415
416
417PANEL_JOBSET::PANEL_JOBSET( wxAuiNotebook* aParent, KICAD_MANAGER_FRAME* aFrame,
418 std::unique_ptr<JOBSET> aJobsFile ) :
419 PANEL_JOBSET_BASE( aParent ),
420 m_parentBook( aParent ),
421 m_frame( aFrame ),
422 m_jobsFile( std::move( aJobsFile ) )
423{
424 m_jobsGrid->PushEventHandler( new JOBS_GRID_TRICKS( this, m_jobsGrid ) );
425
426 m_jobsGrid->SetDefaultRowSize( m_jobsGrid->GetDefaultRowSize() + 4 );
427 m_jobsGrid->OverrideMinSize( 0.6, 0.3 );
428 m_jobsGrid->SetSelectionMode( wxGrid::wxGridSelectRows );
429
430 // 'm' for margins
431 m_jobsGrid->SetColSize( 0, GetTextExtent( wxT( "99m" ) ).x );
432
433 m_buttonAddJob->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
434 m_buttonUp->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
435 m_buttonDown->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
436 m_buttonDelete->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
437 m_buttonOutputAdd->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
438
441
442 m_buttonRunAllOutputs->Enable( !m_jobsFile->GetOutputs().empty()
443 && !m_jobsFile->GetJobs().empty() );
444}
445
446
448{
449 // Delete the GRID_TRICKS.
450 m_jobsGrid->PopEventHandler( true );
451}
452
453
455{
456 JOBSET_OUTPUT* output = aPanel->GetOutput();
457
458 m_outputListSizer->Detach( aPanel );
459 aPanel->Destroy();
460
461 // ensure the window contents get shifted as needed
462 m_outputList->Layout();
463 Layout();
464
465 m_jobsFile->RemoveOutput( output );
466
467 m_buttonRunAllOutputs->Enable( !m_jobsFile->GetOutputs().empty() );
468}
469
470
472{
473 if( m_jobsGrid->GetNumberRows() )
474 m_jobsGrid->DeleteRows( 0, m_jobsGrid->GetNumberRows() );
475
476 m_jobsGrid->AppendRows( m_jobsFile->GetJobs().size() );
477
478 int num = 1;
479
480 for( JOBSET_JOB& job : m_jobsFile->GetJobs() )
481 {
482 m_jobsGrid->SetCellValue( num - 1, 0, wxString::Format( "%d", num ) );
483 m_jobsGrid->SetReadOnly( num - 1, 0 );
484
485 m_jobsGrid->SetCellValue( num - 1, 1, job.GetDescription() );
486
487 num++;
488 }
489
490 UpdateTitle();
491
492 // Ensure the outputs get their Run-ability status updated
493 for( PANEL_JOBSET_OUTPUT* panel : GetOutputPanels() )
494 panel->UpdateStatus();
495}
496
497
499{
500 wxString tabName = m_jobsFile->GetFullName();
501
502 if( m_jobsFile->GetDirty() )
503 tabName = wxS( "*" ) + tabName;
504
505 int pageIdx = m_parentBook->FindPage( this );
506 m_parentBook->SetPageText( pageIdx, tabName );
507}
508
509
511{
513 m_jobsFile.get(), aOutput );
514
515#if __OSX__
516 m_outputListSizer->Add( outputPanel, 0, wxEXPAND, 5 );
517#else
518 m_outputListSizer->Add( outputPanel, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5 );
519#endif
520
521 m_outputList->Layout();
522}
523
524
525std::vector<PANEL_JOBSET_OUTPUT*> PANEL_JOBSET::GetOutputPanels()
526{
527 std::vector<PANEL_JOBSET_OUTPUT*> panels;
528
529 for( const wxSizerItem* item : m_outputListSizer->GetChildren() )
530 {
531 if( PANEL_JOBSET_OUTPUT* panel = dynamic_cast<PANEL_JOBSET_OUTPUT*>( item->GetWindow() ) )
532 panels.push_back( panel );
533 }
534
535 return panels;
536}
537
538
540{
541 Freeze();
542
543 for( JOBSET_OUTPUT& job : m_jobsFile->GetOutputs() )
544 addJobOutputPanel( &job );
545
546 // ensure the window contents get shifted as needed
547 Layout();
548 Thaw();
549}
550
551
553{
554 bool success = false;
555 JOBSET_JOB& job = m_jobsFile->GetJobs()[aItemIndex];
557
558 if( iface < KIWAY::KIWAY_FACE_COUNT )
559 {
561 success = m_frame->Kiway().ProcessJobConfigDialog( iface, job.m_job.get(), m_frame );
562 }
563 else
564 {
565 // special jobs
566 if( job.m_job->GetType() == "special_execute" )
567 {
568 JOB_SPECIAL_EXECUTE* specialJob = static_cast<JOB_SPECIAL_EXECUTE*>( job.m_job.get() );
569
570 DIALOG_EXECUTECOMMAND_JOB_SETTINGS dialog( m_frame, specialJob );
571
572 if( dialog.ShowModal() == wxID_OK )
573 success = true;
574 }
575 else if( job.m_job->GetType() == "special_copyfiles" )
576 {
577 JOB_SPECIAL_COPYFILES* specialJob =
578 static_cast<JOB_SPECIAL_COPYFILES*>( job.m_job.get() );
579 DIALOG_COPYFILES_JOB_SETTINGS dialog( m_frame, specialJob );
580
581 if( dialog.ShowModal() == wxID_OK )
582 success = true;
583 }
584 }
585
586 if( success )
587 {
588 m_jobsFile->SetDirty();
589 UpdateTitle();
590 }
591
592 // Bring the Kicad manager frame back to the front
593 m_frame->Raise();
594
595 return success;
596}
597
598
599void PANEL_JOBSET::OnGridCellChange( wxGridEvent& aEvent )
600{
601 int row = aEvent.GetRow();
602 int col = aEvent.GetCol();
603
604 if( col == 1 )
605 m_jobsFile->GetJobs()[row].SetDescription( m_jobsGrid->GetCellValue( row, col ) );
606}
607
608
609void PANEL_JOBSET::OnSaveButtonClick( wxCommandEvent& aEvent )
610{
612 return;
613
614 m_jobsFile->SaveToFile( wxEmptyString, true );
615 UpdateTitle();
616}
617
618
619void PANEL_JOBSET::OnAddJobClick( wxCommandEvent& aEvent )
620{
622 return;
623
624 wxArrayString headers;
625 std::vector<wxArrayString> items;
626
627 headers.Add( _( "Job Types" ) );
628
630
631 for( const std::pair<const wxString, JOB_REGISTRY_ENTRY>& entry : jobMap )
632 {
633 wxArrayString item;
634 item.Add( wxGetTranslation( entry.second.title ) );
635 items.emplace_back( item );
636 }
637
638 EDA_LIST_DIALOG dlg( this, _( "Add New Job" ), headers, items );
639 dlg.SetListLabel( _( "Select job type:" ) );
640
641 if( dlg.ShowModal() == wxID_OK )
642 {
643 wxString selectedString = dlg.GetTextSelection();
644
645 wxString jobKey;
646 if( !selectedString.IsEmpty() )
647 {
648 for( const std::pair<const wxString, JOB_REGISTRY_ENTRY>& entry : jobMap )
649 {
650 if( wxGetTranslation( entry.second.title ) == selectedString )
651 {
652 jobKey = entry.first;
653 break;
654 }
655 }
656 }
657
658 if( !jobKey.IsEmpty() )
659 {
660 int row = m_jobsFile->GetJobs().size();
661 bool wasDirty = m_jobsFile->GetDirty();
662 JOB* job = JOB_REGISTRY::CreateInstance<JOB>( jobKey );
663
664 m_jobsFile->AddNewJob( jobKey, job );
665
666 if( OpenJobOptionsForListItem( row ) )
667 {
669
670 m_jobsGrid->SetGridCursor( row, 1 );
671 m_jobsGrid->EnableCellEditControl();
672 }
673 else
674 {
675 m_jobsFile->RemoveJob( row );
676 m_jobsFile->SetDirty( wasDirty );
677 }
678 }
679 }
680}
681
682
683void PANEL_JOBSET::OnJobButtonDelete( wxCommandEvent& aEvent )
684{
686 return;
687
688 wxArrayInt selectedRows = m_jobsGrid->GetSelectedRows();
689
690 if( selectedRows.empty() )
691 return;
692
693 m_jobsGrid->CommitPendingChanges( true /* quiet mode */ );
694 m_jobsGrid->ClearSelection();
695
696 // Reverse sort so deleting a row doesn't change the indexes of the other rows.
697 selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
698
699 int select = selectedRows[0];
700
701 for( int row : selectedRows )
702 m_jobsFile->RemoveJob( row );
703
705
706 if( m_jobsGrid->GetNumberRows() )
707 {
708 m_jobsGrid->MakeCellVisible( std::max( 0, select-1 ), m_jobsGrid->GetGridCursorCol() );
709 m_jobsGrid->SetGridCursor( std::max( 0, select-1 ), m_jobsGrid->GetGridCursorCol() );
710 }
711}
712
713
714void PANEL_JOBSET::OnAddOutputClick( wxCommandEvent& aEvent )
715{
716 wxArrayString headers;
717 std::vector<wxArrayString> items;
718
719 headers.Add( _( "Output Types" ) );
720
721 for( const std::pair<const JOBSET_OUTPUT_TYPE, JOBSET_OUTPUT_TYPE_INFO>& outputType : JobsetOutputTypeInfos )
722 {
723 wxArrayString item;
724 item.Add( wxGetTranslation( outputType.second.name ) );
725 items.emplace_back( item );
726 }
727
728 EDA_LIST_DIALOG dlg( this, _( "Add New Output" ), headers, items );
729 dlg.SetListLabel( _( "Select output type:" ) );
730 dlg.HideFilter();
731
732 if( dlg.ShowModal() == wxID_OK )
733 {
734 wxString selectedString = dlg.GetTextSelection();
735
736 for( const std::pair<const JOBSET_OUTPUT_TYPE, JOBSET_OUTPUT_TYPE_INFO>& jobType : JobsetOutputTypeInfos )
737 {
738 if( wxGetTranslation( jobType.second.name ) == selectedString )
739 {
740 JOBSET_OUTPUT* output = m_jobsFile->AddNewJobOutput( jobType.first );
741
742 DIALOG_JOBSET_OUTPUT_OPTIONS dialog( m_frame, m_jobsFile.get(), output );
743 if (dialog.ShowModal() == wxID_OK)
744 {
745 Freeze();
746 addJobOutputPanel( output );
747 m_buttonRunAllOutputs->Enable( !m_jobsFile->GetOutputs().empty() );
748 Thaw();
749 }
750 else
751 {
752 // canceled
753 m_jobsFile->RemoveOutput( output );
754 }
755 }
756 }
757 }
758}
759
760
762{
763 if( m_jobsFile->GetDirty() )
764 {
765 wxFileName fileName = m_jobsFile->GetFullFilename();
766 wxString msg = _( "Save changes to '%s' before closing?" );
767
768 if( !HandleUnsavedChanges( this, wxString::Format( msg, fileName.GetFullName() ),
769 [&]() -> bool
770 {
771 return m_jobsFile->SaveToFile(wxEmptyString, true);
772 } ) )
773 {
774 return false;
775 }
776 }
777
778 return true;
779}
780
781
783{
785 KIWAY_PLAYER* frame = m_frame->Kiway().Player( FRAME_PCB_EDITOR, false );
786
787 if( !frame )
788 {
789 frame = m_frame->Kiway().Player( FRAME_PCB_EDITOR, true );
790
791 // frame can be null if Cvpcb cannot be run. No need to show a warning
792 // Kiway() generates the error messages
793 if( !frame )
794 return;
795
796 wxFileName boardfn = project.GetProjectFullName();
797 boardfn.SetExt( FILEEXT::PcbFileExtension );
798
799 // Prevent our window from being closed during the open process
800 wxEventBlocker blocker( this );
801
802 frame->OpenProjectFiles( std::vector<wxString>( 1, boardfn.GetFullPath() ) );
803
804 if( !frame->IsVisible() )
805 frame->Show( true );
806 }
807
808 frame = m_frame->Kiway().Player( FRAME_SCH, false );
809
810 if( !frame )
811 {
812 frame = m_frame->Kiway().Player( FRAME_SCH, true );
813
814 // frame can be null if Cvpcb cannot be run. No need to show a warning
815 // Kiway() generates the error messages
816 if( !frame )
817 return;
818
819 wxFileName schFn = project.GetProjectFullName();
821
822 wxEventBlocker blocker( this );
823
824 frame->OpenProjectFiles( std::vector<wxString>( 1, schFn.GetFullPath() ) );
825
826 if( !frame->IsVisible() )
827 frame->Show( true );
828 }
829
830 SetFocus();
831}
832
833
835{
836 return m_jobsFile->GetFullFilename();
837}
838
839
840void PANEL_JOBSET::OnJobButtonUp( wxCommandEvent& aEvent )
841{
843 return;
844
845 int item = m_jobsGrid->GetGridCursorRow();
846
847 if( item > 0 )
848 {
849 m_jobsFile->MoveJobUp( item );
850
852
853 m_jobsGrid->SelectRow( item - 1 );
854 m_jobsGrid->SetGridCursor( item - 1, m_jobsGrid->GetGridCursorCol() );
855 }
856 else
857 {
858 wxBell();
859 }
860}
861
862
863void PANEL_JOBSET::OnJobButtonDown( wxCommandEvent& aEvent )
864{
866 return;
867
868 int item = m_jobsGrid->GetGridCursorRow();
869
870 if( item < m_jobsGrid->GetNumberRows() - 1 )
871 {
872 m_jobsFile->MoveJobDown( item );
873
875
876 m_jobsGrid->SelectRow( item + 1 );
877 m_jobsGrid->SetGridCursor( item + 1, m_jobsGrid->GetGridCursorCol() );
878 }
879 else
880 {
881 wxBell();
882 }
883}
884
885
886void PANEL_JOBSET::OnGenerateAllOutputsClick( wxCommandEvent& event )
887{
889 return;
890
891 // sanity
892 if( m_jobsFile->GetOutputs().empty() )
893 {
894 DisplayError( this, _( "No outputs defined" ) );
895 return;
896 }
897
898 CallAfter(
899 [this]()
900 {
903
904 wxFileName fn = project.GetProjectFullName();
905 wxSetWorkingDirectory( fn.GetPath() );
906
907 JOBS_RUNNER jobRunner( &( m_frame->Kiway() ), m_jobsFile.get(), &project );
908
909 WX_PROGRESS_REPORTER* progressReporter =
910 new WX_PROGRESS_REPORTER( m_frame, _( "Running jobs" ), 1 );
911
912 jobRunner.RunJobsAllOutputs();
913
914 for( PANEL_JOBSET_OUTPUT* panel : GetOutputPanels() )
915 panel->UpdateStatus();
916
917 delete progressReporter;
918
919 // Bring the Kicad manager frame back to the front
920 m_frame->Raise();
921 } );
922}
923
924
925void PANEL_JOBSET::OnSizeGrid( wxSizeEvent& aEvent )
926{
927 m_jobsGrid->SetColSize( 1, m_jobsGrid->GetSize().x - m_jobsGrid->GetColSize( 0 ) );
928
929 // Always propagate for a grid repaint (needed if the height changes, as well as width)
930 aEvent.Skip();
931}
932
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
Class DIALOG_OUTPUT_RUN_RESULTS_BASE.
DIALOG_OUTPUT_RUN_RESULTS(wxWindow *aParent, JOBSET *aJobsFile, JOBSET_OUTPUT *aOutput)
virtual void OnJobListItemSelected(wxListEvent &event) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
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
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:618
void CancelShowEditorOnMouseUp()
Definition: wx_grid.h:186
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:646
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:84
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
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.