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 The 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
197 + wxS( "</font><br>" );
198 break;
200 retv = wxS( "<font color=#909090 size=3>" ) + aLine.message + wxS( "</font><br>" );
201 break;
203 retv = wxS( "<font color=#60D060 size=3>" ) + aLine.message + wxS( "</font><br>" );
204 break;
205 default:
206 retv = wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
207 }
208 }
209 else
210 {
211 switch( aLine.severity )
212 {
214 retv = wxS( "<font color=#D00000 size=3>" ) + _( "Error:" ) + wxS( " </font>" )
215 wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
216 break;
218 retv = wxS( "<font size=3>" ) + _( "Warning:" ) + wxS( " " ) + aLine.message
219 + wxS( "</font><br>" );
220 break;
222 retv = wxS( "<font color=#808080 size=3>" ) + aLine.message + wxS( "</font><br>" );
223 break;
225 retv = wxS( "<font color=#008000 size=3>" ) + aLine.message + wxS( "</font><br>" );
226 break;
227 default:
228 retv = wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
229 }
230 }
231
232 // wxHtmlWindow fails to do correct baseline alignment between Japanese/Chinese cells and
233 // Roman cells. This keeps the line in a single cell.
234 retv.Replace( wxS( " " ), wxS( "&nbsp;" ) );
235
236 return retv;
237}
238
239
241{
242 switch( aLine.severity )
243 {
244 case RPT_SEVERITY_ERROR: return _( "Error:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
245 case RPT_SEVERITY_WARNING: return _( "Warning:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
246 case RPT_SEVERITY_INFO: return _( "Info:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
247 default: return aLine.message + wxT( "\n" );
248 }
249}
250
251
252void WX_HTML_REPORT_PANEL::onRightClick( wxMouseEvent& event )
253{
254 wxMenu popup;
255 popup.Append( wxID_COPY, "Copy" );
256 PopupMenu( &popup );
257}
258
259
260void WX_HTML_REPORT_PANEL::onMenuEvent( wxMenuEvent& event )
261{
262 if( event.GetId() == wxID_COPY )
263 {
264 wxLogNull doNotLog; // disable logging of failed clipboard actions
265
266 if( wxTheClipboard->Open() )
267 {
268 bool primarySelection = wxTheClipboard->IsUsingPrimarySelection();
269 wxTheClipboard->UsePrimarySelection( false ); // required to use the main clipboard
270 wxTheClipboard->SetData( new wxTextDataObject( m_htmlView->SelectionToText() ) );
271 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
272 wxTheClipboard->Close();
273 wxTheClipboard->UsePrimarySelection( primarySelection );
274 }
275 }
276}
277
278
279// Don't globally define this; different facilities use different definitions of "ALL"
282
283
284void WX_HTML_REPORT_PANEL::onCheckBoxShowAll( wxCommandEvent& event )
285{
286 if( event.IsChecked() )
288 else
290
292 Flush( true );
293}
294
295
297{
303}
304
305
307{
308 if( event.IsChecked() )
310 else
311 m_severities &= ~RPT_SEVERITY_WARNING;
312
314 Flush( true );
315}
316
317
319{
320 if( event.IsChecked() )
322 else
323 m_severities &= ~RPT_SEVERITY_ERROR;
324
326 Flush( true );
327}
328
329
330void WX_HTML_REPORT_PANEL::onCheckBoxShowInfos( wxCommandEvent& event )
331{
332 if( event.IsChecked() )
334 else
335 m_severities &= ~RPT_SEVERITY_INFO;
336
338 Flush( true );
339}
340
341
343{
344 if( event.IsChecked() )
346 else
347 m_severities &= ~RPT_SEVERITY_ACTION;
348
350 Flush( true );
351}
352
353
354void WX_HTML_REPORT_PANEL::onBtnSaveToFile( wxCommandEvent& event )
355{
356 wxFileName fn;
357
358 if( m_reportFileName.empty() )
359 {
360 fn = wxT( "report.txt" );
361
362 if( KIWAY_HOLDER* parent = dynamic_cast<KIWAY_HOLDER*>( m_parent ) )
363 fn.SetPath( parent->Prj().GetProjectPath() );
364 }
365 else
366 {
367 fn = m_reportFileName;
368 }
369
370 wxWindow* topLevelParent = wxGetTopLevelParent( this );
371
372 wxFileDialog dlg( topLevelParent, _( "Save Report File" ), fn.GetPath(), fn.GetFullName(),
373 FILEEXT::TextFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
374
375 if( dlg.ShowModal() != wxID_OK )
376 return;
377
378 fn = dlg.GetPath();
379
380 if( fn.GetExt().IsEmpty() )
381 fn.SetExt( "txt" );
382
383 wxFFile f( fn.GetFullPath(), "wb" );
384
385 if( !f.IsOpened() )
386 {
387 wxString msg;
388
389 msg.Printf( _( "Cannot write report to file '%s'." ),
390 fn.GetFullPath().GetData() );
391 wxMessageBox( msg, _( "File save error" ), wxOK | wxICON_ERROR,
392 wxGetTopLevelParent( this ) );
393 return;
394 }
395
396 for( REPORT_LINES section : { m_reportHead, m_report, m_reportTail } )
397 {
398 for( const REPORT_LINE& l : section )
399 {
400 wxString s = generatePlainText( l );
401
403 f.Write( s );
404 }
405 }
406
407 m_reportFileName = fn.GetFullPath();
408 f.Close();
409}
410
411
413{
414 m_report.clear();
415 m_reportHead.clear();
416 m_reportTail.clear();
417}
418
419
420void WX_HTML_REPORT_PANEL::SetLabel( const wxString& aLabel )
421{
422 m_box->GetStaticBox()->SetLabel( aLabel );
423}
424
425
427{
428 if( aSeverities < 0 )
430 else
431 m_severities = aSeverities;
432
434}
435
436
438{
439 return m_severities;
440}
441
442
443void WX_HTML_REPORT_PANEL::SetFileName( const wxString& aReportFileName )
444{
445 m_reportFileName = aReportFileName;
446}
447
448
450{
451 return ( m_reportFileName );
452}
453
454
456{
457 switch( aSeverity )
458 {
459 case RPT_SEVERITY_INFO: m_checkBoxShowInfos->SetValue( aValue ); break;
460 case RPT_SEVERITY_ACTION: m_checkBoxShowActions->SetValue( aValue ); break;
461 case RPT_SEVERITY_WARNING: m_checkBoxShowWarnings->SetValue( aValue ); break;
462 default: m_checkBoxShowErrors->SetValue( aValue ); break;
463 }
464}
465
466
467REPORTER& WX_HTML_PANEL_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
468{
469 wxCHECK_MSG( m_panel != nullptr, *this,
470 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
471
472 m_panel->Report( aText, aSeverity );
473 return *this;
474}
475
476
477REPORTER& WX_HTML_PANEL_REPORTER::ReportTail( const wxString& aText, SEVERITY aSeverity )
478{
479 wxCHECK_MSG( m_panel != nullptr, *this,
480 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
481
482 m_panel->Report( aText, aSeverity, LOC_TAIL );
483 return *this;
484}
485
486
487REPORTER& WX_HTML_PANEL_REPORTER::ReportHead( const wxString& aText, SEVERITY aSeverity )
488{
489 wxCHECK_MSG( m_panel != nullptr, *this,
490 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
491
492 m_panel->Report( aText, aSeverity, LOC_HEAD );
493 return *this;
494}
495
496
498{
499 // Check just for errors and warnings for compatibility
501}
502
503
504bool WX_HTML_PANEL_REPORTER::HasMessageOfSeverity( int aSeverityMask ) const
505{
506 return m_panel->Count( aSeverityMask ) > 0;
507}
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()
Clears the report panel.
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)
Return the number of messages matching the given severity mask.
void SetLazyUpdate(bool aLazyUpdate)
Set the lazy update.
WX_HTML_PANEL_REPORTER m_reporter
void SetLabel(const wxString &aLabel) override
Set the frame label.
std::vector< REPORT_LINE > REPORT_LINES
void MsgPanelSetMinSize(const wxSize &aMinSize)
Set the min size of the area which displays html messages.
void SetFileName(const wxString &aReportFileName)
Set the report full file name to the string.
wxString generateHtml(const REPORT_LINE &aLine)
void Report(const wxString &aText, SEVERITY aSeverity, REPORTER::LOCATION aLocation=REPORTER::LOC_BODY)
Report the string.
void onCheckBoxShowAll(wxCommandEvent &event) override
void SetShowSeverity(SEVERITY aSeverity, bool aValue)
void SetVisibleSeverities(int aSeverities)
Set the visible severity filter.
void Flush(bool aSort=false)
Force updating the HTML page, after the report is built in lazy mode If aSort = true,...
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
void onCheckBoxShowInfos(wxCommandEvent &event) override
REPORTER & Reporter()
Return the reporter object that reports to this panel.
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:155
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