NCBI C++ ToolKit
multi_file_input.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: multi_file_input.cpp 46536 2021-06-28 12:37:36Z shkeda $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Andrey Yazhuk
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
36 
37 #include <wx/sizer.h>
39 #include <wx/scrolwin.h>
40 #include <wx/bmpbuttn.h>
41 #include <wx/filedlg.h>
42 #include <wx/stattext.h>
43 #include <wx/statbox.h>
44 #include <wx/artprov.h>
45 
46 
48 
50 : m_Input(input)
51 {
52  SetDataObject(new wxFileDataObject);
53 }
54 
55 wxDragResult CMultiFileInput::CDropTarget::OnDragOver(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
56  wxDragResult def)
57 {
58  return wxDragCopy;
59 }
60 
61 wxDragResult CMultiFileInput::CDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def)
62 {
63  if (!GetData())
64  return wxDragNone;
65 
66  wxFileDataObject *dobj = (wxFileDataObject *)m_dataObject;
67  wxArrayString filenames = dobj->GetFilenames();
68 
69  vector<wxString> names;
70 
71  size_t n = filenames.GetCount();
72  for (size_t i = 0; i < n; i++)
73  names.push_back(filenames[i]);
74 
75  // On windows, dropping the file comes as a wxDragMove, and on Mac (wxCocoa)
76  // the same operation causes a wxDragLink
77  if (def == wxDragMove || def == wxDragLink || def == wxDragCopy) {
78  m_Input.AddFilenames(names);
79  return wxDragCopy;
80  }
81  return wxDragError;
82 }
83 
84 
85 BEGIN_EVENT_TABLE(CMultiFileInput, wxPanel)
86  EVT_HYPERLINK(wxID_ANY, CMultiFileInput::OnLink)
89 
90 
92 {
93  Init();
94 }
95 
96 
98  wxWindowID id,
99  const wxPoint& pos,
100  const wxSize& size,
101  long style,
102  const wxString& name)
104 {
105  Init();
106  Create(parent, id, pos, size, style, name);
107 }
108 
109 
111 {
112 }
113 
114 
116 {
117  m_ScrollWnd = NULL;
118  m_FileSizer = NULL;
119  m_LinkSizer = NULL;
120 
121  m_DlgTitle = wxT("Select Files");
122  m_DlgParent = this;
123 
125 }
126 
127 
128 void CMultiFileInput::Create(wxWindow* parent,
129  wxWindowID id,
130  const wxPoint& pos,
131  const wxSize& size,
132  long style,
133  const wxString& name)
134 {
135  wxPanel::Create(parent, id, pos, size, style, name);
136 
137  wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
138 
139  // Create scrolled window
140  m_ScrollWnd = new wxScrolledWindow(this);
141  //m_ScrollWnd->SetWindowStyle(wxBORDER_STATIC);
142  m_ScrollWnd->SetScrollRate(4, 4);
143  sizer->Add(m_ScrollWnd, 1, wxEXPAND);
144 
145  // Setup Flex Sizer that will hold filename table
146  m_FileSizer = new wxFlexGridSizer(0, 3, 0, 0);
147  m_FileSizer->AddGrowableCol(0);
148  m_FileSizer->SetFlexibleDirection(wxHORIZONTAL);
149  m_ScrollWnd->SetSizer(m_FileSizer);
150 
151  // add one empty row to the file table
152  x_AddFilenameRow(wxEmptyString);
153  m_FileSizer->SetRows(1);
154 
155  // Create links at the bottom
156  m_LinkSizer = new wxBoxSizer(wxHORIZONTAL);
157  sizer->Add(m_LinkSizer, 0, wxEXPAND, 0);
158 
159  wxHyperlinkCtrl* delete_link =
160  new wxHyperlinkCtrl(this, eDeleteAllFilesLink, wxT("Remove all files from list"), wxT("delete_files"));
161  delete_link->SetVisitedColour(delete_link->GetNormalColour());
162  m_LinkSizer->Add(delete_link, 0, wxALL, 4);
163 
164  m_LinkSizer->AddStretchSpacer(1);
165 
166  wxStaticText* drop_text = new wxStaticText(this, wxID_ANY, wxT("Drop files here"));
167  m_LinkSizer->Add(drop_text, 0, wxALL, 4);
168 
169  //m_LinkSizer->Add(new wxButton(this, eLoadBtn, "Load"), 0, wxTOP, 4);
170 
171  SetSizer(sizer);
172 
173  SetDropTarget(new CMultiFileInput::CDropTarget(*this));
174 }
175 
176 
177 
178 void CMultiFileInput::SetDlgTitle(const wxString& title)
179 {
180  m_DlgTitle = title;
181 }
182 
183 
184 void CMultiFileInput::SetDefaultDir(const wxString& dir)
185 {
186  m_DefaultDir = dir;
187 }
188 
189 
191 {
192  return m_DefaultDir;
193 }
194 
195 
196 void CMultiFileInput::SetWildcard(const wxString& wildcard)
197 {
198  m_Wildcard = wildcard;
199 }
200 
201 
203 {
204  return m_Wildcard;
205 }
206 
207 
208 void CMultiFileInput::SetDlgParent(wxWindow* parent)
209 {
210  m_DlgParent = parent;
211 }
212 
213 
214 void CMultiFileInput::SetDlgAttrs(const wxString& title, const wxString& dir,
215  const wxString& wildcard, wxWindow* parent)
216 {
217  m_DlgTitle = title;
218  m_DefaultDir = dir;
219  m_Wildcard = wildcard;
220  m_DlgParent = parent;
221 }
222 
224 {
225  if (single) {
226  x_SetSingleMode();
227  }
228  else {
229  x_SetMultiMode();
230  }
231 }
232 
234 {
235  if (m_SingleMode)
236  return;
237 
238  m_SingleMode = true;
239 
242 
243  if (!m_SaveFilenames.empty()) {
244  // Don't need text edit events needed by SetValue in versions 2.9+
245 #if (wxMAJOR_VERSION == 2 && wxMINOR_VERSION < 9)
246  m_Inputs[0]->SetValue(m_SaveFilenames[0]);
247 #else
248  m_Inputs[0]->ChangeValue(m_SaveFilenames[0]);
249 #endif
251  }
252 
253  wxWindow* wnd = FindWindow(eDeleteAllFilesLink);
254  if (wnd) wnd->Show(false);
255 
256  m_LinkSizer->Layout();
257 }
258 
260 {
261  if (!m_SingleMode)
262  return;
263 
264  m_SingleMode = false;
265 
266  if (!m_SaveFilenames.empty()) { // when the control is created it is empty
267  if (!m_Inputs[0]->GetValue().empty())
268  m_SaveFilenames.erase(m_SaveFilenames.begin());
269 
271  m_SaveFilenames.clear();
272  }
273 
274  wxWindow* wnd = FindWindow(eDeleteAllFilesLink);
275  if (wnd) wnd->Show(true);
276 
277  m_LinkSizer->Layout();
278 }
279 
280 void CMultiFileInput::GetFilenames(vector<wxString>& filenames) const
281 {
282  for( size_t i = 0; i < m_Inputs.size(); i++ ) {
284  wxString file = input->GetValue().Strip();
285  if (!file.empty())
286  filenames.push_back(file);
287  }
288 }
289 
290 
291 void CMultiFileInput::SetFilenames(const vector<wxString>& filenames)
292 {
294 
296 }
297 
298 
299 void CMultiFileInput::OnLink(wxHyperlinkEvent& event)
300 {
301  int id = event.GetId();
302  if (event.GetId() == eDeleteAllFilesLink) {
304  }
305  else {
306  x_DeleteFilename(id);
307  }
308 }
309 
310 
311 void CMultiFileInput::x_AddFilenameRow(const wxString& filename)
312 {
313  int row_n = m_FileSizer->GetRows();
314 
315  // add a row to Flex sizer (if needed)
316  m_FileSizer->SetRows(row_n + 1);
317 
318  // Create File Combo
320 
321 // Don't need text edit events needed by SetValue in versions 2.9+
322 #if (wxMAJOR_VERSION == 2 && wxMINOR_VERSION < 9)
323  input->SetValue(filename);
324 #else
325  input->ChangeValue(filename);
326 #endif
327  x_SendFileTxtChangedEvt(input, filename);
328 
329  m_FileSizer->Add(input, 1, wxEXPAND | wxALL, 2);
330  m_Inputs.push_back(input);
331 
332  // Create "Choose File" button
333  wxButton* btn = new wxBitmapButton(m_ScrollWnd, m_LastChildID++, wxArtProvider::GetBitmap(wxT("menu::open")), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW);
334  btn->SetToolTip(wxT("Choose a file..."));
335  m_FileSizer->Add(btn, 0, wxEXPAND | wxALL, 2);
336 
337  // create "Delete" link
338  wxHyperlinkCtrl* link = new CHyperlink(m_ScrollWnd, m_LastChildID++, wxT("Delete"), wxT("delete"));
339  link->SetVisitedColour(link->GetNormalColour());
340  m_FileSizer->Add(link, 0, wxALIGN_BOTTOM | wxALL, 5);
341 }
342 
343 
345 {
346  int row_n = m_FileSizer->GetRows();
347 
348  if(row_n > 1) {
349  // delete a row
350  wxWindow* input = FindWindowById(link_id - 2, m_ScrollWnd);
351  vector<CAdvancedFileInput*>::iterator it = std::find(m_Inputs.begin(), m_Inputs.end(), input);
352  m_Inputs.erase(it);
353  input->Destroy();
354 
355  wxWindow* btn = FindWindowById(link_id - 1, m_ScrollWnd);
356  btn->Destroy();
357 
358  wxWindow* link = FindWindowById(link_id, m_ScrollWnd);
359  link->Destroy();
360 
361  m_FileSizer->SetRows(row_n - 1);
362  m_ScrollWnd->FitInside();
363  } else {
364  // there is only one row left - keep it but remove the value
365 
366  // Don't need text edit events needed by SetValue in versions 2.9+
367 #if (wxMAJOR_VERSION == 2 && wxMINOR_VERSION < 9)
368  m_Inputs[0]->SetValue(wxEmptyString);
369 #else
370  m_Inputs[0]->ChangeValue(wxEmptyString);
371 #endif
372  x_SendFileTxtChangedEvt(m_Inputs[0], wxEmptyString);
373  }
374 }
375 
376 
378 {
379  _ASSERT(m_DlgParent != NULL && ! m_DlgTitle.empty());
380 
381  long style = wxFD_OPEN | wxFD_FILE_MUST_EXIST;
382  if (!m_SingleMode) style |= wxFD_MULTIPLE;
383  wxFileDialog dlg(m_DlgParent, m_DlgTitle, m_DefaultDir, wxEmptyString, m_Wildcard, style);
384 
385  if (dlg.ShowModal() == wxID_OK) {
386  wxArrayString paths;
387  dlg.GetPaths(paths);
388 
389  // remember the directory
390  m_DefaultDir = dlg.GetDirectory();
391 
392  vector<wxString> filenames;
393  size_t n = paths.GetCount();
394  for (size_t i = 0; i < n; i++)
395  filenames.push_back (paths[i]);
396 
398  }
399 }
400 
401 
402 void CMultiFileInput::AddFilenames(const vector<wxString>& paths)
403 {
404  if (m_SingleMode && !paths.empty()) {
405 
406  // Don't need text edit events needed by SetValue in versions 2.9+
407 #if (wxMAJOR_VERSION == 2 && wxMINOR_VERSION < 9)
408  m_Inputs[0]->SetValue(paths[0]);
409 #else
410  m_Inputs[0]->ChangeValue(paths[0]);
411 #endif
412  x_SendFileTxtChangedEvt(m_Inputs[0], paths[0]);
413 
414  return;
415  }
416 
417  // add new files, if we have empty row in the end - use them
418  int i = (int)(m_Inputs.size() - 1);
419  while(i >= 0) {
421  wxString s = input->GetValue();
422  if( ! s.empty()) {
423  break;
424  } else {
425  i--;
426  }
427  }
428  // copy filenames to existing rows
429  int i_p = 0; // index of the path
430  int paths_n = (int)paths.size();
431 
432  for ( int j = i + 1; j < (int) m_Inputs.size() && i_p < paths_n; j++, i_p++ ) {
433  // Don't need text edit events needed by SetValue in versions 2.9+
434 #if (wxMAJOR_VERSION == 2 && wxMINOR_VERSION < 9)
435  m_Inputs[j]->SetValue(paths[i_p]);
436 #else
437  m_Inputs[j]->ChangeValue(paths[i_p]);
438 #endif
439  x_SendFileTxtChangedEvt(m_Inputs[j], paths[i_p]);
440  }
441  // add more rows
442  for( ; i_p < paths_n; i_p++ ) {
443  x_AddFilenameRow(paths[i_p]);
444  }
445  m_ScrollWnd->FitInside();
446 }
447 
448 
450 {
451  m_Inputs.clear();
452  m_ScrollWnd->DestroyChildren();
453  m_FileSizer->SetRows(0);
454 
455  x_AddFilenameRow(wxEmptyString); // add one empty line
456 
457  m_ScrollWnd->FitInside();
458 }
459 
460 
461 void CMultiFileInput::OnBrowseBtn(wxCommandEvent& event)
462 {
463 
464  int id = event.GetId();
465  if(id == eLoadBtn) {
466  event.Skip(); // let parents handl it
467  return;
468  }
469 
470  int input_id = id - 1;
471  for( size_t i = 0; i < m_Inputs.size(); i++ ) {
472  if (m_Inputs[i]->GetId() == input_id) {
474  break;
475  }
476  }
477 }
478 
479 // Send a change event for any objects that want to see filename changes
480 // as they happen.
482  const wxString& txt)
483 {
484  wxCommandEvent txt_change_evt(CAdvancedFileInput::s_InputTxtChangedEvt);
485  txt_change_evt.SetString(txt);
486  txt_change_evt.SetClientData(input);
487  GetEventHandler()->ProcessEvent(txt_change_evt);
488 }
489 
CAdvancedFileInput.
static const wxEventType s_InputTxtChangedEvt
event id for any filename text change events
CDropTarget(CMultiFileInput &input)
virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
virtual wxDragResult OnDragOver(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxDragResult def)
CMultiFileInput.
void AddFilenames(const vector< wxString > &filenames)
wxBoxSizer * m_LinkSizer
void SetDlgParent(wxWindow *parent)
void SetDefaultDir(const wxString &dir)
void GetFilenames(vector< wxString > &filenames) const
void SetWildcard(const wxString &wildcard)
void x_SendFileTxtChangedEvt(CAdvancedFileInput *input, const wxString &txt)
wxFlexGridSizer * m_FileSizer
void SetDlgTitle(const wxString &title)
vector< wxString > m_SaveFilenames
void x_DeleteFilename(int link_id)
void OnBrowseBtn(wxCommandEvent &event)
void SetSingleMode(bool single)
virtual ~CMultiFileInput()
wxScrolledWindow * m_ScrollWnd
wxString GetWildcard() const
void Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name=wxT("panel"))
void SetDlgAttrs(const wxString &title, const wxString &dir, const wxString &wildcard, wxWindow *parent)
void OnLink(wxHyperlinkEvent &event)
void SetFilenames(const vector< wxString > &filenames)
wxString GetDefaultDir() const
void x_AddFilenameRow(const wxString &filename)
vector< CAdvancedFileInput * > m_Inputs
static const struct name_t names[]
#define false
Definition: bool.h:36
#define NULL
Definition: ncbistd.hpp:225
const CSeq_id & GetId(const CSeq_loc &loc, CScope *scope)
If all CSeq_ids embedded in CSeq_loc refer to the same CBioseq, returns the first CSeq_id found,...
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
END_EVENT_TABLE()
FILE * file
static int input()
int i
yy_size_t n
#define wxT(x)
Definition: muParser.cpp:41
constexpr bool empty(list< Ts... >) noexcept
const struct ncbi::grid::netcache::search::fields::SIZE size
static int filenames
Definition: pcre2grep.c:247
static static static wxID_ANY
#define _ASSERT
Modified on Fri Sep 20 14:57:58 2024 by modify_doxy.py rev. 669887