KiCad PCB EDA Suite
dialog_about.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) 2010 Rafael Sokolowski <Rafael.Sokolowski@web.de>
5  * Copyright (C) 2017-2021 KiCad Developers, see CHANGELOG.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 
26 #include <config.h>
27 #include <string>
28 
29 #include <wx/clipbrd.h>
30 #include <wx/msgdlg.h>
31 #include <wx/hyperlink.h>
32 
33 /* All KiCad icons are linked into shared library 'libbitmaps.a'.
34  * Icons:
35  * preference_xpm; // Icon for 'Developers' tab
36  * editor_xpm; // Icon for 'Doc Writers' tab
37  * color_materials_xpm; // Icon for 'Artists' tab
38  * language_xpm; // Icon for 'Translators' tab
39  * right_xpm; // Right arrow icon for list items
40  * info_xpm; // Bulb for description tab
41  * tools_xpm; // Sheet of paper icon for license info tab
42  */
43 #include <bitmaps.h>
44 #include <build_version.h>
46 #include <tool/tool_manager.h>
47 
48 #include "dialog_about.h"
49 
50 
52  : DIALOG_ABOUT_BASE( aParent ), m_info( aAppInfo )
53 {
54  wxASSERT( aParent != nullptr );
55 
56  // TODO: Change these to 16x16 versions when available
57  m_images = new wxImageList( 24, 24, false, 9 );
58 
59  m_images->Add( KiBitmap( BITMAPS::info ) ); // INFORMATION
60  m_images->Add( KiBitmap( BITMAPS::recent ) ); // VERSION
61  m_images->Add( KiBitmap( BITMAPS::preference ) ); // DEVELOPERS
62  m_images->Add( KiBitmap( BITMAPS::editor ) ); // DOCWRITERS
63  m_images->Add( KiBitmap( BITMAPS::library ) ); // LIBRARIANS
64  m_images->Add( KiBitmap( BITMAPS::color_materials ) ); // ARTISTS
65  m_images->Add( KiBitmap( BITMAPS::language ) ); // TRANSLATORS
66  m_images->Add( KiBitmap( BITMAPS::zip ) ); // PACKAGERS
67  m_images->Add( KiBitmap( BITMAPS::tools ) ); // LICENSE
68 
69  m_notebook->SetImageList( m_images );
70 
71  if( m_info.GetAppIcon().IsOk() )
72  {
73  SetIcon( m_info.GetAppIcon() );
74  m_bitmapApp->SetBitmap( m_info.GetAppIcon() );
75  }
76  else
77  {
78  wxIcon icon;
79  icon.CopyFromBitmap( KiBitmap( BITMAPS::icon_kicad ) );
80  SetIcon( icon );
81  m_bitmapApp->SetBitmap( icon );
82  }
83 
84  m_titleName = aParent->GetAboutTitle();
85  m_staticTextAppTitle->SetLabel( m_titleName );
87  m_staticTextBuildVersion->SetLabel( "Version: " + m_info.GetBuildVersion() );
89 
90  SetTitle( wxString::Format( _( "About %s" ), m_titleName ) );
92 
93  GetSizer()->SetSizeHints( this );
94  SetFocus();
95  Centre();
96 }
97 
98 
100 {
101  delete m_images;
102 }
103 
104 
106 {
107  // three columns with vertical and horizontal extra space of two pixels
108  wxFlexGridSizer* fgSizer = new wxFlexGridSizer( 3, 2, 2 );
109  fgSizer->SetFlexibleDirection( wxHORIZONTAL );
110  fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
111 
112  return fgSizer;
113 }
114 
115 
117 {
120 
121  wxString version = GetVersionInfoData( m_titleName, true );
122 
123  createNotebookHtmlPage( m_notebook, _( "Version" ), IMAGES::VERSION, version, true );
124 
126  m_info.GetDevelopers() );
128  m_info.GetDocWriters() );
129 
131  m_info.GetLibrarians() );
132 
134  m_info.GetArtists() );
138  m_info.GetPackagers() );
139 
141 }
142 
143 void DIALOG_ABOUT::createNotebookPage( wxNotebook* aParent, const wxString& aCaption,
144  IMAGES aIconIndex, const CONTRIBUTORS& aContributors )
145 {
146  wxPanel* outerPanel = new wxPanel( aParent );
147  wxBoxSizer* outerSizer = new wxBoxSizer( wxVERTICAL );
148 
149  wxBoxSizer* bSizer = new wxBoxSizer( wxHORIZONTAL );
150 
151  wxScrolledWindow* m_scrolledWindow1 = new wxScrolledWindow( outerPanel, wxID_ANY,
152  wxDefaultPosition,
153  wxDefaultSize,
154  wxHSCROLL|wxVSCROLL );
155  m_scrolledWindow1->SetScrollRate( 5, 5 );
156 
157  /* Panel for additional space at the left,
158  * but can also be used to show an additional bitmap.
159  */
160  wxPanel* panel1 = new wxPanel( m_scrolledWindow1 );
161 
162  wxFlexGridSizer* fgSizer1 = createFlexGridSizer();
163 
164  for( size_t i=0; i<aContributors.GetCount(); ++i )
165  {
166  CONTRIBUTOR* contributor = &aContributors.Item( i );
167 
168  // Icon at first column
169  wxStaticBitmap* m_bitmap1 = createStaticBitmap( m_scrolledWindow1, contributor->GetIcon() );
170  fgSizer1->Add( m_bitmap1, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5 );
171 
172  // Name of contributor at second column
173  if ( contributor->GetName() != wxEmptyString )
174  {
175  wxStaticText* m_staticText1 = new wxStaticText( m_scrolledWindow1, wxID_ANY,
176  contributor->GetName(),
177  wxDefaultPosition, wxDefaultSize, 0 );
178  m_staticText1->Wrap( -1 );
179  fgSizer1->Add( m_staticText1, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
180  }
181  else
182  {
183  fgSizer1->AddSpacer( 5 );
184  }
185 
186  // Email address of contributor at third column
187  if ( contributor->GetExtra() != wxEmptyString )
188  {
189  wxStaticText* hyperlink = wxStaticTextRef( m_scrolledWindow1,
190  contributor->GetExtra() );
191  fgSizer1->Add( hyperlink, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
192  }
193  else
194  {
195  fgSizer1->AddSpacer( 5 );
196  }
197  }
198 
199  bSizer->Add( panel1, 1, wxEXPAND|wxALL, 10 );
200  bSizer->Add( fgSizer1, 7, wxEXPAND|wxALL, 10 ); // adjust width of panel with first int value
201  m_scrolledWindow1->SetSizer( bSizer );
202  m_scrolledWindow1->Layout();
203  bSizer->Fit( m_scrolledWindow1 );
204 
205  outerSizer->Add( m_scrolledWindow1, 1, wxEXPAND, 0 );
206  outerPanel->SetSizer( outerSizer );
207 
208  aParent->AddPage( outerPanel, aCaption, false, static_cast<int>( aIconIndex ) );
209 }
210 
211 
212 void DIALOG_ABOUT::createNotebookPageByCategory( wxNotebook* aParent, const wxString& aCaption,
213  IMAGES aIconIndex,
214  const CONTRIBUTORS& aContributors )
215 {
216  // The left justification between wxStaticText and wxHyperlinkCtrl is different so
217  // we must pad to make the alignment look decent.
218  //
219  // @todo Just make all of the contributor lists HTML so the alignment is consistent.
220  wxString padding;
221 
222  // Of course the padding is different depending on the platform so we adjust the
223  // padding accordingly.
224 #if defined( __WXGTK__ )
225  padding += " ";
226 #endif
227  wxPanel* outerPanel = new wxPanel( aParent );
228  wxBoxSizer* outerSizer = new wxBoxSizer( wxVERTICAL );
229 
230  wxBoxSizer* bSizer = new wxBoxSizer( wxHORIZONTAL );
231 
232  wxScrolledWindow* m_scrolledWindow1 = new wxScrolledWindow( outerPanel, wxID_ANY,
233  wxDefaultPosition,
234  wxDefaultSize,
235  wxHSCROLL|wxVSCROLL );
236  m_scrolledWindow1->SetScrollRate( 5, 5 );
237 
238  /* Panel for additional space at the left,
239  * but can also be used to show an additional bitmap.
240  */
241  wxPanel* panel1 = new wxPanel( m_scrolledWindow1 );
242 
243  wxFlexGridSizer* fgSizer1 = createFlexGridSizer();
244 
245  for( size_t i=0; i < aContributors.GetCount(); ++i )
246  {
247  CONTRIBUTOR* contributor = &aContributors.Item( i );
248 
249  wxBitmap* icon = contributor->GetIcon();
250  wxString category = contributor->GetCategory();
251 
252  /* to construct the next row we expect to have
253  * a category and a contributor that was not considered up to now
254  */
255  if( ( category != wxEmptyString ) && !( contributor->IsChecked() ) )
256  {
257  // Icon at first column
258  wxStaticBitmap* m_bitmap1 = createStaticBitmap( m_scrolledWindow1, icon );
259  fgSizer1->Add( m_bitmap1, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5 );
260 
261  // Category name at second column
262  wxStaticText* m_staticText1 = new wxStaticText( m_scrolledWindow1, wxID_ANY,
263  contributor->GetCategory() + wxT( ":" ),
264  wxDefaultPosition, wxDefaultSize, 0 );
265  m_staticText1->SetFont( m_staticText1->GetFont().Bold() );
266  m_staticText1->Wrap( -1 );
267  fgSizer1->Add( m_staticText1, 0, wxALIGN_LEFT|wxBOTTOM|wxEXPAND, 2 );
268 
269  // Nothing at third column
270  fgSizer1->AddSpacer( 5 );
271 
272  // Now, all contributors of the same category will follow
273  for( size_t j=0; j < aContributors.GetCount(); ++j )
274  {
275  CONTRIBUTOR* sub_contributor = &aContributors.Item( j );
276 
277  if ( sub_contributor->GetCategory() == category )
278  {
279  // First column is empty
280  fgSizer1->AddSpacer( 5 );
281 
282  wxControl* ctrl;
283 
284  // No URL supplied, display normal text control
285  if( sub_contributor->GetUrl().IsEmpty() )
286  {
287  ctrl = new wxStaticText( m_scrolledWindow1, wxID_ANY,
288  padding + wxT( "• " ) + sub_contributor->GetName(),
289  wxDefaultPosition,
290  wxDefaultSize, 0 );
291  }
292  else
293  {
294  // Display a hyperlink control instead
295  ctrl = new wxHyperlinkCtrl( m_scrolledWindow1, wxID_ANY,
296  wxT( "• " ) + sub_contributor->GetName(),
297  sub_contributor->GetUrl(),
298  wxDefaultPosition,
299  wxDefaultSize,
300  wxBORDER_NONE | wxHL_CONTEXTMENU | wxHL_ALIGN_LEFT );
301  }
302 
303  m_staticText1->Wrap( -1 );
304 
305  fgSizer1->Add( ctrl, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
306 
307  // Email address of contributor at third column
308  if( sub_contributor->GetExtra() != wxEmptyString )
309  {
310  wxStaticText* mail = wxStaticTextRef( m_scrolledWindow1,
311  sub_contributor->GetExtra() );
312  fgSizer1->Add( mail, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
313  }
314  else
315  {
316  fgSizer1->AddSpacer( 5 );
317  }
318 
319  /* this contributor was added to the GUI,
320  * thus can be ignored next time
321  */
322  sub_contributor->SetChecked( true );
323  }
324  }
325  }
326  else
327  {
328  continue;
329  }
330  }
331 
332  /* Now, lets list the remaining contributors that have not been considered
333  * because they were not assigned to any category.
334  */
335  for ( size_t k=0; k < aContributors.GetCount(); ++k )
336  {
337  CONTRIBUTOR* contributor = &aContributors.Item( k );
338 
339  if ( contributor->IsChecked() )
340  continue;
341 
342  // Icon at first column
343  wxStaticBitmap* m_bitmap1 = createStaticBitmap( m_scrolledWindow1, contributor->GetIcon() );
344  fgSizer1->Add( m_bitmap1, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 5 );
345 
346  // Name of contributor at second column
347  if( contributor->GetName() != wxEmptyString )
348  {
349  wxStaticText* m_staticText1 = new wxStaticText( m_scrolledWindow1, wxID_ANY,
350  contributor->GetName(),
351  wxDefaultPosition, wxDefaultSize, 0 );
352  m_staticText1->Wrap( -1 );
353  fgSizer1->Add( m_staticText1, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
354  }
355  else
356  {
357  fgSizer1->AddSpacer( 5 );
358  }
359 
360  // Email address of contributor at third column
361  if ( contributor->GetExtra() != wxEmptyString )
362  {
363  wxStaticText* mail = wxStaticTextRef( m_scrolledWindow1,
364  contributor->GetExtra() );
365  fgSizer1->Add( mail, 0, wxALIGN_LEFT|wxBOTTOM, 2 );
366  }
367  else
368  {
369  fgSizer1->AddSpacer( 5 );
370  }
371  }
372 
373  bSizer->Add( panel1, 1, wxEXPAND|wxALL, 10 );
374  bSizer->Add( fgSizer1, 7, wxEXPAND|wxALL, 10 ); // adjust width of panel with first int value
375  m_scrolledWindow1->SetSizer( bSizer );
376  m_scrolledWindow1->Layout();
377  bSizer->Fit( m_scrolledWindow1 );
378 
379  outerSizer->Add( m_scrolledWindow1, 1, wxEXPAND, 0 );
380  outerPanel->SetSizer( outerSizer );
381 
382  aParent->AddPage( outerPanel, aCaption, false, static_cast<int>( aIconIndex ) );
383 }
384 
385 
386 void DIALOG_ABOUT::createNotebookHtmlPage( wxNotebook* aParent, const wxString& aCaption,
387  IMAGES aIconIndex, const wxString& html,
388  bool aSelection )
389 {
390  wxPanel* panel = new wxPanel( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
391  wxTAB_TRAVERSAL );
392 
393  wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
394 
395  wxString htmlPage = wxEmptyString, htmlContent = html;
396 
397  // to have a unique look background color for HTML pages is set to the default as it is
398  // used for all the other widgets
399  wxString htmlColor = ( GetBackgroundColour() ).GetAsString( wxC2S_HTML_SYNTAX );
400  wxString textColor = GetForegroundColour().GetAsString( wxC2S_HTML_SYNTAX );
401  wxString linkColor =
402  wxSystemSettings::GetColour( wxSYS_COLOUR_HOTLIGHT ).GetAsString( wxC2S_HTML_SYNTAX );
403 
404  // beginning of HTML structure
405  htmlPage.Append( wxString::Format( wxT( "<html><body bgcolor='%s' text='%s' link='%s'>" ),
406  htmlColor, textColor, linkColor ) );
407 
408  htmlPage.Append( htmlContent );
409 
410  // end of HTML structure indicated by closing tags
411  htmlPage.Append( wxT( "</body></html>" ) );
412 
413  int flags = aSelection ? wxHW_SCROLLBAR_AUTO : ( wxHW_SCROLLBAR_AUTO | wxHW_NO_SELECTION );
414 
415  // the HTML page is going to be created with previously created HTML content
416  auto htmlWindow = new wxHtmlWindow( panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, flags );
417 
418  // HTML font set to font properties as they are used for widgets to have an unique look
419  // under different platforms with HTML
420  wxFont font = GetFont();
421  htmlWindow->SetStandardFonts( font.GetPointSize(), font.GetFaceName(), font.GetFaceName() );
422  htmlWindow->SetPage( htmlPage );
423 
424  // the HTML window shall not be used to open external links, thus this task is delegated
425  // to users default browser
426  htmlWindow->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED,
427  wxHtmlLinkEventHandler( DIALOG_ABOUT::onHtmlLinkClicked ), NULL, this );
428 
429  // no additional space around the HTML window as it is also the case by the other notebook pages
430  bSizer->Add( htmlWindow, 1, wxEXPAND, 0 );
431  panel->SetSizer( bSizer );
432 
433  aParent->AddPage( panel, aCaption, false, static_cast<int>( aIconIndex ) );
434 }
435 
436 
437 wxStaticText* DIALOG_ABOUT::wxStaticTextRef( wxScrolledWindow* aParent, const wxString& aReference )
438 {
439  wxStaticText* text = new wxStaticText( aParent, wxID_ANY,
440  wxT( "(" ) + aReference + wxT( ")" ) );
441 
442  return text;
443 }
444 
445 
446 wxStaticBitmap* DIALOG_ABOUT::createStaticBitmap( wxScrolledWindow* aParent, wxBitmap* aIcon )
447 {
448  wxStaticBitmap* bitmap = new wxStaticBitmap( aParent, wxID_ANY, wxNullBitmap,
449  wxDefaultPosition, wxDefaultSize, 0 );
450 
451  if( aIcon )
452  {
453  bitmap->SetBitmap( *aIcon );
454  }
455  else
456  {
457  bitmap->SetBitmap( KiBitmap( BITMAPS::right ) );
458  }
459 
460  return bitmap;
461 }
462 
463 
464 void DIALOG_ABOUT::onHtmlLinkClicked( wxHtmlLinkEvent& event )
465 {
466  ::wxLaunchDefaultBrowser( event.GetLinkInfo().GetHref() );
467 }
468 
469 
470 void DIALOG_ABOUT::onCopyVersionInfo( wxCommandEvent& event )
471 {
472  wxLogNull doNotLog; // disable logging of failed clipboard actions
473 
474  if( !wxTheClipboard->Open() )
475  {
476  wxMessageBox( _( "Could not open clipboard to write version information." ),
477  _( "Clipboard Error" ), wxOK | wxICON_EXCLAMATION, this );
478  return;
479  }
480 
481  wxString msg_version = GetVersionInfoData( m_titleName );
482 
483  wxTheClipboard->SetData( new wxTextDataObject( msg_version ) );
484  wxTheClipboard->Flush(); // Allow clipboard data to be available after KiCad closes
485  wxTheClipboard->Close();
486  m_btCopyVersionInfo->SetLabel( _( "Copied..." ) );
487 }
488 
489 
490 void DIALOG_ABOUT::onReportBug( wxCommandEvent& event )
491 {
492  if( TOOL_MANAGER* mgr = static_cast<EDA_BASE_FRAME*>( GetParent() )->GetToolManager() )
493  mgr->RunAction( "common.SuiteControl.reportBug", true );
494 }
495 
496 
497 void DIALOG_ABOUT::OnNotebookPageChanged( wxNotebookEvent& aEvent )
498 {
499  // Work around wxMac issue where the notebook pages are blank
500 #ifdef __WXMAC__
501  int page = aEvent.GetSelection();
502 
503  if( page >= 0 )
504  m_notebook->ChangeSelection( static_cast<unsigned>( page ) );
505 #endif
506 }
wxFlexGridSizer * createFlexGridSizer()
wxString & GetUrl()
Definition: aboutinfo.h:193
CONTRIBUTORS GetTranslators()
Definition: aboutinfo.h:90
wxString & GetLibVersion()
Definition: aboutinfo.h:112
wxString GetVersionInfoData(const wxString &aTitle, bool aHtml, bool aBrief)
Create a version info string for bug reports and the about dialog.
DIALOG_ABOUT(EDA_BASE_FRAME *aParent, ABOUT_APP_INFO &aAppInfo)
wxStaticText * m_staticTextAppTitle
void SetChecked(bool status)
Definition: aboutinfo.h:196
wxString & GetCategory()
Definition: aboutinfo.h:194
void createNotebookPageByCategory(wxNotebook *aParent, const wxString &aCaption, IMAGES aIconIndex, const CONTRIBUTORS &aContributors)
wxString & GetName()
Definition: aboutinfo.h:191
wxImageList * m_images
Definition: dialog_about.h:56
CONTRIBUTORS GetLibrarians()
Definition: aboutinfo.h:88
void createNotebooks()
wxString & GetBuildVersion()
Definition: aboutinfo.h:106
wxStaticText * m_staticTextLibVersion
void createNotebookPage(wxNotebook *aParent, const wxString &aCaption, IMAGES aIconIndex, const CONTRIBUTORS &aContributors)
wxIcon & GetAppIcon()
Wrapper to manage memory allocation for bitmaps.
Definition: aboutinfo.h:115
void OnNotebookPageChanged(wxNotebookEvent &aEvent) override
An object of this class is meant to be used to store application specific information like who has co...
Definition: aboutinfo.h:44
void createNotebookHtmlPage(wxNotebook *aParent, const wxString &aCaption, IMAGES aIconIndex, const wxString &aHtmlMessage, bool aSelection=false)
wxStaticBitmap * m_bitmapApp
wxString & GetLicense()
Definition: aboutinfo.h:97
IMAGES
Definition: dialog_about.h:37
Master controller class:
Definition: tool_manager.h:54
#define NULL
CONTRIBUTORS GetDocWriters()
Definition: aboutinfo.h:87
wxStaticText * m_staticTextBuildVersion
void onCopyVersionInfo(wxCommandEvent &event) override
void onHtmlLinkClicked(wxHtmlLinkEvent &event)
CONTRIBUTORS GetArtists()
Definition: aboutinfo.h:89
#define _(s)
wxString GetCopyright()
Definition: aboutinfo.h:100
wxStaticText * m_staticTextCopyright
wxString & GetExtra()
Definition: aboutinfo.h:192
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
wxNotebook * m_notebook
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
wxStaticBitmap * createStaticBitmap(wxScrolledWindow *aParent, wxBitmap *icon)
CONTRIBUTORS GetPackagers()
Definition: aboutinfo.h:91
wxStaticText * wxStaticTextRef(wxScrolledWindow *aParent, const wxString &aReference)
wxBitmap * GetIcon()
Definition: aboutinfo.h:195
CONTRIBUTORS GetDevelopers()
Definition: aboutinfo.h:86
Class DIALOG_ABOUT_BASE.
const wxString & GetAboutTitle() const
A contributor, a person which was involved in the development of the application or which has contrib...
Definition: aboutinfo.h:160
The base frame for deriving all KiCad main window classes.
wxString m_titleName
Definition: dialog_about.h:57
wxString & GetDescription()
Definition: aboutinfo.h:94
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
wxButton * m_btCopyVersionInfo
bool IsChecked()
Definition: aboutinfo.h:197
ABOUT_APP_INFO & m_info
Definition: dialog_about.h:59
void onReportBug(wxCommandEvent &event) override