KiCad PCB EDA Suite
Loading...
Searching...
No Matches
native_model_file_picker_gtk.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-3.0.html
19 */
20
22
23#ifdef __WXGTK3__
24
27
28#include <trace_helpers.h>
29
30#include <wx/filedlg.h>
31#include <wx/log.h>
32#include <wx/thread.h>
33
34namespace
35{
36struct PICKER_CONTEXT
37{
38 MODEL_FILE_PREVIEW_REQUEST_SERVICE* service;
39 bool embedFile;
40};
41
42thread_local PICKER_CONTEXT* currentContext = nullptr;
43
44// Held as a raw pointer because shutdown must run while wx and the importer are still alive,
45// which a static object's destructor cannot guarantee. pcbnew's IFACE::OnKifaceEnd is the sole
46// owner of that teardown, so any other kiface that starts showing this picker has to call
47// ShutdownNativeModelFilePickerGtk too or it leaks a joinable worker.
48MODEL_FILE_PREVIEW_REQUEST_SERVICE* requestService = nullptr;
49
50wxWindow* createExtraControl( wxWindow* aParent )
51{
52 if( !currentContext )
53 return nullptr;
54
55 try
56 {
57 return new PANEL_MODEL_FILE_PREVIEW( aParent, currentContext->service->MakeRequest(),
58 currentContext->service->MakeCancel(), currentContext->embedFile );
59 }
60 catch( ... )
61 {
62 return nullptr;
63 }
64}
65
66class CONTEXT_SCOPE
67{
68public:
69 explicit CONTEXT_SCOPE( PICKER_CONTEXT* aContext ) { currentContext = aContext; }
70
71 ~CONTEXT_SCOPE() { currentContext = nullptr; }
72
73 CONTEXT_SCOPE( const CONTEXT_SCOPE& ) = delete;
74 CONTEXT_SCOPE& operator=( const CONTEXT_SCOPE& ) = delete;
75};
76} // namespace
77
78
80ShowNativeModelFilePickerGtk( const NATIVE_MODEL_FILE_PICKER_OPTIONS& aOptions )
81{
82 wxASSERT_MSG( wxIsMainThread(), wxS( "model picker must run on the UI thread" ) );
83
84 if( currentContext )
85 {
86 wxFAIL_MSG( wxS( "nested model pickers are unsupported" ) );
87 return {};
88 }
89
90 if( !requestService )
91 requestService = new MODEL_FILE_PREVIEW_REQUEST_SERVICE;
92
93 const long style = ( aOptions.style & ~( wxFD_MULTIPLE | wxFD_SAVE ) ) | wxFD_OPEN | wxFD_FILE_MUST_EXIST;
94 wxASSERT_MSG( !( aOptions.style & ( wxFD_MULTIPLE | wxFD_SAVE ) ),
95 wxS( "model picker supports single-file open only" ) );
96
97 // S3D::ImportModel needs a real filesystem path, so the chooser stays local-only.
98 wxFileDialog dialog( aOptions.parent, aOptions.title, aOptions.directory, aOptions.filename, aOptions.wildcard,
99 style );
100 dialog.SetFilterIndex( aOptions.filterIndex );
101 PICKER_CONTEXT context{ requestService, aOptions.embedFile };
102 CONTEXT_SCOPE contextScope( &context );
103
104 if( !dialog.SetExtraControlCreator( &createExtraControl ) )
105 wxLogTrace( traceModelPreview, wxS( "extra control unsupported" ) );
106
107 const int modalResult = dialog.ShowModal();
108
110 result.embedFile = aOptions.embedFile;
111
112 if( modalResult == wxID_OK )
113 {
114 result.path = dialog.GetPath();
115 result.filterIndex = dialog.GetFilterIndex();
116 result.accepted = !result.path.IsEmpty();
117
118 if( auto* panel = dynamic_cast<PANEL_MODEL_FILE_PREVIEW*>( dialog.GetExtraControl() ) )
119 result.embedFile = panel->GetEmbedFile();
120 }
121
122 return result;
123}
124
125
126void ShutdownNativeModelFilePickerGtk()
127{
128 wxASSERT_MSG( wxIsMainThread(), wxS( "model picker shutdown must run on the UI thread" ) );
129
130 if( requestService )
131 {
132 requestService->Shutdown();
133 delete requestService;
134 requestService = nullptr;
135 }
136}
137
138#endif // __WXGTK3__
const wxChar *const traceModelPreview
Flag to enable native operating-system model preview debug output.
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.