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
57{
58}
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
77{
78 return m_reporter;
79}
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 {
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 );
146
147 count = 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 CallAfter(
276 [&]()
277 {
279 } );
280
281 Flush( true );
282 event.Skip();
283}
284
285
286void WX_HTML_REPORT_PANEL::onBtnSaveToFile( wxCommandEvent& event )
287{
288 wxFileName fn;
289
290 if( m_reportFileName.empty() )
291 {
292 fn = wxT( "report.txt" );
293
294 if( KIWAY_HOLDER* parent = dynamic_cast<KIWAY_HOLDER*>( m_parent ) )
295 fn.SetPath( parent->Prj().GetProjectPath() );
296 }
297 else
298 {
299 fn = m_reportFileName;
300 }
301
302 wxWindow* topLevelParent = wxGetTopLevelParent( this );
303
304 wxFileDialog dlg( topLevelParent, _( "Save Report File" ), fn.GetPath(), fn.GetFullName(),
305 FILEEXT::TextFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
306
307 if( dlg.ShowModal() != wxID_OK )
308 return;
309
310 fn = dlg.GetPath();
311
312 if( fn.GetExt().IsEmpty() )
313 fn.SetExt( "txt" );
314
315 wxFFile f( fn.GetFullPath(), "wb" );
316
317 if( !f.IsOpened() )
318 {
319 wxMessageBox( wxString::Format( _( "Cannot write report to file '%s'." ), fn.GetFullPath().GetData() ),
320 _( "File save error" ), wxOK | wxICON_ERROR, wxGetTopLevelParent( this ) );
321 return;
322 }
323
324 for( const REPORT_LINES& section : { m_reportHead, m_report, m_reportTail } )
325 {
326 for( const REPORT_LINE& l : section )
327 {
328 wxString s = generatePlainText( l );
329
331 f.Write( s );
332 }
333 }
334
335 m_reportFileName = fn.GetFullPath();
336 f.Close();
337}
338
339
341{
342 m_report.clear();
343 m_reportHead.clear();
344 m_reportTail.clear();
345}
346
347
348void WX_HTML_REPORT_PANEL::SetLabel( const wxString& aLabel )
349{
350 m_box->GetStaticBox()->SetLabel( aLabel );
351}
352
353
355{
356 int severities = 0;
357
358 if( m_checkBoxShowErrors->GetValue() )
359 severities |= RPT_SEVERITY_ERROR;
360
361 if( m_checkBoxShowWarnings->GetValue() )
362 severities |= RPT_SEVERITY_WARNING;
363
364 if( m_checkBoxShowActions->GetValue() )
365 severities |= RPT_SEVERITY_ACTION;
366
367 if( m_checkBoxShowInfos->GetValue() )
368 severities |= RPT_SEVERITY_INFO;
369
370 return severities;
371}
372
373
374REPORTER& WX_HTML_PANEL_REPORTER::Report( const wxString& aText, SEVERITY aSeverity )
375{
376 REPORTER::Report( aText, aSeverity );
377
378 wxCHECK_MSG( m_panel != nullptr, *this,
379 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
380
381 m_panel->Report( aText, aSeverity );
382 return *this;
383}
384
385
386REPORTER& WX_HTML_PANEL_REPORTER::ReportTail( const wxString& aText, SEVERITY aSeverity )
387{
388 REPORTER::ReportTail( aText, aSeverity );
389
390 wxCHECK_MSG( m_panel != nullptr, *this,
391 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
392
393 m_panel->Report( aText, aSeverity, LOC_TAIL );
394 return *this;
395}
396
397
398REPORTER& WX_HTML_PANEL_REPORTER::ReportHead( const wxString& aText, SEVERITY aSeverity )
399{
400 REPORTER::ReportHead( aText, aSeverity );
401
402 wxCHECK_MSG( m_panel != nullptr, *this,
403 wxT( "No WX_HTML_REPORT_PANEL object defined in WX_HTML_PANEL_REPORTER." ) );
404
405 m_panel->Report( aText, aSeverity, LOC_HEAD );
406 return *this;
407}
408
409
411{
412 // Check just for errors and warnings for compatibility
414}
415
416
417bool WX_HTML_PANEL_REPORTER::HasMessageOfSeverity( int aSeverityMask ) const
418{
419 return m_panel->Count( aSeverityMask ) > 0;
420}
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: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
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.
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)
Definition: ui_common.cpp:156
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