1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
5  * Copyright (C) 2013-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
23  */
24 
25 #ifndef _REPORTER_H_
26 #define _REPORTER_H_
27 
28 #include <memory>
29 
30 #include <eda_units.h>
31 #include <widgets/report_severity.h>
32 
33 /**
34  * @file reporter.h
35  * @author Wayne Stambaugh
36  * @note A special thanks to Dick Hollenbeck who came up with the idea that inspired
37  *       me to write this.
38  * @warning Do not add any dependencies to wxWidgets (or any other third party UI library )
39  *          to the REPORTER object.  All wxWidgets objects should be defined by pointer or
40  *          reference and forward declared so that using reporters in low level KiCad objects
41  *          will not require pulling in wxWidgets to building them.
42  */
43 
44 class wxString;
45 class wxStatusBar;
46 class wxTextCtrl;
47 class WX_HTML_REPORT_PANEL;
48 class WX_INFOBAR;
49 
50 
51 /**
52  * A pure virtual class used to derive REPORTER objects from.
53  *
54  * The purpose of the REPORTER object is to offer a way for a procedural function
55  * to report multiple errors without having to:
56  * <ul>
57  * <li> know too much about the caller's UI, i.e. wx. </li>
58  * <li> stop after the first error </li>
59  * </ul>
60  * the reporter has 4 severity levels (flags) tagging the messages:
61  *  - information
62  *  - warning
63  *  - error
64  *  - action (i.e. indication of changes - add component, change footprint, etc. )
65  *
66  * They are indicators for the message formatting and displaying code,
67  * filtering is not made here.
68  */
69 
70 class REPORTER
71 {
72 public:
73     /**
74      * Location where the message is to be reported.
75      * LOC_HEAD messages are printed before all others (typically intro messages)
76      * LOC_BODY messages are printed in the middle
77      * LOC_TAIL messages are printed after all others (typically status messages)
78      */
79     enum LOCATION {
80         LOC_HEAD = 0,
81         LOC_BODY,
82         LOC_TAIL
83     };
84 
85     /**
86      * Report a string with a given severity.
87      *
88      * @param aText is the string to report.
89      * @param aSeverity is an indicator ( RPT_UNDEFINED, RPT_INFO, RPT_WARNING, RPT_ERROR,
90      *                  RPT_ACTION ) used to filter and format messages
91      */
92 
93     virtual REPORTER& Report( const wxString& aText,
94                               SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) = 0;
95 
96     /**
97      * Places the report at the end of the list, for objects that support report ordering
98      */
99     virtual REPORTER& ReportTail( const wxString& aText,
100                                   SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED )
101     {
102         return Report( aText, aSeverity );
103     }
104 
105     /**
106      * Places the report at the beginning of the list for objects that support ordering.
107      */
108     virtual REPORTER& ReportHead( const wxString& aText,
109                                   SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED )
110     {
111         return Report( aText, aSeverity );
112     }
113 
114     REPORTER& Report( const char* aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED );
115 
116     REPORTER& operator <<( const wxString& aText ) { return Report( aText ); }
117 
118     /**
119      * Returns true if the reporter client is non-empty.
120      */
121     virtual bool HasMessage() const = 0;
122 
GetUnits()123     virtual EDA_UNITS GetUnits() const
124     {
125         return EDA_UNITS::MILLIMETRES;
126     }
127 
~REPORTER()128     virtual ~REPORTER()
129     {
130     }
131 };
132 
133 
134 /**
135  * A wrapper for reporting to a wxTextCtrl object.
136  */
137 class WX_TEXT_CTRL_REPORTER : public REPORTER
138 {
139 public:
WX_TEXT_CTRL_REPORTER(wxTextCtrl * aTextCtrl)140     WX_TEXT_CTRL_REPORTER( wxTextCtrl* aTextCtrl ) :
141         REPORTER(),
142         m_textCtrl( aTextCtrl )
143     {
144     }
145 
~WX_TEXT_CTRL_REPORTER()146     virtual ~WX_TEXT_CTRL_REPORTER()
147     {
148     }
149 
150     REPORTER& Report( const wxString& aText,
151                       SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
152 
153     bool HasMessage() const override;
154 
155 private:
156     wxTextCtrl* m_textCtrl;
157 };
158 
159 
160 /**
161  * A wrapper for reporting to a wxString object.
162  */
163 class WX_STRING_REPORTER : public REPORTER
164 {
165 public:
WX_STRING_REPORTER(wxString * aString)166     WX_STRING_REPORTER( wxString* aString ) :
167         REPORTER(),
168         m_string( aString )
169     {
170     }
171 
~WX_STRING_REPORTER()172     virtual ~WX_STRING_REPORTER()
173     {
174     }
175 
176     REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
177 
178     bool HasMessage() const override;
179 
180 private:
181     wxString* m_string;
182 };
183 
184 
185 /**
186  * A wrapper for reporting to a wx HTML window.
187  */
188 class WX_HTML_PANEL_REPORTER : public REPORTER
189 {
190 public:
WX_HTML_PANEL_REPORTER(WX_HTML_REPORT_PANEL * aPanel)191     WX_HTML_PANEL_REPORTER( WX_HTML_REPORT_PANEL* aPanel ) :
192         REPORTER(),
193         m_panel( aPanel )
194     {
195     }
196 
~WX_HTML_PANEL_REPORTER()197     virtual ~WX_HTML_PANEL_REPORTER()
198     {
199     }
200 
201     REPORTER& Report( const wxString& aText,
202                       SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
203 
204     REPORTER& ReportTail( const wxString& aText,
205                           SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
206 
207     REPORTER& ReportHead( const wxString& aText,
208                           SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
209 
210     bool HasMessage() const override;
211 
212 private:
213     WX_HTML_REPORT_PANEL* m_panel;
214 };
215 
216 
217 /**
218  * A singleton reporter that reports to nowhere.
219  *
220  * Used as to simplify code by avoiding the reportee to check for a non-NULL reporter object.
221  */
222 class NULL_REPORTER : public REPORTER
223 {
224 public:
NULL_REPORTER()225     NULL_REPORTER()
226     {
227     }
228 
~NULL_REPORTER()229     virtual ~NULL_REPORTER()
230     {
231     }
232 
233     static REPORTER& GetInstance();
234 
235     REPORTER& Report( const wxString& aText,
236                       SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
237 
HasMessage()238     bool HasMessage() const override { return false; }
239 };
240 
241 
242 /**
243  * Debug type reporter, forwarding messages to std::cout.
244  */
245 class STDOUT_REPORTER : public REPORTER
246 {
247 public:
STDOUT_REPORTER()248     STDOUT_REPORTER()
249     {
250     }
251 
~STDOUT_REPORTER()252     virtual ~STDOUT_REPORTER()
253     {
254     }
255 
256     static REPORTER& GetInstance();
257 
258     REPORTER& Report( const wxString& aMsg, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
259 
HasMessage()260     bool HasMessage() const override { return false; }
261 };
262 
263 
264 class WXLOG_REPORTER : public REPORTER
265 {
266 public:
WXLOG_REPORTER()267     WXLOG_REPORTER()
268     {
269     }
270 
~WXLOG_REPORTER()271     virtual ~WXLOG_REPORTER()
272     {
273     }
274 
275     static REPORTER& GetInstance();
276 
277     REPORTER& Report( const wxString& aMsg, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
278 
HasMessage()279     bool HasMessage() const override { return false; }
280 };
281 
282 
283 /**
284  * A wrapper for reporting to a specific text location in a statusbar.
285  */
286 class STATUSBAR_REPORTER : public REPORTER
287 {
288 public:
289     STATUSBAR_REPORTER( wxStatusBar* aStatusBar, int aPosition = 0 )
REPORTER()290             : REPORTER(),
291               m_statusBar( aStatusBar ),
292               m_position( aPosition )
293     {
294     }
295 
296     REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
297 
298     bool HasMessage() const override;
299 
300 private:
301     wxStatusBar* m_statusBar;
302     int          m_position;
303 };
304 
305 
306 /**
307  * A wrapper for reporting to a #WX_INFOBAR UI element.
308  *
309  * The infobar is not updated until the @c Finalize() method is called. That method will
310  * queue either a show message or a dismiss event for the infobar - so this reporter is
311  * safe to use inside a paint event without causing an infinite paint event loop.
312  *
313  * No action is taken if no message is given to the reporter.
314  */
315 class INFOBAR_REPORTER : public REPORTER
316 {
317 public:
INFOBAR_REPORTER(WX_INFOBAR * aInfoBar)318     INFOBAR_REPORTER( WX_INFOBAR* aInfoBar )
319             : REPORTER(),
320               m_messageSet( false ),
321               m_infoBar( aInfoBar ),
322               m_severity( RPT_SEVERITY_UNDEFINED )
323     {
324     }
325 
326     virtual ~INFOBAR_REPORTER();
327 
328     REPORTER& Report( const wxString& aText,
329                       SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override;
330 
331     bool HasMessage() const override;
332 
333     /**
334      * Update the infobar with the reported text.
335      */
336     void Finalize();
337 
338 private:
339     bool                      m_messageSet;
340     WX_INFOBAR*               m_infoBar;
341     std::unique_ptr<wxString> m_message;
342     SEVERITY                  m_severity;
343 };
344 
345 #endif     // _REPORTER_H_
346