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, const wxSize& size,
41 long style ) :
42 WX_HTML_REPORT_PANEL_BASE( parent, id, pos, size, style ),
43 m_reporter( this ),
44 m_lazyUpdate( false )
45{
47 Flush();
48
49 Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( WX_HTML_REPORT_PANEL::onMenuEvent ), nullptr, this );
50
51 m_htmlView->Bind( wxEVT_SYS_COLOUR_CHANGED, wxSysColourChangedEventHandler( WX_HTML_REPORT_PANEL::onThemeChanged ),
52 this );
53}
54
55
59
60
61void WX_HTML_REPORT_PANEL::onThemeChanged( wxSysColourChangedEvent &aEvent )
62{
63 Flush();
64
65 aEvent.Skip();
66}
67
68
69void WX_HTML_REPORT_PANEL::MsgPanelSetMinSize( const wxSize& aMinSize )
70{
71 m_fgSizer->SetMinSize( aMinSize );
72 GetSizer()->SetSizeHints( this );
73}
74
75
80
81
82void WX_HTML_REPORT_PANEL::Report( const wxString& aText, SEVERITY aSeverity, REPORTER::LOCATION aLocation )
83{
84 REPORT_LINE line;
85 line.message = aText;
86 line.severity = aSeverity;
87
88 if( aLocation == REPORTER::LOC_HEAD )
89 m_reportHead.push_back( line );
90 else if( aLocation == REPORTER::LOC_TAIL )
91 m_reportTail.push_back( line );
92 else
93 m_report.push_back( line );
94
95 if( !m_lazyUpdate )
96 {
97 m_htmlView->AppendToPage( generateHtml( line ) );
99 }
100}
101
102
104{
105 wxString html;
106
107 if( aSort )
108 {
109 std::sort( m_report.begin(), m_report.end(),
110 []( const REPORT_LINE& a, const REPORT_LINE& b)
111 {
112 return a.severity < b.severity;
113 });
114 }
115
116 for( const auto& line : m_reportHead )
117 html += generateHtml( line );
118
119 for( const auto& line : m_report )
120 html += generateHtml( line );
121
122 for( const auto& line : m_reportTail )
123 html += generateHtml( line );
124
125 m_htmlView->SetPage( html );
127}
128
129
131{
132 int x, y, xUnit, yUnit;
133
134 m_htmlView->GetVirtualSize( &x, &y );
135 m_htmlView->GetScrollPixelsPerUnit( &xUnit, &yUnit );
136 m_htmlView->Scroll( 0, y / yUnit );
137
138 updateBadges();
139}
140
141
143{
144 int count = Count(RPT_SEVERITY_ERROR );
145 m_errorsBadge->UpdateNumber( count, RPT_SEVERITY_ERROR );
146
147 count = Count(RPT_SEVERITY_WARNING );
148 m_warningsBadge->UpdateNumber( count, RPT_SEVERITY_WARNING );
149}
150
151
152int WX_HTML_REPORT_PANEL::Count( int severityMask )
153{
154 int count = 0;
155
156 for( const auto& reportLineArray : { m_report, m_reportHead, m_reportTail } )
157 {
158 for( const REPORT_LINE& reportLine : reportLineArray )
159 {
160 if( severityMask & reportLine.severity )
161 count++;
162 }
163 }
164
165 return count;
166}
167
168
170{
171 wxString retv;
172
173 if( !( GetVisibleSeverities() & aLine.severity ) )
174 return retv;
175
177 {
178 switch( aLine.severity )
179 {
181 retv = wxS( "<font color=#F04040 size=3>" ) + _( "Error:" ) + wxS( " </font>" )
182 + wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
183 break;
185 retv = wxS( "<font size=3>" ) + _( "Warning:" ) + wxS( " " ) + aLine.message
186 + wxS( "</font><br>" );
187 break;
189 retv = wxS( "<font color=#909090 size=3>" ) + aLine.message + wxS( "</font><br>" );
190 break;
192 retv = wxS( "<font color=#60D060 size=3>" ) + aLine.message + wxS( "</font><br>" );
193 break;
194 default:
195 retv = wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
196 }
197 }
198 else
199 {
200 switch( aLine.severity )
201 {
203 retv = wxS( "<font color=#D00000 size=3>" ) + _( "Error:" ) + wxS( " </font>" )
204 + wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
205 break;
207 retv = wxS( "<font size=3>" ) + _( "Warning:" ) + wxS( " " ) + aLine.message
208 + wxS( "</font><br>" );
209 break;
211 retv = wxS( "<font color=#808080 size=3>" ) + aLine.message + wxS( "</font><br>" );
212 break;
214 retv = wxS( "<font color=#008000 size=3>" ) + aLine.message + wxS( "</font><br>" );
215 break;
216 default:
217 retv = wxS( "<font size=3>" ) + aLine.message + wxS( "</font><br>" );
218 }
219 }
220
221 // wxHtmlWindow fails to do correct baseline alignment between Japanese/Chinese cells and
222 // Roman cells. This keeps the line in a single cell.
223 retv.Replace( wxS( " " ), wxS( "&nbsp;" ) );
224
225 return retv;
226}
227
228
230{
231 switch( aLine.severity )
232 {
233 case RPT_SEVERITY_ERROR: return _( "Error:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
234 case RPT_SEVERITY_WARNING: return _( "Warning:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
235 case RPT_SEVERITY_INFO: return _( "Info:" ) + wxS( " " ) + aLine.message + wxT( "\n" );
236 default: return aLine.message + wxT( "\n" );
237 }
238}
239
240
241void WX_HTML_REPORT_PANEL::onRightClick( wxMouseEvent& event )
242{
243 wxMenu popup;
244 popup.Append( wxID_COPY, "Copy" );
245 PopupMenu( &popup );
246}
247
248
249void WX_HTML_REPORT_PANEL::onMenuEvent( wxMenuEvent& event )
250{
251 if( event.GetId() == wxID_COPY )
252 {
253 wxLogNull doNotLog; // disable logging of failed clipboard actions
254
255 if( wxTheClipboard->Open() )
256 {
257 bool primarySelection = wxTheClipboard->IsUsingPrimarySelection();
258 wxTheClipboard->UsePrimarySelection( false ); // required to use the main clipboard
259 wxTheClipboard->SetData( new wxTextDataObject( m_htmlView->SelectionToText() ) );
260 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
261 wxTheClipboard->Close();
262 wxTheClipboard->UsePrimarySelection( primarySelection );
263 }
264 }
265}
266
267
268// Don't globally define this; different facilities use different definitions of "ALL"
271
272
273void WX_HTML_REPORT_PANEL::onCheckBox( wxCommandEvent& event )
274{
275 if( event.GetEventObject() == m_checkBoxShowAll )
276 {
277 m_checkBoxShowErrors->SetValue( true );
278 m_checkBoxShowWarnings->SetValue( event.IsChecked() );
279 m_checkBoxShowInfos->SetValue( event.IsChecked() );
280 m_checkBoxShowActions->SetValue( event.IsChecked() );
281 }
282
283 CallAfter(
284 [&]()
285 {
287 } );
288
289 Flush( true );
290 event.Skip();
291}
292
293
294void WX_HTML_REPORT_PANEL::onBtnSaveToFile( wxCommandEvent& event )
295{
296 wxFileName fn;
297
298 if( m_reportFileName.empty() )
299 {
300 fn = wxT( "report.txt" );
301
302 if( KIWAY_HOLDER* parent = dynamic_cast<KIWAY_HOLDER*>( m_parent ) )
303 fn.SetPath( parent->Prj().GetProjectPath() );
304 }
305 else
306 {
307 fn = m_reportFileName;
308 }
309
310 wxWindow* topLevelParent = wxGetTopLevelParent( this );
311
312 wxFileDialog dlg( topLevelParent, _( "Save Report File" ), fn.GetPath(), fn.GetFullName(),
313 FILEEXT::TextFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
314
315 if( dlg.ShowModal() != wxID_OK )
316 return;
317
318 fn = dlg.GetPath();
319
320 if( fn.GetExt().IsEmpty() )
321 fn.SetExt( "txt" );
322
323 wxFFile f( fn.GetFullPath(), "wb" );
324
325 if( !f.IsOpened() )
326 {
327 wxMessageBox( wxString::Format( _( "Cannot write report to file '%s'." ), fn.GetFullPath().GetData() ),
328 _( "File save error" ), wxOK | wxICON_ERROR, wxGetTopLevelParent( this ) );
329 return;
330 }
331
332 for( const REPORT_LINES& section : { m_reportHead, m_report, m_reportTail } )
333 {
334 for( const REPORT_LINE& l : section )
335 {
336 wxString s = generatePlainText( l );
337
339 f.Write( s );
340 }
341 }
342
343 m_reportFileName = fn.GetFullPath();
344 f.Close();
345}
346
347
349{
350 m_report.clear();
351 m_reportHead.clear();
352 m_reportTail.clear();
353}
354
355
356void WX_HTML_REPORT_PANEL::SetLabel( const wxString& aLabel )
357{
358 m_box->GetStaticBox()->SetLabel( aLabel );
359}
360
361
363{
364 int severities = 0;
365
366 if( m_checkBoxShowErrors->GetValue() )
367 severities |= RPT_SEVERITY_ERROR;
368
369 if( m_checkBoxShowWarnings->GetValue() )
370 severities |= RPT_SEVERITY_WARNING;
371
372 if( m_checkBoxShowActions->GetValue() )
373 severities |= RPT_SEVERITY_ACTION;
374
375 if( m_checkBoxShowInfos->GetValue() )
376 severities |= RPT_SEVERITY_INFO;
377
378 return severities;
379}
380
381
382REPORTER& WX_HTML_PANEL_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
383{
384 REPORTER::Report( aText, aSeverity );
385
386 wxCHECK_MSG( m_panel != nullptr, *this,
387 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
388
389 m_panel->Report( aText, aSeverity );
390 return *this;
391}
392
393
394REPORTER& WX_HTML_PANEL_REPORTER::ReportTail( const wxString& aText, SEVERITY aSeverity )
395{
396 REPORTER::ReportTail( aText, aSeverity );
397
398 wxCHECK_MSG( m_panel != nullptr, *this,
399 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
400
401 m_panel->Report( aText, aSeverity, LOC_TAIL );
402 return *this;
403}
404
405
406REPORTER& WX_HTML_PANEL_REPORTER::ReportHead( const wxString& aText, SEVERITY aSeverity )
407{
408 REPORTER::ReportHead( aText, aSeverity );
409
410 wxCHECK_MSG( m_panel != nullptr, *this,
411 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
412
413 m_panel->Report( aText, aSeverity, LOC_HEAD );
414 return *this;
415}
416
417
419{
420 // Check just for errors and warnings for compatibility
422}
423
424
425bool WX_HTML_PANEL_REPORTER::HasMessageOfSeverity( int aSeverityMask ) const
426{
427 return m_panel->Count( aSeverityMask ) > 0;
428}
A mix in class which holds the location of a wxWindow's KIWAY.
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
LOCATION
Location where the message is to be reported.
Definition reporter.h:88
@ LOC_TAIL
Definition reporter.h:91
@ LOC_HEAD
Definition reporter.h:89
virtual REPORTER & ReportHead(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Places the report at the beginning of the list for objects that support ordering.
Definition reporter.h:121
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Definition reporter.h:102
virtual REPORTER & ReportTail(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Places the report at the end of the list, for objects that support report ordering.
Definition reporter.h:112
REPORTER()
Definition reporter.h:75
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 any messages were reported.
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
WX_HTML_REPORT_PANEL_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
void Clear()
Clears the report panel.
wxString m_reportFileName
defaults to the not very useful /bin/report.txt
void onThemeChanged(wxSysColourChangedEvent &aEvent)
REPORT_LINES m_report
copy of the report, stored for filtering
void onRightClick(wxMouseEvent &event) override
int Count(int severityMask)
Return the number of messages matching the given severity mask.
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.
wxString generateHtml(const REPORT_LINE &aLine)
void Report(const wxString &aText, SEVERITY aSeverity, REPORTER::LOCATION aLocation=REPORTER::LOC_BODY)
Report the string.
void Flush(bool aSort=false)
Force updating the HTML page, after the report is built in lazy mode If aSort = true,...
void onMenuEvent(wxMenuEvent &event)
wxString generatePlainText(const REPORT_LINE &aLine)
void onCheckBox(wxCommandEvent &event) override
void onBtnSaveToFile(wxCommandEvent &event) override
REPORT_LINES m_reportHead
... and at the beginning, regardless of sorting
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)
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