KiCad PCB EDA Suite
Loading...
Searching...
No Matches
wx_html_report_panel.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) 2015 CERN
5 * Copyright (C) 2015-2024 KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <algorithm>
23
25
27#include <gal/color4d.h>
28#include <wx/clipbrd.h>
29#include <string_utils.h>
30#include <wx/ffile.h>
31#include <wx/log.h>
32#include <wx/filedlg.h>
33#include <wx/msgdlg.h>
34#include <wx/menu.h>
35#include <wx/textctrl.h>
36#include <kiplatform/ui.h>
37#include <kiway_holder.h>
38#include <project.h>
39
40WX_HTML_REPORT_PANEL::WX_HTML_REPORT_PANEL( wxWindow* parent, wxWindowID id, const wxPoint& pos,
41 const wxSize& size, long style ) :
42 WX_HTML_REPORT_PANEL_BASE( parent, id, pos, size, style ),
43 m_reporter( this ),
44 m_severities( -1 ),
45 m_lazyUpdate( false )
46{
49 Flush();
50
51 Connect( wxEVT_COMMAND_MENU_SELECTED,
52 wxMenuEventHandler( WX_HTML_REPORT_PANEL::onMenuEvent ), nullptr, this );
53
54 m_htmlView->Bind( wxEVT_SYS_COLOUR_CHANGED,
55 wxSysColourChangedEventHandler( WX_HTML_REPORT_PANEL::onThemeChanged ),
56 this );
57}
58
59
61{
62}
63
64
65void WX_HTML_REPORT_PANEL::onThemeChanged( wxSysColourChangedEvent &aEvent )
66{
67 Flush();
68
69 aEvent.Skip();
70}
71
72
73void WX_HTML_REPORT_PANEL::MsgPanelSetMinSize( const wxSize& aMinSize )
74{
75 m_fgSizer->SetMinSize( aMinSize );
76 GetSizer()->SetSizeHints( this );
77}
78
79
81{
82 return m_reporter;
83}
84
85
86void WX_HTML_REPORT_PANEL::Report( const wxString& aText, SEVERITY aSeverity,
87 REPORTER::LOCATION aLocation )
88{
89 REPORT_LINE line;
90 line.message = aText;
91 line.severity = aSeverity;
92
93 if( aLocation == REPORTER::LOC_HEAD )
94 m_reportHead.push_back( line );
95 else if( aLocation == REPORTER::LOC_TAIL )
96 m_reportTail.push_back( line );
97 else
98 m_report.push_back( line );
99
100 if( !m_lazyUpdate )
101 {
104 }
105}
106
107
109{
110 m_lazyUpdate = aLazyUpdate;
111}
112
113
115{
116 wxString html;
117
118 if( aSort )
119 {
120 std::sort( m_report.begin(), m_report.end(),
121 []( const REPORT_LINE& a, const REPORT_LINE& b)
122 {
123 return a.severity < b.severity;
124 });
125 }
126
127 for( const auto& line : m_reportHead )
128 html += generateHtml( line );
129
130 for( const auto& line : m_report )
131 html += generateHtml( line );
132
133 for( const auto& line : m_reportTail )
134 html += generateHtml( line );
135
136 m_htmlView->SetPage( html );
138}
139
140
142{
143 int x, y, xUnit, yUnit;
144
145 m_htmlView->GetVirtualSize( &x, &y );
146 m_htmlView->GetScrollPixelsPerUnit( &xUnit, &yUnit );
147 m_htmlView->Scroll( 0, y / yUnit );
148
149 updateBadges();
150}
151
152
154{
155 int count = Count(RPT_SEVERITY_ERROR );
157
158 count = Count(RPT_SEVERITY_WARNING );
160}
161
162
163int WX_HTML_REPORT_PANEL::Count( int severityMask )
164{
165 int count = 0;
166
167 for( const auto& reportLineArray : { m_report, m_reportHead, m_reportTail } )
168 {
169 for( const REPORT_LINE& reportLine : reportLineArray )
170 {
171 if( severityMask & reportLine.severity )
172 count++;
173 }
174 }
175
176 return count;
177}
178
179
181{
182 wxString retv;
183
184 if( !( m_severities & aLine.severity ) )
185 return retv;
186
188 {
189 switch( aLine.severity )
190 {
192 retv = wxS( "<font color=#F04040 size=3>" ) + _( "Error:" ) + wxS( " </font>" )
193 wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
194 break;
196 retv = wxS( "<font size=3>" ) + _( "Warning:" ) + wxS( " " ) + aLine.message + wxS( "</font><br>" );
197 break;
199 retv = wxS( "<font color=#909090 size=3>" ) + aLine.message + wxS( "</font><br>" );
200 break;
202 retv = wxS( "<font color=#60D060 size=3>" ) + aLine.message + wxS( "</font><br>" );
203 break;
204 default:
205 retv = wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
206 }
207 }
208 else
209 {
210 switch( aLine.severity )
211 {
213 retv = wxS( "<font color=#D00000 size=3>" ) + _( "Error:" ) + wxS( " </font>" )
214 wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
215 break;
217 retv = wxS( "<font size=3>" ) + _( "Warning:" ) + wxS( " " ) + aLine.message + wxS( "</font><br>" );
218 break;
220 retv = wxS( "<font color=#808080 size=3>" ) + aLine.message + wxS( "</font><br>" );
221 break;
223 retv = wxS( "<font color=#008000 size=3>" ) + aLine.message + wxS( "</font><br>" );
224 break;
225 default:
226 retv = wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
227 }
228 }
229
230 // wxHtmlWindow fails to do correct baseline alignment between Japanese/Chinese cells and
231 // Roman cells. This keeps the line in a single cell.
232 retv.Replace( wxS( " " ), wxS( "&nbsp;" ) );
233
234 return retv;
235}
236
237
239{
240 switch( aLine.severity )
241 {
242 case RPT_SEVERITY_ERROR: return _( "Error:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
243 case RPT_SEVERITY_WARNING: return _( "Warning:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
244 case RPT_SEVERITY_INFO: return _( "Info:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
245 default: return aLine.message + wxT( "\n" );
246 }
247}
248
249
250void WX_HTML_REPORT_PANEL::onRightClick( wxMouseEvent& event )
251{
252 wxMenu popup;
253 popup.Append( wxID_COPY, "Copy" );
254 PopupMenu( &popup );
255}
256
257
258void WX_HTML_REPORT_PANEL::onMenuEvent( wxMenuEvent& event )
259{
260 if( event.GetId() == wxID_COPY )
261 {
262 wxLogNull doNotLog; // disable logging of failed clipboard actions
263
264 if( wxTheClipboard->Open() )
265 {
266 bool primarySelection = wxTheClipboard->IsUsingPrimarySelection();
267 wxTheClipboard->UsePrimarySelection( false ); // required to use the main clipboard
268 wxTheClipboard->SetData( new wxTextDataObject( m_htmlView->SelectionToText() ) );
269 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
270 wxTheClipboard->Close();
271 wxTheClipboard->UsePrimarySelection( primarySelection );
272 }
273 }
274}
275
276
277// Don't globally define this; different facilities use different definitions of "ALL"
280
281
282void WX_HTML_REPORT_PANEL::onCheckBoxShowAll( wxCommandEvent& event )
283{
284 if( event.IsChecked() )
286 else
288
290 Flush( true );
291}
292
293
295{
301}
302
303
305{
306 if( event.IsChecked() )
308 else
309 m_severities &= ~RPT_SEVERITY_WARNING;
310
312 Flush( true );
313}
314
315
317{
318 if( event.IsChecked() )
320 else
321 m_severities &= ~RPT_SEVERITY_ERROR;
322
324 Flush( true );
325}
326
327
328void WX_HTML_REPORT_PANEL::onCheckBoxShowInfos( wxCommandEvent& event )
329{
330 if( event.IsChecked() )
332 else
333 m_severities &= ~RPT_SEVERITY_INFO;
334
336 Flush( true );
337}
338
339
341{
342 if( event.IsChecked() )
344 else
345 m_severities &= ~RPT_SEVERITY_ACTION;
346
348 Flush( true );
349}
350
351
352void WX_HTML_REPORT_PANEL::onBtnSaveToFile( wxCommandEvent& event )
353{
354 wxFileName fn;
355
356 if( m_reportFileName.empty() )
357 {
358 fn = wxT( "report.txt" );
359
360 if( KIWAY_HOLDER* parent = dynamic_cast<KIWAY_HOLDER*>( m_parent ) )
361 fn.SetPath( parent->Prj().GetProjectPath() );
362 }
363 else
364 {
365 fn = m_reportFileName;
366 }
367
368 wxWindow* topLevelParent = wxGetTopLevelParent( this );
369
370 wxFileDialog dlg( topLevelParent, _( "Save Report File" ), fn.GetPath(), fn.GetFullName(),
371 FILEEXT::TextFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
372
373 if( dlg.ShowModal() != wxID_OK )
374 return;
375
376 fn = dlg.GetPath();
377
378 if( fn.GetExt().IsEmpty() )
379 fn.SetExt( "txt" );
380
381 wxFFile f( fn.GetFullPath(), "wb" );
382
383 if( !f.IsOpened() )
384 {
385 wxString msg;
386
387 msg.Printf( _( "Cannot write report to file '%s'." ),
388 fn.GetFullPath().GetData() );
389 wxMessageBox( msg, _( "File save error" ), wxOK | wxICON_ERROR,
390 wxGetTopLevelParent( this ) );
391 return;
392 }
393
394 for( REPORT_LINES section : { m_reportHead, m_report, m_reportTail } )
395 {
396 for( const REPORT_LINE& l : section )
397 {
398 wxString s = generatePlainText( l );
399
401 f.Write( s );
402 }
403 }
404
405 m_reportFileName = fn.GetFullPath();
406 f.Close();
407}
408
409
411{
412 m_report.clear();
413 m_reportHead.clear();
414 m_reportTail.clear();
415}
416
417
418void WX_HTML_REPORT_PANEL::SetLabel( const wxString& aLabel )
419{
420 m_box->GetStaticBox()->SetLabel( aLabel );
421}
422
423
425{
426 if( aSeverities < 0 )
428 else
429 m_severities = aSeverities;
430
432}
433
434
436{
437 return m_severities;
438}
439
440
441void WX_HTML_REPORT_PANEL::SetFileName( const wxString& aReportFileName )
442{
443 m_reportFileName = aReportFileName;
444}
445
446
448{
449 return ( m_reportFileName );
450}
451
452
454{
455 switch( aSeverity )
456 {
457 case RPT_SEVERITY_INFO: m_checkBoxShowInfos->SetValue( aValue ); break;
458 case RPT_SEVERITY_ACTION: m_checkBoxShowActions->SetValue( aValue ); break;
459 case RPT_SEVERITY_WARNING: m_checkBoxShowWarnings->SetValue( aValue ); break;
460 default: m_checkBoxShowErrors->SetValue( aValue ); break;
461 }
462}
463
464
465REPORTER& WX_HTML_PANEL_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
466{
467 wxCHECK_MSG( m_panel != nullptr, *this,
468 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
469
470 m_panel->Report( aText, aSeverity );
471 return *this;
472}
473
474
475REPORTER& WX_HTML_PANEL_REPORTER::ReportTail( const wxString& aText, SEVERITY aSeverity )
476{
477 wxCHECK_MSG( m_panel != nullptr, *this,
478 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
479
480 m_panel->Report( aText, aSeverity, LOC_TAIL );
481 return *this;
482}
483
484
485REPORTER& WX_HTML_PANEL_REPORTER::ReportHead( const wxString& aText, SEVERITY aSeverity )
486{
487 wxCHECK_MSG( m_panel != nullptr, *this,
488 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
489
490 m_panel->Report( aText, aSeverity, LOC_HEAD );
491 return *this;
492}
493
494
496{
497 // Check just for errors and warnings for compatibility
499}
500
501
502bool WX_HTML_PANEL_REPORTER::HasMessageOfSeverity( int aSeverityMask ) const
503{
504 return m_panel->Count( aSeverityMask ) > 0;
505}
bool SetPage(const wxString &aSource) override
Definition: html_window.cpp:50
bool AppendToPage(const wxString &aSource)
Definition: html_window.cpp:69
A mix in class which holds the location of a wxWindow's KIWAY.
Definition: kiway_holder.h:39
void UpdateNumber(int aNumber, SEVERITY aSeverity)
Update the number displayed on the badge.
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:72
LOCATION
Location where the message is to be reported.
Definition: reporter.h:80
@ LOC_TAIL
Definition: reporter.h:83
@ LOC_HEAD
Definition: reporter.h:81
bool HasMessageOfSeverity(int aSeverityMask) const override
Returns true if the reporter has one or more messages matching the specified severity mask.
bool HasMessage() const override
Returns true if the reporter client is non-empty.
REPORTER & ReportTail(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Places the report at the end of the list, for objects that support report ordering.
REPORTER & ReportHead(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Places the report at the beginning of the list for objects that support ordering.
REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) override
Report a string with a given severity.
WX_HTML_REPORT_PANEL * m_panel
Class WX_HTML_REPORT_PANEL_BASE.
void Clear()
return the number of messages matching the given severity mask.
void onCheckBoxShowErrors(wxCommandEvent &event) override
wxString m_reportFileName
defaults to the not very useful /bin/report.txt
void onThemeChanged(wxSysColourChangedEvent &aEvent)
void onCheckBoxShowActions(wxCommandEvent &event) override
REPORT_LINES m_report
copy of the report, stored for filtering
void onRightClick(wxMouseEvent &event) override
int m_severities
message severities to display (mask)
int Count(int severityMask)
sets the frame label
void SetLazyUpdate(bool aLazyUpdate)
Forces updating the HTML page, after the report is built in lazy mode If aSort = true,...
WX_HTML_PANEL_REPORTER m_reporter
void SetLabel(const wxString &aLabel) override
Sets the lazy update.
std::vector< REPORT_LINE > REPORT_LINES
void MsgPanelSetMinSize(const wxSize &aMinSize)
returns the reporter object that reports to this panel
void SetFileName(const wxString &aReportFileName)
wxString generateHtml(const REPORT_LINE &aLine)
void Report(const wxString &aText, SEVERITY aSeverity, REPORTER::LOCATION aLocation=REPORTER::LOC_BODY)
Reports the string.
void onCheckBoxShowAll(wxCommandEvent &event) override
void SetShowSeverity(SEVERITY aSeverity, bool aValue)
Set the report full file name to the string.
void SetVisibleSeverities(int aSeverities)
void Flush(bool aSort=false)
Set the visible severity filter.
void onCheckBoxShowWarnings(wxCommandEvent &event) override
void onMenuEvent(wxMenuEvent &event)
wxString generatePlainText(const REPORT_LINE &aLine)
void onBtnSaveToFile(wxCommandEvent &event) override
REPORT_LINES m_reportHead
... and at the beginning, regardless of sorting
~WX_HTML_REPORT_PANEL()
Set the min size of the area which displays html messages:
void onCheckBoxShowInfos(wxCommandEvent &event) override
REPORT_LINES m_reportTail
Lines to print at the end, regardless of sorting.
WX_HTML_REPORT_PANEL(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(500, 300), long style=wxTAB_TRAVERSAL)
#define _(s)
static wxString TextFileWildcard()
bool IsDarkTheme()
Determine if the desktop interface is currently using a dark theme or a light theme.
Definition: wxgtk/ui.cpp:48
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:154
SEVERITY
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
bool ConvertSmartQuotesAndDashes(wxString *aString)
Convert curly quotes and em/en dashes to straight quotes and dashes.
Definition of file extensions used in Kicad.
static int RPT_SEVERITY_ALL