1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2008-2015 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
24  */
25 
26 /**
27  * @file pgm_base.h
28  * @brief see class PGM_BASE
29  */
30 
31 #ifndef  PGM_BASE_H_
32 #define  PGM_BASE_H_
33 
34 #include <map>
35 #include <memory>
36 #include <search_stack.h>
37 #include <settings/environment.h>
38 #include <wx/filename.h>
39 
40 #undef pid_t
41 #include <pybind11/embed.h>
42 
43 class wxSingleInstanceChecker;
44 class wxApp;
45 class wxMenu;
46 class wxWindow;
47 
48 class COMMON_SETTINGS;
49 class SETTINGS_MANAGER;
50 class SCRIPTING;
51 
52 /**
53  * A small class to handle the list of existing translations.
54  *
55  * The locale translation is automatic.  The selection of languages is mainly for
56  * maintainer's convenience.  To add a support to a new translation add a new item
57  * to #LanguagesList[].
58  */
59 struct LANGUAGE_DESCR
60 {
61     /// wxWidgets locale identifier (See wxWidgets doc)
62     int         m_WX_Lang_Identifier;
63 
64     /// KiCad identifier used in menu selection (See id.h)
65     int         m_KI_Lang_Identifier;
66 
67     /// Labels used in menus
68     wxString    m_Lang_Label;
69 
70     /// Set to true if the m_Lang_Label must not be translated
71     bool        m_DoNotTranslate;
72 };
73 
74 
75 /**
76  * An array containing all the languages that KiCad supports.
77  */
78 extern LANGUAGE_DESCR LanguagesList[];
79 
80 /**
81  * Container for data for KiCad programs.
82  *
83  * The functions are virtual so we can do cross module calls without linking to them.  This
84  * used to be a wxApp derivative, but that is difficult under wxPython which shapes the wxApp.
85  * So now this is a "side-car" (like a motorcycle side-car) object with a back pointer into
86  * the wxApp which initializes it.
87  *
88  * - OnPgmStart() is virtual, may be overridden, and parallels wxApp::OnInit(), from where it
89  *   should called.
90  * - OnPgmEnd() is virtual, may be overridden, and parallels wxApp::OnExit(), from where it
91  *   should be called.
92  */
93 class PGM_BASE
94 {
95 public:
96     PGM_BASE();
97     virtual ~PGM_BASE();
98 
99 #if 0
100     /*
101 
102     Derived classes must implement these two functions: OnPgmInit() and
103     OnPgmExit(), and since they are only called from same source file as their
104     implementation, these need not be virtual here. In fact, in the case of
105     python project manager's class PGM_PYTHON, these functions are actually
106     written in python. In total there are three implementations, corresponding
107     to the three defines given by kiface.h's KFCTL_* #defines.
108 
109     */
110 
111     /**
112      * This is the first executed function (like main() ).
113      *
114      * @return true if the application can be started.
115      */
116     virtual bool OnPgmInit() = 0;           // call this from wxApp::OnInit()
117 
118     virtual void OnPgmExit() = 0;           // call this from wxApp::OnExit()
119 #endif
120 
121     /**
122      * Specific to MacOSX (not used under Linux or Windows).
123      *
124      * MacOSX requires it for file association.
125      * @see http://wiki.wxwidgets.org/WxMac-specific_topics
126      */
127     virtual void MacOpenFile( const wxString& aFileName ) = 0;
128 
GetSettingsManager()129     virtual SETTINGS_MANAGER& GetSettingsManager() const { return *m_settings_manager; }
130 
131     virtual COMMON_SETTINGS* GetCommonSettings() const;
132 
133     virtual void SetTextEditor( const wxString& aFileName );
134 
135     /**
136      * Return the path to the preferred text editor application.
137      *
138      * @param   aCanShowFileChooser If no editor is currently set and this argument is
139      *          'true' then this method will show a file chooser dialog asking for the
140      *          editor's executable.
141      * @return  Returns the full path of the editor, or an empty string if no editor has
142      *          been set.
143      */
144     virtual const wxString& GetTextEditor( bool aCanShowFileChooser = true );
145 
146     /**
147      * Shows a dialog that instructs the user to select a new preferred editor.
148      * @param   aDefaultEditor Default full path for the default editor this dialog should
149      *          show by default.
150      * @return  Returns the full path of the editor, or an empty string if no editor was
151      *          chosen.
152      */
153     virtual const wxString AskUserForPreferredEditor(
154             const wxString& aDefaultEditor = wxEmptyString );
155 
IsKicadEnvVariableDefined()156     virtual bool IsKicadEnvVariableDefined() const               { return !m_kicad_env.IsEmpty(); }
157 
GetKicadEnvVariable()158     virtual const wxString& GetKicadEnvVariable() const          { return m_kicad_env; }
159 
GetExecutablePath()160     virtual const wxString& GetExecutablePath() const            { return m_bin_dir; }
161 
GetLocale()162     virtual wxLocale* GetLocale()                                { return m_locale; }
163 
GetPdfBrowserName()164     virtual const wxString& GetPdfBrowserName() const            { return m_pdf_browser; }
165 
SetPdfBrowserName(const wxString & aFileName)166     virtual void SetPdfBrowserName( const wxString& aFileName )  { m_pdf_browser = aFileName; }
167 
168     /**
169      * @return true if the PDF browser is the default (system) PDF browser and false if the
170      *         PDF browser is the preferred (selected) browser, else returns false if there
171      *         is no selected browser.
172      */
UseSystemPdfBrowser()173     virtual bool UseSystemPdfBrowser() const
174     {
175         return m_use_system_pdf_browser || m_pdf_browser.IsEmpty();
176     }
177 
178     /**
179      * Force the use of system PDF browser, even if a preferred PDF browser is set.
180      */
ForceSystemPdfBrowser(bool aFlg)181     virtual void ForceSystemPdfBrowser( bool aFlg ) { m_use_system_pdf_browser = aFlg; }
182 
183     /**
184      * Set the dictionary file name for internationalization.
185      *
186      * The files are in kicad/internat/xx or kicad/internat/xx_XX and are named kicad.mo
187      *
188      * @param aErrMsg is the string to return the error message it.
189      * @param first_time must be set to true the first time this function is called,
190      *                   false otherwise.
191      * @return false if there was an error setting the language.
192      */
193     virtual bool SetLanguage( wxString& aErrMsg, bool first_time = false );
194 
195     /**
196      * Set the default language without reference to any preferences.  Can be used to set
197      * the language for dialogs that show before preferences are loaded
198      * @param aErrMsg String to return the error message(s) in
199      * @return false if the language could not be set
200      */
201     bool SetDefaultLanguage( wxString& aErrMsg );
202 
203     /**
204      * Set in .m_language_id member the wxWidgets language identifier ID from the KiCad
205      * menu id (internal menu identifier).
206      *
207      * @param menu_id The KiCad menuitem id (returned by Menu Event, when clicking on a
208      *                 menu item)
209      */
210     virtual void SetLanguageIdentifier( int menu_id );
211 
212     /**
213      * @return the wxWidgets language identifier Id of the language currently selected.
214      */
GetSelectedLanguageIdentifier()215     virtual int GetSelectedLanguageIdentifier() const { return m_language_id; }
216 
217     virtual void SetLanguagePath();
218 
219     /**
220      * Read the PDF browser choice from the common configuration.
221      */
222     virtual void ReadPdfBrowserInfos();
223 
224     /**
225      * Save the PDF browser choice to the common configuration.
226      */
227     virtual void WritePdfBrowserInfos();
228 
229     /**
230      * Sets the environment variable \a aName to \a aValue.
231      *
232      * This function first checks to see if the environment variable \a aName is already
233      * defined.  If it is not defined, then the environment variable \a aName is set to
234      * a value.  Otherwise, the environment variable is left unchanged.  This allows the user
235      * to override environment variables for testing purposes.
236      *
237      * @param aName is a wxString containing the environment variable name.
238      * @param aValue is a wxString containing the environment variable value.
239      * @return true if the environment variable \a Name was set to \a aValue.
240      */
241     virtual bool SetLocalEnvVariable( const wxString& aName, const wxString& aValue );
242 
243     /**
244      * Updates the local environment with the contents of the current ENV_VAR_MAP stored in the
245      * COMMON_SETTINGS
246      * @see GetLocalEnvVariables()
247      */
248     virtual void SetLocalEnvVariables();
249 
250     virtual ENV_VAR_MAP& GetLocalEnvVariables() const;
251 
252     /**
253      * Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
254      *
255      * This should return what wxGetApp() returns.
256      */
257     virtual wxApp&   App();
258 
259     static const wxChar workingDirKey[];
260 
261     /**
262      * Initialize this program.
263      *
264      * Initialize the process in a KiCad standard way using some generalized techniques:
265      *  - Default paths (help, libs, bin) and configuration file names
266      *  - Language and locale
267      *  - fonts
268      *
269      * @note Do not initialize anything relating to DSOs or projects.
270      *
271      * @param aHeadless If true, run in headless mode (e.g. for unit tests)
272      * @param aSkipPyInit If true, do not init python stuff.
273      * Useful in application that do not use python, to disable python dependency at run time
274      * @return true if success, false if failure and program is to terminate.
275      */
276     bool InitPgm( bool aHeadless = false, bool aSkipPyInit = false );
277 
278     // The PGM_* classes can have difficulties at termination if they
279     // are not destroyed soon enough.  Relying on a static destructor can be
280     // too late for contained objects like wxSingleInstanceChecker.
281     void Destroy();
282 
283     /**
284      * Save the program (process) settings subset which are stored .kicad_common.
285      */
286     void SaveCommonSettings();
287 
288     /**
289      * wxWidgets on MSW tends to crash if you spool up more than one print job at a time.
290      */
291     bool m_Printing;
292 
293     int  m_ModalDialogCount;
294 
295     bool m_Quitting;
296 
297 protected:
298     /// Loads internal settings from COMMON_SETTINGS
299     void loadCommonSettings();
300 
301     /// Trap all changes in here, simplifies debugging
setLanguageId(int aId)302     void setLanguageId( int aId )       { m_language_id = aId; }
303 
304     /**
305      * Find the path to the executable and stores it in PGM_BASE::m_bin_dir.
306      *
307      * @return true if success, else false.
308      */
309     bool setExecutablePath();
310 
311 protected:
312     std::unique_ptr<SETTINGS_MANAGER> m_settings_manager;
313 
314     std::unique_ptr<SCRIPTING> m_python_scripting;
315 
316     wxString        m_bin_dir;                /// full path to this program
317     wxString        m_kicad_env;              /// The KICAD system environment variable.
318 
319     wxLocale*       m_locale;
320     int             m_language_id;
321 
322     bool            m_use_system_pdf_browser;
323     wxString        m_pdf_browser;            /// Filename of the app selected for browsing PDFs
324 
325     wxString        m_text_editor;
326 };
327 
328 
329 /// The global Program "get" accessor.
330 /// Implemented in: 1) common/single_top.cpp,  2) kicad/kicad.cpp, and 3) scripting/kiway.i
331 extern PGM_BASE& Pgm();
332 
333 /// similar to PGM_BASE& Pgm(), but return a reference that can be nullptr
334 /// when running a shared lib from a script, not from a kicad appl
335 extern PGM_BASE* PgmOrNull();
336 
337 
338 #endif  // PGM_BASE_H_
339