Audacity 3.2.0
DropTarget.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file DropTarget.cpp
6 @brief Inject drag-and-drop importation of files
7
8 Paul Licameli split from ProjectManager.cpp
9
10**********************************************************************/
11
12#include <wx/dataobj.h>
13#include <wx/dnd.h>
14
15#include "AudacityException.h"
16#include "FileNames.h"
17#include "Project.h"
18#include "ProjectFileManager.h"
19#include "TrackPanel.h"
20#include "Viewport.h"
21
22#if wxUSE_DRAG_AND_DROP
23class FileObject final : public wxFileDataObject
24{
25public:
26 FileObject()
27 {
28 }
29
30 bool IsSupportedFormat(const wxDataFormat & format, Direction WXUNUSED(dir = Get)) const
31 // PRL: This function does NOT override any inherited virtual! What does it do?
32 {
33 if (format.GetType() == wxDF_FILENAME) {
34 return true;
35 }
36
37#if defined(__WXMAC__)
38#if !wxCHECK_VERSION(3, 0, 0)
39 if (format.GetFormatId() == kDragPromisedFlavorFindFile) {
40 return true;
41 }
42#endif
43#endif
44
45 return false;
46 }
47};
48
49class DropTarget final : public wxFileDropTarget
50{
51public:
52 DropTarget(AudacityProject *proj)
53 {
54 mProject = proj;
55
56 // SetDataObject takes ownership
57 SetDataObject(safenew FileObject());
58 }
59
60 ~DropTarget()
61 {
62 }
63
64#if defined(__WXMAC__)
65#if !wxCHECK_VERSION(3, 0, 0)
66 bool GetData() override
67 {
68 bool foundSupported = false;
69 bool firstFileAdded = false;
70 OSErr result;
71
72 UInt16 items = 0;
73 CountDragItems((DragReference)m_currentDrag, &items);
74
75 for (UInt16 index = 1; index <= items; index++) {
76
77 DragItemRef theItem = 0;
78 GetDragItemReferenceNumber((DragReference)m_currentDrag, index, &theItem);
79
80 UInt16 flavors = 0;
81 CountDragItemFlavors((DragReference)m_currentDrag, theItem , &flavors ) ;
82
83 for (UInt16 flavor = 1 ;flavor <= flavors; flavor++) {
84
85 FlavorType theType = 0;
86 result = GetFlavorType((DragReference)m_currentDrag, theItem, flavor, &theType);
87 if (theType != kDragPromisedFlavorFindFile && theType != kDragFlavorTypeHFS) {
88 continue;
89 }
90 foundSupported = true;
91
92 Size dataSize = 0;
93 GetFlavorDataSize((DragReference)m_currentDrag, theItem, theType, &dataSize);
94
95 ArrayOf<char> theData{ dataSize };
96 GetFlavorData((DragReference)m_currentDrag, theItem, theType, (void*) theData.get(), &dataSize, 0L);
97
98 wxString name;
99 if (theType == kDragPromisedFlavorFindFile) {
100 name = wxMacFSSpec2MacFilename((FSSpec *)theData.get());
101 }
102 else if (theType == kDragFlavorTypeHFS) {
103 name = wxMacFSSpec2MacFilename(&((HFSFlavor *)theData.get())->fileSpec);
104 }
105
106 if (!firstFileAdded) {
107 // reset file list
108 ((wxFileDataObject*)GetDataObject())->SetData(0, "");
109 firstFileAdded = true;
110 }
111
112 ((wxFileDataObject*)GetDataObject())->AddFile(name);
113
114 // We only want to process one flavor
115 break;
116 }
117 }
118 return foundSupported;
119 }
120#endif
121
122 bool OnDrop(wxCoord x, wxCoord y) override
123 {
124 // bool foundSupported = false;
125#if !wxCHECK_VERSION(3, 0, 0)
126 bool firstFileAdded = false;
127 OSErr result;
128
129 UInt16 items = 0;
130 CountDragItems((DragReference)m_currentDrag, &items);
131
132 for (UInt16 index = 1; index <= items; index++) {
133
134 DragItemRef theItem = 0;
135 GetDragItemReferenceNumber((DragReference)m_currentDrag, index, &theItem);
136
137 UInt16 flavors = 0;
138 CountDragItemFlavors((DragReference)m_currentDrag, theItem , &flavors ) ;
139
140 for (UInt16 flavor = 1 ;flavor <= flavors; flavor++) {
141
142 FlavorType theType = 0;
143 result = GetFlavorType((DragReference)m_currentDrag, theItem, flavor, &theType);
144 if (theType != kDragPromisedFlavorFindFile && theType != kDragFlavorTypeHFS) {
145 continue;
146 }
147 return true;
148 }
149 }
150#endif
151 return CurrentDragHasSupportedFormat();
152 }
153
154#endif
155
156 bool OnDropFiles(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxArrayString& filenames) override
157 {
158 // Experiment shows that this function can be reached while there is no
159 // catch block above in wxWidgets. So stop all exceptions here.
160 return GuardedCall< bool > ( [&] {
161 wxArrayString sortednames(filenames);
162 sortednames.Sort(FileNames::CompareNoCase);
163
164 auto cleanup = finally( [&] {
165 Viewport::Get(*mProject).HandleResize(); // Adjust scrollers for NEW track sizes.
166 } );
167
169 std::vector<FilePath> { sortednames.begin(), sortednames.end() });
170
171 auto &viewport = Viewport::Get(*mProject);
172 viewport.ZoomFitHorizontallyAndShowTrack(nullptr);
173
174 return true;
175 } );
176 }
177
178private:
179 AudacityProject *mProject;
180};
181
182// Hook the construction of projects
185 // We can import now, so become a drag target
186 // SetDropTarget(safenew AudacityDropTarget(this));
187 // mTrackPanel->SetDropTarget(safenew AudacityDropTarget(this));
188
190 .SetDropTarget(
191 // SetDropTarget takes ownership
192 safenew DropTarget( &project ) );
193 return nullptr;
194 }
195};
196#endif
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
const TranslatableString name
Definition: Distortion.cpp:76
#define safenew
Definition: MemoryX.h:9
static const AudacityProject::AttachedObjects::RegisteredFactory key
const auto project
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:274
bool Import(const std::vector< FilePath > &fileNames, bool addToHistory=true)
static ProjectFileManager & Get(AudacityProject &project)
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:233
void HandleResize()
Definition: Viewport.cpp:387
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:32
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:196
FILES_API int CompareNoCase(const wxString &first, const wxString &second)