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

Go to the SVN repository for this file.

1 /* $Id: blast_db_dialog.cpp 44121 2019-10-31 15:23:32Z katargir $
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  * A dialog for browsing BLAST Databases.
30  */
31 
32 
33 #include <ncbi_pch.hpp>
34 
35 
38 
39 #include <wx/sizer.h>
40 #include <wx/bitmap.h>
41 #include <wx/icon.h>
42 #include <wx/button.h>
43 #include <wx/textctrl.h>
44 #include <wx/stattext.h>
45 #include <wx/treectrl.h>
46 #include <wx/wupdlock.h>
47 
48 
49 ////@begin XPM images
50 ////@end XPM images
51 
52 
54 
55 class CBLASTDlgItemData : public wxTreeItemData
56 {
57 public:
59 
61 };
62 
63 ///////////////////////////////////////////////////////////////////////////////
64 ///
66 : m_LabelPos(string::npos),
67  m_LabelLength(0),
68  m_Visible(true),
69  m_Expanded(false),
70  m_Parent(NULL),
71  m_ChildItems(NULL)
72 {
73 }
74 
75 CBLAST_Dlg_Item::CBLAST_Dlg_Item(const string& label, const string& path, bool is_database)
76 : //m_Label(label),
77  m_Path(path),
78  m_IsDatabase(is_database),
79  m_Visible(true),
80  m_Expanded(false),
81  m_Parent(NULL),
82  m_ChildItems(NULL)
83 {
84  m_LabelPos = path.find(label);
85  _ASSERT(m_LabelPos != string::npos);
86  m_LabelLength = label.size();
87 
88 }
89 
90 wxString CBLAST_Dlg_Item::GetLabel() const {
91  if (m_LabelLength == 0)
92  return wxT("");
93  return wxString(&m_Path[m_LabelPos], m_LabelLength);
94 }
95 
96 
98 {
99  m_Parent = NULL;
100  delete m_ChildItems;
101 }
102 
104 {
105  if(m_ChildItems) {
106  string l = label;
108  if(it != m_ChildItems->end()) {
109  return it->second;
110  }
111  }
112  return NULL;
113 }
114 
115 
117 {
118  _ASSERT(item.m_Parent == NULL);
119 // _ASSERT(m_ChildItems == NULL || m_ChildItems->find(item.m_Label) == m_ChildItems->end());
121 
122  if(m_ChildItems == NULL) {
124  }
126 // m_ChildItems->insert(TNameToItemMap::value_type(item.m_Label, CRef<CBLAST_Dlg_Item>(&item)));
127  item.m_Parent = this;
128 }
129 
130 
131 ///////////////////////////////////////////////////////////////////////////////
132 ///
133 IMPLEMENT_DYNAMIC_CLASS( CBLAST_DB_Dialog, CDialog )
134 
135 BEGIN_EVENT_TABLE( CBLAST_DB_Dialog, CDialog )
136 ////@begin CBLAST_DB_Dialog event table entries
137  EVT_INIT_DIALOG( CBLAST_DB_Dialog::OnInitDialog )
138  EVT_TEXT( ID_SEARCH, CBLAST_DB_Dialog::OnSearchTextUpdated )
139  EVT_BUTTON( ID_RESET_BTN, CBLAST_DB_Dialog::OnResetBtnClick )
140  EVT_TREE_SEL_CHANGED( ID_TREECTRL, CBLAST_DB_Dialog::OnTreectrlSelChanged )
141  EVT_TREE_ITEM_ACTIVATED( ID_TREECTRL, CBLAST_DB_Dialog::OnTreectrlItemActivated )
142  EVT_TREE_ITEM_COLLAPSED( ID_TREECTRL, CBLAST_DB_Dialog::OnTreectrlItemCollapsed )
143  EVT_TREE_ITEM_EXPANDED( ID_TREECTRL, CBLAST_DB_Dialog::OnTreectrlItemExpanded )
144  EVT_BUTTON( wxID_OK, CBLAST_DB_Dialog::OnOkClick )
145 ////@end CBLAST_DB_Dialog event table entries
147 
148 
150 {
151  Init();
152 }
153 
154 
155 CBLAST_DB_Dialog::CBLAST_DB_Dialog( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
156 {
157  Init();
158  Create(parent, id, caption, pos, size, style);
159 }
160 
161 
162 bool CBLAST_DB_Dialog::Create( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
163 {
164 ////@begin CBLAST_DB_Dialog creation
165  SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
166  CDialog::Create( parent, id, caption, pos, size, style );
167 
168  CreateControls();
169  if (GetSizer())
170  {
171  GetSizer()->SetSizeHints(this);
172  }
173  Centre();
174 ////@end CBLAST_DB_Dialog creation
175  return true;
176 }
177 
178 
180 {
181 ////@begin CBLAST_DB_Dialog destruction
182 ////@end CBLAST_DB_Dialog destruction
183 }
184 
185 
187 {
188 ////@begin CBLAST_DB_Dialog member initialisation
189  m_SearchCtrl = NULL;
190  m_StatusText = NULL;
191  m_TreeCtrl = NULL;
192  m_OKBtn = NULL;
193 ////@end CBLAST_DB_Dialog member initialisation
194  m_DbMap = NULL;
195 }
196 
197 
199 {
200 ////@begin CBLAST_DB_Dialog content construction
201  CBLAST_DB_Dialog* itemCDialog1 = this;
202 
203  wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
204  itemCDialog1->SetSizer(itemBoxSizer2);
205 
206  wxFlexGridSizer* itemFlexGridSizer3 = new wxFlexGridSizer(2, 2, 0, 0);
207  itemBoxSizer2->Add(itemFlexGridSizer3, 0, wxGROW|wxLEFT|wxRIGHT|wxTOP, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
208 
209  wxStaticText* itemStaticText4 = new wxStaticText( itemCDialog1, wxID_STATIC, _("Filter:"), wxDefaultPosition, wxDefaultSize, 0 );
210  itemFlexGridSizer3->Add(itemStaticText4, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
211 
212  wxBoxSizer* itemBoxSizer5 = new wxBoxSizer(wxHORIZONTAL);
213  itemFlexGridSizer3->Add(itemBoxSizer5, 0, wxGROW|wxALIGN_CENTER_VERTICAL, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
214 
215  m_SearchCtrl = new wxTextCtrl( itemCDialog1, ID_SEARCH, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
216  itemBoxSizer5->Add(m_SearchCtrl, 1, wxGROW|wxALL, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
217 
218  wxButton* itemButton7 = new wxButton( itemCDialog1, ID_RESET_BTN, _("Clear"), wxDefaultPosition, wxDefaultSize, 0 );
219  itemBoxSizer5->Add(itemButton7, 0, wxALIGN_CENTER_VERTICAL|wxALL, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
220 
221  itemFlexGridSizer3->Add(wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x, wxDLG_UNIT(itemCDialog1, wxSize(-1, 5)).y, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
222 
223  m_StatusText = new wxStaticText( itemCDialog1, wxID_STATUS, _("Filter:"), wxDefaultPosition, wxDefaultSize, 0 );
224  itemFlexGridSizer3->Add(m_StatusText, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
225 
226  itemFlexGridSizer3->AddGrowableCol(1);
227 
228  m_TreeCtrl = new wxTreeCtrl( itemCDialog1, ID_TREECTRL, wxDefaultPosition, wxDLG_UNIT(itemCDialog1, wxSize(240, 160)), wxTR_HAS_BUTTONS |wxTR_FULL_ROW_HIGHLIGHT|wxTR_HIDE_ROOT|wxTR_SINGLE|wxTR_GBENCH_LINES );
229  itemBoxSizer2->Add(m_TreeCtrl, 1, wxGROW|wxALL, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
230 
231  wxStdDialogButtonSizer* itemStdDialogButtonSizer11 = new wxStdDialogButtonSizer;
232 
233  itemBoxSizer2->Add(itemStdDialogButtonSizer11, 0, wxALIGN_RIGHT|wxALL, wxDLG_UNIT(itemCDialog1, wxSize(5, -1)).x);
234  m_OKBtn = new wxButton( itemCDialog1, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 );
235  itemStdDialogButtonSizer11->AddButton(m_OKBtn);
236 
237  wxButton* itemButton13 = new wxButton( itemCDialog1, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
238  itemStdDialogButtonSizer11->AddButton(itemButton13);
239 
240  itemStdDialogButtonSizer11->Realize();
241 
242 ////@end CBLAST_DB_Dialog content construction
243 }
244 
245 
247 {
248  return true;
249 }
250 
251 
252 wxBitmap CBLAST_DB_Dialog::GetBitmapResource( const wxString& name )
253 {
254  // Bitmap retrieval
255 ////@begin CBLAST_DB_Dialog bitmap retrieval
256  wxUnusedVar(name);
257  return wxNullBitmap;
258 ////@end CBLAST_DB_Dialog bitmap retrieval
259 }
260 
261 
262 wxIcon CBLAST_DB_Dialog::GetIconResource( const wxString& name )
263 {
264  // Icon retrieval
265 ////@begin CBLAST_DB_Dialog icon retrieval
266  wxUnusedVar(name);
267  return wxNullIcon;
268 ////@end CBLAST_DB_Dialog icon retrieval
269 }
270 
271 
272 void CBLAST_DB_Dialog::SetToolName(const string& tool)
273 {
274  string s = tool + " - Select BLAST Databases";
275  SetTitle(ToWxString(s));
276 }
277 
278 
280 {
281  m_DbMap = &map;
282 }
283 
284 
285 void CBLAST_DB_Dialog::SelectDatabases(vector<string>& databases)
286 {
287  if( ! databases.empty()) {
288  m_SelDatabase = databases[0];
289  }
290 }
291 
292 
293 void CBLAST_DB_Dialog::GetSelectedDatabases(vector<string>& databases)
294 {
295  databases.push_back(m_SelDatabase);
296 }
297 
298 
299 void CBLAST_DB_Dialog::OnSearchTextUpdated( wxCommandEvent& event )
300 {
301  wxString s_val = m_SearchCtrl->GetValue();
302 
303  string query = ToStdString(s_val);
305 }
306 
307 
308 void CBLAST_DB_Dialog::OnResetBtnClick( wxCommandEvent& event )
309 {
310  m_SearchCtrl->SetValue(wxT(""));
312 }
313 
314 
315 void CBLAST_DB_Dialog::OnInitDialog( wxInitDialogEvent& event )
316 {
317  CDialog::OnInitDialog(event);
318 
319  GUI_AsyncExec([this](ICanceled&) { this->x_CreateItems(); }, wxT("Building list of BLAST DBs..."));
320 
322 
323  // select databases
325  CBLAST_Dlg_Item& ch_item = **it;
326  if(ch_item.GetPath() == m_SelDatabase) {
327  m_TreeCtrl->SelectItem(ch_item.GetId());
328  }
329  }
330 }
331 
332 
334 {
335  // clean old data, this should delete all previously created items
337  m_CatItems.clear();
338  m_DbItems.clear();
339 
340  if (!m_DbMap)
341  return;
342 
343  vector<string> tokens;
344 
345  // build the new item hierarchy
346  ITERATE(TDbMap, it, *m_DbMap) {
347  const string& path = it->first;
348  tokens.clear();
349  NStr::Split(path, "/", tokens);
351  CBLAST_Dlg_Item* new_item = NULL;
352  size_t n = tokens.size();
353  for (size_t i = 0; i < n; ++i) {
354  const string& label = tokens[i];
355  if (i < n - 1) {
356  // try to find the item for category
357  new_item = item->GetChildByLabel(label);
358  if (new_item == NULL) {
359  // create a category item
360  new_item = new CBLAST_Dlg_Item(label, path);
361  item->AddChild(*new_item);
362  m_CatItems.push_back(new_item);
363  }
364  }
365  else {
366  // last item - create a DB item
367  new_item = new CBLAST_Dlg_Item(label, path, true);
368  item->AddChild(*new_item);
369  m_DbItems.push_back(new_item);
370  }
371  item = new_item;
372  }
373  }
374 }
375 
376 
378 {
379  if(item.IsVisible()) {
380  const CBLAST_Dlg_Item* parent = item.GetParent();
381 // const string& label = item.GetLabel();
382  wxString label = item.GetLabel();
383 
384  // create wxTreeItem for this item
385  wxTreeItemId id;
387  if(parent) {
388  id = m_TreeCtrl->AppendItem(parent->GetId(), label,
389  -1, -1, data);
390  item.SetId(id);
391  } else {
392  id = m_TreeCtrl->AddRoot(label, -1, -1, data);
393  item.SetId(id);
394  }
395 
396  // process child items recursively
398  if(items) {
400  CBLAST_Dlg_Item& ch_item = *it->second;
401  if(ch_item.IsVisible()) {
402  x_BuildTreeItems(ch_item);
403  }
404  }
405  if(parent) {
406  if(item.IsExpanded()) {
407  m_TreeCtrl->Expand(id);
408  } else {
409  m_TreeCtrl->Collapse(id);
410  }
411  }
412  }
413  }
414 }
415 
416 
417 // completely rebuilds all wxTreeItems in the Tree Control
419 {
420  wxWindowUpdateLocker locker(m_TreeCtrl);
421 
422  if(m_Root) {
423  m_TreeCtrl->UnselectAll();
424  m_TreeCtrl->DeleteAllItems();
425 
427  }
428 }
429 
430 
432 {
433  if(m_Root) {
434  wxBusyCursor wait;
435  wxWindowUpdateLocker locker(m_TreeCtrl);
436  bool reset = query.empty();
437  int n_vis = 0;
438 
439  // make all categories invisible by default
441  CBLAST_Dlg_Item& ch_item = **it;
442  ch_item.SetVisible(false);
443  }
444 
445  // iterate on all DB items and set Visible flag
447  CBLAST_Dlg_Item& ch_item = **it;
448  bool vis = true;
449  if( ! reset) {
450  // const string& label = ch_item.GetLabel();
451  string label = ToStdString(ch_item.GetLabel());
452 
453  vis = (NStr::FindNoCase(label, query) != string::npos);
454  }
455  ch_item.SetVisible(vis);
456 
457  if(vis) {
458  n_vis++;
459 
460  // mark parent category items as visible
461  CBLAST_Dlg_Item* parent = ch_item.GetParent();
462  while(parent && ! parent->IsVisible()) {
463  parent->SetVisible(true);
464  parent = parent->GetParent();
465  }
466  }
467  }
468 
470 
471  x_UpdateFilterStatusText(reset, n_vis);
472  }
473 }
474 
475 
477 {
478  string status = reset ? "All " : "Filtered - ";
479  if( ! reset && n == 0) {
480  status += "no matches";
481  } else {
482  status += NStr::IntToString(n);
483  status += " Database";
484  status += (n != 1 ? "s are shown" : " is shown");
485  }
486 
487  m_StatusText->SetLabel(ToWxString(status));
488 }
489 
490 
492 {
493  x_UpdateCollapsedState(event.GetItem());
494 }
495 
496 
498 {
499  x_UpdateCollapsedState(event.GetItem());
500 }
501 
502 
503 void CBLAST_DB_Dialog::OnTreectrlSelChanged( wxTreeEvent& event )
504 {
505  bool db_item = false;
506 
507  wxTreeItemId id = m_TreeCtrl->GetSelection();
508  if(id.IsOk()) {
509  wxTreeItemData* data = m_TreeCtrl->GetItemData(id);
510  CBLASTDlgItemData* ex_data = dynamic_cast<CBLASTDlgItemData*>(data);
511  db_item = ex_data->m_Item->IsDatabase();
512  }
513 
514  m_OKBtn->Enable(db_item);
515 }
516 
517 
519 {
521 }
522 
523 
524 void CBLAST_DB_Dialog::OnOkClick( wxCommandEvent& event )
525 {
527 }
528 
529 
531 {
533  if(item) {
534  m_SelDatabase = item->GetPath();
535  EndModal(wxID_OK);
536  }
537 }
538 
539 
541 {
542  wxTreeItemId id = m_TreeCtrl->GetSelection();
543 
544  if(id.IsOk()) {
545  wxTreeItemData* data = m_TreeCtrl->GetItemData(id);
546  CBLASTDlgItemData* ex_data = dynamic_cast<CBLASTDlgItemData*>(data);
547  CBLAST_Dlg_Item* item = ex_data->m_Item.GetPointer();
548  if (item->IsDatabase())
549  return item;
550  }
551  return NULL;
552 }
553 
554 
556 {
557  bool open = m_TreeCtrl->IsExpanded(id);
558 
559  wxTreeItemData* data = m_TreeCtrl->GetItemData(id);
560  CBLASTDlgItemData* ex_data = dynamic_cast<CBLASTDlgItemData*>(data);
561  ex_data->m_Item->Expand(open);
562 }
563 
564 
std::invoke_result< _Fty, ICanceled & >::type GUI_AsyncExec(_Fty &&_Fnarg, const wxString &msg=wxT("Accessing network..."))
Definition: async_call.hpp:130
CRef< CBLAST_Dlg_Item > m_Item
CBLASTDlgItemData(CBLAST_Dlg_Item *item)
CBLAST_DB_Dialog.
CDialog.
Definition: dialog.hpp:47
virtual void EndModal(int retCode)
Definition: dialog.cpp:142
Interface for testing cancellation request in a long lasting operation.
Definition: icanceled.hpp:51
container_type::iterator iterator
Definition: map.hpp:54
const_iterator end() const
Definition: map.hpp:152
iterator_bool insert(const value_type &val)
Definition: map.hpp:165
container_type::value_type value_type
Definition: map.hpp:52
const_iterator find(const key_type &key) const
Definition: map.hpp:153
Definition: map.hpp:338
#define _(proto)
Definition: ct_nlmzip_i.h:78
#define true
Definition: bool.h:35
#define false
Definition: bool.h:36
static void Init(void)
Definition: cursor6.c:76
char data[12]
Definition: iconv.c:80
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
CRef< CBLAST_Dlg_Item > m_Root
void OnTreectrlSelChanged(wxTreeEvent &event)
bool IsExpanded() const
deque< CBLAST_Dlg_Item * > TItemDeque
void AddChild(CBLAST_Dlg_Item &item)
CBLAST_Dlg_Item * x_GetSelectedDBItem()
CBLAST_Dlg_Item * GetParent()
void x_BuildTreeItems(CBLAST_Dlg_Item &item)
void x_UpdateCollapsedState(wxTreeItemId id)
wxTreeCtrl * m_TreeCtrl
void OnOkClick(wxCommandEvent &event)
void OnTreectrlItemCollapsed(wxTreeEvent &event)
const string & GetPath() const
void Expand(bool expand)
void SelectDatabases(vector< string > &databases)
void SetVisible(bool visible)
void OnInitDialog(wxInitDialogEvent &event)
void GetSelectedDatabases(vector< string > &databases)
void x_FilterItems(const string &query)
void OnTreectrlItemExpanded(wxTreeEvent &event)
map< wxString, CRef< CBLAST_Dlg_Item > > TNameToItemMap
CBLAST_Dlg_Item * m_Parent
TNameToItemMap * m_ChildItems
void x_UpdateFilterStatusText(bool reset, int n)
TNameToItemMap * GetChildItems()
CBLAST_Dlg_Item * GetChildByLabel(const string &label)
bool IsDatabase() const
const TDbMap * m_DbMap
void SetDBMap(const TDbMap &map)
void SetToolName(const string &tool)
wxStaticText * m_StatusText
void SetId(const wxTreeItemId &id)
const wxTreeItemId & GetId() const
bool IsVisible() const
wxIcon GetIconResource(const wxString &name)
void OnTreectrlItemActivated(wxTreeEvent &event)
void OnResetBtnClick(wxCommandEvent &event)
wxTextCtrl * m_SearchCtrl
static bool ShowToolTips()
bool Create(wxWindow *parent, wxWindowID id=ID_CBLAST_DB_DIALOG, const wxString &caption=wxEmptyString, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(400, 300), long style=wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU|wxCLOSE_BOX|wxTAB_TRAVERSAL)
CBLASTDatabases::TDbMap TDbMap
wxBitmap GetBitmapResource(const wxString &name)
wxString GetLabel() const
void OnSearchTextUpdated(wxCommandEvent &event)
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define kEmptyStr
Definition: ncbistr.hpp:123
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3461
static SIZE_TYPE FindNoCase(const CTempString str, const CTempString pattern, SIZE_TYPE start, SIZE_TYPE end, EOccurrence which=eFirst)
Find the pattern in the specified range of a string using a case insensitive search.
Definition: ncbistr.cpp:2993
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5084
static const char label[]
END_EVENT_TABLE()
int i
yy_size_t n
#define ID_TREECTRL
#define wxT(x)
Definition: muParser.cpp:41
const struct ncbi::grid::netcache::search::fields::SIZE size
static string query
#define _ASSERT
static void SetTitle(CRef< CSeq_entry > entry, string title)
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
string ToStdString(const wxString &s)
Definition: wx_utils.hpp:161
#define wxTR_GBENCH_LINES
Definition: wx_utils.hpp:69
Modified on Sun Apr 21 03:41:22 2024 by modify_doxy.py rev. 669887