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

Go to the SVN repository for this file.

1 /* $Id: seq_table_grid.cpp 47479 2023-05-02 13:24:02Z ucko $
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: Colleen Bollin
27  */
28 
29 
30 #include <ncbi_pch.hpp>
31 #include <wx/sizer.h>
32 #include <wx/msgdlg.h>
33 #include <wx/dc.h>
34 #include <wx/settings.h>
35 #include <wx/dcclient.h>
36 
37 #include <wx/textdlg.h>
38 #include <wx/tokenzr.h>
39 #include <wx/clipbrd.h>
40 
41 ////@begin includes
42 ////@end includes
43 
54 
55 
58 
59 
61 {
62 }
63 
65 {
66  for (auto a : m_cache)
67  {
68  a.second->DecRef();
69  }
70  m_cache.clear();
71 }
72 
73 wxGridCellAttr *CSeqGridCellAttrProvider::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind /* = wxGridCellAttr::Any */) const
74 {
75  wxGridCellAttr *attr = NULL;
76 
77  switch (kind)
78  {
79  case (wxGridCellAttr::Any):
80  case (wxGridCellAttr::Cell):
81  {
82  auto it = m_cache.find(make_pair(row, col));
83  if (it != m_cache.end())
84  {
85  attr = it->second;
86  attr->IncRef();
87  }
88  }
89  break;
90 
91  case (wxGridCellAttr::Col):
92  attr = wxGridCellAttrProvider::GetAttr(row, col, kind);
93  break;
94 
95  case (wxGridCellAttr::Row):
96  attr = wxGridCellAttrProvider::GetAttr(row, col, kind);
97  break;
98 
99  default:
100  break;
101  }
102 
103  return attr;
104 }
105 
106 void CSeqGridCellAttrProvider::SetAttr(wxGridCellAttr *attr, int row, int col)
107 {
108  auto it = m_cache.find(make_pair(row, col));
109  if (it == m_cache.end())
110  {
111  if (attr)
112  {
113  attr->IncRef();
114  m_cache[make_pair(row, col)] = attr;
115  }
116  }
117  else
118  {
119  it->second->DecRef();
120  if (attr)
121  {
122  attr->IncRef();
123  it->second = attr;
124  }
125  else
126  {
127  m_cache.erase(it);
128  }
129  }
130 }
131 
133  wxWindowID id,
134  const wxPoint& pos,
135  const wxSize& size,
136  long style,
137  const wxString& name)
138  {
139  wxGrid::Init();
140  wxGrid::Create(parent, id, pos, size, style, name);
141  }
142 
144 {
145  if ( wxGrid::m_rowHeights.IsEmpty() )
146  {
147  // need to really create the array
148  wxGrid::InitRowHeights();
149  }
150  m_diffs.clear();
151  m_diffs.resize( m_numRows, 0);
152 }
153 
154 int CCollapsibleGrid::UpdateRowOrColSize(int& sizeCurrent, int sizeNew)
155 {
156  // On input here sizeCurrent can be negative if it's currently hidden (the
157  // real size is its absolute value then). And sizeNew can be 0 to indicate
158  // that the row/column should be hidden or -1 to indicate that it should be
159  // shown again.
160 
161  if ( sizeNew < 0 )
162  {
163  // We're showing back a previously hidden row/column.
164  wxASSERT_MSG( sizeNew == -1, wxS("New size must be positive or -1.") );
165 
166  // If it's already visible, simply do nothing.
167  if ( sizeCurrent >= 0 )
168  return 0;
169 
170  // Otherwise show it by restoring its old size.
171  sizeCurrent = -sizeCurrent;
172 
173  // This is positive which is correct.
174  return sizeCurrent;
175  }
176  else if ( sizeNew == 0 )
177  {
178  // We're hiding a row/column.
179 
180  // If it's already hidden, simply do nothing.
181  if ( sizeCurrent <= 0 )
182  return 0;
183 
184  // Otherwise hide it and also remember the shown size to be able to
185  // restore it later.
186  sizeCurrent = -sizeCurrent;
187 
188  // This is negative which is correct.
189  return sizeCurrent;
190  }
191  else // We're just changing the row/column size.
192  {
193  // Here it could have been hidden or not previously.
194  const int sizeOld = sizeCurrent < 0 ? 0 : sizeCurrent;
195 
196  sizeCurrent = sizeNew;
197 
198  return sizeCurrent - sizeOld;
199  }
200 }
201 
202 void CCollapsibleGrid::FastSetRowSize(int row, int height)
203 {
204  const int diff = UpdateRowOrColSize(wxGrid::m_rowHeights[row], height);
205  m_diffs[row] += diff;
206 }
207 
209 {
210  int diff = 0;
211  for ( int i = 0; i < m_numRows; i++ )
212  {
213  diff += m_diffs[i];
214  wxGrid::m_rowBottoms[i] += diff;
215  }
216 
217  InvalidateBestSize();
218 }
219 
220 
221 // CGridCellWrapStringRenderer
222 
224  const wxGridCellAttr& attr,
225  wxDC& dc,
226  bool isSelected)
227 {
228  dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT );
229 
230  // TODO some special colours for attr.IsReadOnly() case?
231 
232  // different coloured text when the grid is disabled
233  if ( grid.IsThisEnabled() )
234  {
235  if ( isSelected )
236  {
237  wxColour clr;
238  if ( grid.HasFocus() )
239  clr = grid.GetSelectionBackground();
240  else
241  clr = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW);
242  dc.SetTextBackground( clr );
243  dc.SetTextForeground( grid.GetSelectionForeground() );
244  }
245  else
246  {
247  dc.SetTextBackground( attr.GetBackgroundColour() );
248  dc.SetTextForeground( attr.GetTextColour() );
249  }
250  }
251  else
252  {
253  dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
254  dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
255  }
256 
257  dc.SetFont( attr.GetFont() );
258 }
259 
261  wxGridCellAttr& attr,
262  wxDC& dc,
263  const wxRect& rectCell,
264  int row, int col,
265  bool isSelected) {
266 
267 
268  wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
269 
270  // now we only have to draw the text
271  SetTextColoursAndFont(grid, attr, dc, isSelected);
272 
273  int horizAlign, vertAlign;
274  attr.GetAlignment(&horizAlign, &vertAlign);
275 
276  wxRect rect = rectCell;
277  rect.Inflate(-1);
278 
279  wxString text = BreakLines(grid.GetCellValue(row, col));
280 
281  grid.DrawTextRectangle(dc, text, rect, horizAlign, vertAlign);
282 }
283 
284 
285 wxSize CGridCellWrapStringRenderer::GetBestSize(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, int row, int col)
286 {
287  dc.SetFont(attr.GetFont());
288  wxString text = BreakLines(grid.GetCellValue(row, col));
289  wxCoord w, h, lineHeight;
290  dc.GetMultiLineTextExtent(text, &w, &h, &lineHeight);
291  return wxSize(w, h);
292 }
293 
295 {
296  const size_t chunk = 40;
297  wxString out;
298  for (size_t i = 0; i < text.Length(); i += chunk)
299  {
300  size_t len = min(chunk, text.Length() - i);
301  out << text.Mid(i, len) << "\n";
302  }
303  return out;
304 }
305 
306 // CSeqTableGrid
307 
309  : m_ValuesTable(values_table)
310 {
311  SetAttrProvider(new CSeqGridCellAttrProvider);
312 }
313 
315 {
316  return m_ValuesTable->GetNum_rows();
317 }
319 {
320  return static_cast<int>(m_ValuesTable->GetColumns().size()) - 1;
321 }
322 bool CSeqTableGrid::IsEmptyCell(int row, int col)
323 {
324  return false;
325 }
326 
327 wxString CSeqTableGrid::GetValue(int row, int col)
328 {
329  size_t pos = col + 1;
330  size_t row_num = row;
331  if (m_ValuesTable->GetColumns().size() > pos && m_ValuesTable->GetColumns()[pos]->GetData().GetSize() > row_num) {
333  string val = "";
334  if (column->GetData().IsString()) {
335  val = column->GetData().GetString()[row_num];
336  }
337  else if (column->GetData().IsId()) {
338  column->GetData().GetId()[row]->GetLabel(&val, objects::CSeq_id::eContent);
339  }
340  else if (column->GetData().IsInt()) {
341  val = NStr::NumericToString(column->GetData().GetInt()[row_num]);
342  }
343  return wxString(val);
344  }
345  else {
346  return wxEmptyString;
347  }
348 }
349 
350 void CSeqTableGrid::SetValue(int vis_row, int vis_col, const wxString& value)
351 {
352  size_t vcol = vis_col + 1;
353  size_t vrow = vis_row;
354  if (m_ValuesTable->GetColumns().size() > vcol) {
355  CRef<objects::CSeqTable_column> col = m_ValuesTable->GetColumns()[vcol];
356  if (col->GetData().IsString()) {
357  while (col->GetData().GetSize() <= vrow) {
358  col->SetData().SetString().push_back("");
359  }
360  col->SetData().SetString()[vrow] = value.ToStdString();
361  }
362  else if (col->GetData().IsInt()) {
363  col->SetData().SetInt()[vrow] = NStr::StringToInt(value.ToStdString());
364  }
365  else {
366  col->SetData().SetString()[vrow] = value.ToStdString();
367  }
368  }
369 }
370 
371 bool CSeqTableGrid::InsertCols(size_t pos, size_t numCols)
372 {
373  size_t skip = 0;
374  objects::CSeq_table::TColumns::iterator it = m_ValuesTable->SetColumns().begin();
375  while (it != m_ValuesTable->SetColumns().end() && skip < pos + 1) {
376  it++;
377  skip++;
378  }
379 
380  for (size_t i = 0; i < numCols; i++) {
381  CRef< objects::CSeqTable_column > last_col(new objects::CSeqTable_column());
382  last_col->SetData().SetString();
383  m_ValuesTable->SetColumns().insert(it, last_col);
384  }
385  if (GetView())
386  {
387  wxGridTableMessage msg(this,
388  wxGRIDTABLE_NOTIFY_COLS_INSERTED,
389  static_cast<int>(pos),
390  static_cast<int>(numCols));
391 
392  GetView()->ProcessTableMessage(msg);
393  }
394  return true;
395 }
396 
397 bool CSeqTableGrid::AppendCols(size_t numCols)
398 {
399  for (size_t i = 0; i < numCols; i++) {
400  CRef< objects::CSeqTable_column > last_col(new objects::CSeqTable_column());
401  last_col->SetData().SetString();
402  m_ValuesTable->SetColumns().push_back(last_col);
403  }
404 
405  if (GetView())
406  {
407  wxGridTableMessage msg(this,
408  wxGRIDTABLE_NOTIFY_COLS_APPENDED,
409  static_cast<int>(numCols),
410  static_cast<int>(numCols));
411 
412  GetView()->ProcessTableMessage(msg);
413  }
414  return true;
415 }
416 
417 bool CSeqTableGrid::DeleteCols(size_t pos, size_t numCols)
418 {
419  if (pos + numCols < m_ValuesTable->SetColumns().size())
420  {
421  m_ValuesTable->SetColumns().erase(m_ValuesTable->SetColumns().begin() + pos, m_ValuesTable->SetColumns().begin() + pos + numCols);
422 
423  if (GetView())
424  {
425  wxGridTableMessage msg(this,
426  wxGRIDTABLE_NOTIFY_COLS_DELETED,
427  static_cast<int>(pos),
428  static_cast<int>(numCols));
429 
430  GetView()->ProcessTableMessage(msg);
431  }
432  }
433  return true;
434 }
435 
437 {
439  string label = "";
440  size_t r = row;
441  if (id_col && id_col->GetData().GetSize() > r) {
442  id_col->GetData().GetId()[r]->GetLabel(&label, objects::CSeq_id::eContent);
443  }
444  else {
446  }
447  return wxString(label);
448 }
449 
451 {
452  wxString label;
453  size_t c = col + 1;
454  if (m_ValuesTable->GetColumns().size() > c) {
456  if (column->IsSetHeader()) {
457  if (column->GetHeader().IsSetTitle()) {
458  label = column->GetHeader().GetTitle();
459  }
460  else if (column->GetHeader().IsSetField_name()) {
461  label = column->GetHeader().GetField_name();
462  }
463  }
464  }
465  return label;
466 }
467 
468 void CSeqTableGrid::SetColLabelValue(int col, const wxString& label)
469 {
470  size_t c = col + 1;
471  if (m_ValuesTable->GetColumns().size() > c) {
472  m_ValuesTable->SetColumns()[c]->SetHeader().SetTitle(label.ToStdString());
473  }
474 }
475 
476 /*!
477  * CSeqTableGridPanel type definition
478  */
479 
480 IMPLEMENT_DYNAMIC_CLASS( CSeqTableGridPanel, wxPanel )
481 
482 
483 /*!
484  * CSeqTableGridPanel event table definition
485  */
486 
487 BEGIN_EVENT_TABLE( CSeqTableGridPanel, wxPanel )
488 
489 ////@begin CSeqTableGridPanel event table entries
490  EVT_GRID_CELL_RIGHT_CLICK( CSeqTableGridPanel::OnCellRightClick )
491  EVT_GRID_LABEL_RIGHT_CLICK( CSeqTableGridPanel::OnLabelRightClick )
492 
493 ////@end CSeqTableGridPanel event table entries
494  EVT_GRID_CELL_LEFT_CLICK( CSeqTableGridPanel::OnCellLeftClick )
495  EVT_GRID_CELL_LEFT_DCLICK( CSeqTableGridPanel::OnCellDoubleLeftClick )
496  EVT_GRID_LABEL_LEFT_CLICK( CSeqTableGridPanel::OnLabelLeftClick )
497  EVT_GRID_LABEL_LEFT_DCLICK( CSeqTableGridPanel::OnLabelLeftDClick )
498  EVT_GRID_COL_SORT( CSeqTableGridPanel::OnSortTableByColumn )
509 
510 
511 /*!
512  * CSeqTableGridPanel constructors
513  */
514 
516 {
517  Init();
518 }
519 
520 CSeqTableGridPanel::CSeqTableGridPanel( wxWindow* parent, CRef<CSeq_table> values_table, CRef<CSeq_table> choices, int glyph_col,
521  wxWindowID id, const wxPoint& pos, const wxSize& size, long style )
522  : m_Table(values_table), m_Choices(choices), m_Copied (NULL), m_CollapseGlyphCol(glyph_col)
523 {
524  Init();
525  Create(parent, id, pos, size, style);
526 }
527 
528 
529 /*!
530  * CSeqTableGrid creator
531  */
532 
533 bool CSeqTableGridPanel::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style )
534 {
535 ////@begin CSeqTableGridPanel creation
536  wxPanel::Create( parent, id, pos, size, style );
537 
538  CreateControls();
539  if (GetSizer())
540  {
541  GetSizer()->SetSizeHints(this);
542  }
543  Centre();
544 ////@end CSeqTableGridPanel creation
545  return true;
546 }
547 
548 
549 /*!
550  * CSeqTableGridPanel destructor
551  */
552 
554 {
555 ////@begin CSeqTableGridPanel destruction
556 ////@end CSeqTableGridPanel destruction
557 }
558 
559 
560 /*!
561  * Member initialisation
562  */
563 
565 {
566 ////@begin CSeqTableGridPanel member initialisation
567 ////@end CSeqTableGridPanel member initialisation
568  x_SetUpMenu();
569  m_SortByRowLabel = false;
570  m_SortByRowLabelAscend = false;
571  m_CollapseCol = -1;
572  m_SortCol = -1;
573  m_MenuCol = -1;
574  m_Modified = false;
575  m_edit_cell_row = -1;
576  m_edit_cell_col = -1;
577 }
578 
579 
580 /*!
581  * Control creation for CSeqTableGrid
582  */
583 
585 {
586 ////@begin CSeqTableGridPanel content construction
587  // Generated by DialogBlocks, 10/06/2013 17:54:14 (unregistered)
588 
589  CSeqTableGridPanel* itemPanel1 = this;
590 
591  wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
592  itemPanel1->SetSizer(itemBoxSizer2);
593 
594  CCollapsibleGrid* itemGrid3 = new CCollapsibleGrid( itemPanel1, ID_GRID, wxDefaultPosition, wxSize(600, 300), wxSUNKEN_BORDER|wxHSCROLL|wxVSCROLL|wxTAB_TRAVERSAL );
595  itemGrid3->SetDefaultColSize(50);
596  itemGrid3->SetDefaultRowSize(25);
597  itemGrid3->SetColLabelSize(25);
598  itemGrid3->SetRowLabelSize(100);
599  itemGrid3->SetDefaultRenderer(new CGridCellWrapStringRenderer());
600  itemGrid3->CreateGrid(5, 5, wxGrid::wxGridSelectCells);
601  itemBoxSizer2->Add(itemGrid3, 0, wxGROW|wxALL, 5);
602 
603 ////@end CSeqTableGridPanel content construction
604  m_Grid = itemGrid3;
605  CSeqTableGrid *gridAdapter = new CSeqTableGrid(m_Table);
606  m_Grid->SetTable(gridAdapter, true);
609  m_Grid->Connect(wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(CSeqTableGridPanel::CopyPasteDataByKeyboard), (wxObject*) NULL, this); // connect m_Grid to ctrl-v/ctrl-c event handlers
610  m_Grid->SetTabBehaviour(wxGrid::Tab_Leave);
611 }
612 
614 {
616  m_Grid->AutoSizeRows(false);
617  x_SortTableByColumn(col,true);
618  m_CollapseCol = col;
620 }
621 
623 {
624  if (pos < m_Grid->GetNumberCols()) {
625  for (int i = 0; i < m_Grid->GetNumberRows(); i++) {
626  m_Grid->GetOrCreateCellAttr(i, pos)->SetReadOnly(val);
627  }
628  if (val)
630  else
632  }
633 }
634 
635 
636 void CSeqTableGridPanel::MakeColumnReadOnly(string name, bool val)
637 {
638  int pos = m_Grid->GetNumberCols();
639  for (int i = 0; i < m_Grid->GetNumberCols(); i++) {
640  if (NStr::EqualNocase(ToStdString(m_Grid->GetColLabelValue(i)), name)) {
641  pos = i;
642  break;
643  }
644  }
645 
646  MakeColumnReadOnly(pos, val);
647 }
648 
649 
651 {
652  for (int c = 0; c < m_Grid->GetNumberCols(); c++) {
653  MakeColumnReadOnly(c, true);
654  }
655 }
656 
657 
659 {
660  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
661  if (!gridAdapter) {
662  return;
663  }
664  CRef<objects::CSeq_table> values_table = gridAdapter->GetValuesTable();
665  if (!values_table) {
666  return;
667  }
668 
669  int problem_pos = m_Grid->GetNumberCols();
670  for (int i = 0; i < m_Grid->GetNumberCols(); i++) {
671  if (NStr::EqualNocase(ToStdString(m_Grid->GetColLabelValue(i)), kProblems)) {
672  problem_pos = i;
673  break;
674  }
675  }
676  MakeColumnReadOnly(problem_pos);
677 }
678 
679 
681 {
682  int lines = 1;
683  for (int i = 0; i < m_Grid->GetNumberCols(); i++) {
684  string label = ToStdString(m_Grid->GetColLabelValue(i));
685  size_t pos = NStr::Find(label, "\n");
686  int lines_this_column = 1;
687  while (pos != string::npos) {
688  lines_this_column++;
689  pos = NStr::Find(label, "\n", pos + 1);
690  }
691  if (lines_this_column > lines) {
692  lines = lines_this_column;
693  }
694  }
695  int l_height = m_Grid->GetColLabelSize();
696  m_Grid->SetColLabelSize( lines * l_height );
697 }
698 
699 
700 void CSeqTableGridPanel::UpdateColumnChoices(int pos, vector<string> choices)
701 {
702  if (!m_Choices) {
703  if (choices.empty()) {
704  // no choices before, no new choices, nothing to do
705  return;
706  }
707  m_Choices = new objects::CSeq_table();
708  CRef<objects::CSeqTable_column> col(new objects::CSeqTable_column());
709  m_Choices->SetColumns().push_back(col);
710  }
711 
712  while (pos >= m_Choices->GetColumns().size()) {
713  CRef<objects::CSeqTable_column> col(new objects::CSeqTable_column());
714  m_Choices->SetColumns().push_back(col);
715  }
716  m_Choices->SetColumns()[pos]->ResetData();
717  if (!choices.empty()) {
718  CRef<objects::CSeqTable_column> col = m_Choices->SetColumns()[pos];
719  ITERATE (vector<string>, it, choices) {
720  col->SetData().SetString().push_back(*it);
721  }
722  wxArrayString val_list;
723  size_t max_len = 10;
724  wxClientDC dc(this);
725  for (size_t j = 0; j < col->GetData().GetString().size(); j++) {
726  string val = col->GetData().GetString()[j];
727  val_list.push_back(ToWxString(val));
728  wxSize text_size = dc.GetTextExtent(val);
729  size_t this_len = text_size.GetWidth();
730  if (this_len > max_len) {
731  max_len = this_len;
732  }
733  }
734  if (col->GetData().GetString().size() == 2
735  && IsSynonymForTrue(col->GetData().GetString()[0])
736  && IsSynonymForFalse(col->GetData().GetString()[1])) {
737  wxGridCellBoolEditor::UseStringValues(wxT("true"), wxEmptyString);
738  for (int row = 0; row < m_Grid->GetNumberRows(); row++) {
739  m_Grid->SetCellEditor(row, pos, new wxGridCellBoolEditor ());
740  }
741  m_Grid->AutoSizeColLabelSize(pos);
742  } else {
743  for (int row = 0; row < m_Grid->GetNumberRows(); row++) {
744  m_Grid->SetCellEditor(row, pos, new wxGridCellChoiceEditor (val_list, false));
745  }
746  m_Grid->SetColMinimalWidth(pos, static_cast<int>(max_len + wxSYS_VSCROLL_X));
747  m_Grid->SetColSize(pos, static_cast<int>(max_len + wxSYS_VSCROLL_X));
748  }
749  } else {
750  for (int row = 0; row < m_Grid->GetNumberRows(); row++) {
751  m_Grid->SetCellEditor(row, pos, new wxGridCellTextEditor ());
752  }
753  m_Grid->AutoSizeColLabelSize(pos);
754  }
755  m_Grid->AutoSizeRows(false);
756 }
757 
758 
760 {
761  if (m_Choices) {
762  int i = 0;
763  for (; i < m_Choices->GetColumns().size(); i++) {
764  CConstRef<CSeqTable_column> col = m_Choices->GetColumns()[i];
765  if (col->IsSetData() && col->GetData().IsString() && col->GetData().GetString().size() > 0) {
766  wxArrayString val_list;
767  size_t max_len = 10;
768  wxClientDC dc(this);
769  for (size_t j = 0; j < col->GetData().GetString().size(); j++) {
770  string val = col->GetData().GetString()[j];
771  val_list.push_back(ToWxString(val));
772  wxSize text_size = dc.GetTextExtent(val);
773  size_t this_len = text_size.GetWidth();
774  if (this_len > max_len) {
775  max_len = this_len;
776  }
777  }
778  if (col->GetData().GetString().size() == 2
779  && IsSynonymForTrue(col->GetData().GetString()[0])
780  && IsSynonymForFalse(col->GetData().GetString()[1])) {
781  wxGridCellBoolEditor::UseStringValues(wxT("true"), wxEmptyString);
782  for (int row = 0; row < m_Grid->GetNumberRows(); row++) {
783  m_Grid->SetCellEditor(row, i, new wxGridCellBoolEditor ());
784  }
785  m_Grid->AutoSizeColLabelSize(i);
786  } else {
787  for (int row = 0; row < m_Grid->GetNumberRows(); row++) {
788  m_Grid->SetCellEditor(row, i, new wxGridCellChoiceEditor (val_list, false));
789  }
790  m_Grid->SetColMinimalWidth(i, static_cast<int>(max_len + wxSYS_VSCROLL_X));
791  m_Grid->SetColSize(i, static_cast<int>(max_len + wxSYS_VSCROLL_X));
792  }
793  } else {
794  m_Grid->AutoSizeColLabelSize(i);
795  }
796  }
797  while (i < m_Grid->GetNumberCols()) {
798  string label = ToStdString(m_Grid->GetColLabelValue(i));
800  m_Grid->AutoSizeColumn(i);
801  } else {
802  m_Grid->AutoSizeColLabelSize(i);
803  }
804  i++;
805  }
806  } else {
807  m_Grid->AutoSizeColumns();
808  }
811 }
812 
813 
815 {
816  // calculate "best" table width
817  int sum = m_Grid->GetRowLabelSize();
818  for (int i = 0; i < m_Grid->GetNumberCols(); i++) {
819  sum += m_Grid->GetColSize(i);
820  }
821  return sum;
822 }
823 
824 
826 {
827  // calculate "best" table width
828  int sum = GetBestTableWidth();
829 
830  wxSize current_size = m_Grid->GetSize();
831  if (sum > current_size.x) {
832  current_size.x = sum;
833  m_Grid->SetMinClientSize(current_size);
834  }
835 }
836 
837 
838 /*!
839  * Should we show tooltips?
840  */
841 
843 {
844  return true;
845 }
846 
847 /*!
848  * Get bitmap resources
849  */
850 
851 wxBitmap CSeqTableGridPanel::GetBitmapResource( const wxString& name )
852 {
853  // Bitmap retrieval
854 ////@begin CSeqTableGridPanel bitmap retrieval
855  wxUnusedVar(name);
856  return wxNullBitmap;
857 ////@end CSeqTableGridPanel bitmap retrieval
858 }
859 
860 /*!
861  * Get icon resources
862  */
863 
864 wxIcon CSeqTableGridPanel::GetIconResource( const wxString& name )
865 {
866  // Icon retrieval
867 ////@begin CSeqTableGridPanel icon retrieval
868  wxUnusedVar(name);
869  return wxNullIcon;
870 ////@end CSeqTableGridPanel icon retrieval
871 }
872 
874 {
875  if (m_CollapseGlyphCol >= 0 && m_CollapseCol >= 0)
876  {
877  for (unordered_map<int, int>::iterator it=m_CollapseCell.begin(); it != m_CollapseCell.end(); ++it)
878  if (it->second == 1)
879  it->second = -1;
881  for (int i = 0; i < m_Grid->GetNumberRows(); i++)
882  m_Grid->SetCellValue(i,m_CollapseGlyphCol,wxEmptyString);
883  m_CollapseCol = -1;
885  m_CollapseCell.clear();
886  }
887 }
888 
889 
891 {
892  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
893  if( !gridAdapter ) {
895  return empty;
896  }
897  x_ExpandTable();
898  m_SortByRowLabelAscend = true;
900  CRef<objects::CSeq_table> values_table = gridAdapter->GetValuesTable();
901  return values_table;
902 }
903 
904 
906 {
907  CSeqTableGrid *gridAdapter = new CSeqTableGrid(table);
908  m_Grid->SetTable(gridAdapter, true);
911  m_Grid->ForceRefresh();
912 }
913 
914 
916 {
917  static bool registered = false;
918  if (!registered) {
919  registered = true;
920 
923  "Copy",
924  "Copy",
927  "Copy cell or cells");
929  "Paste",
930  "Paste",
933  "Paste cell or cells");
935  "Append",
936  "Append",
939  "Append to cell or cells");
941  "Paste from SeqID",
942  "Paste from SeqID",
945  "Paste to cell or cells from SeqId");
947  "Search",
948  "Search",
951  "Search Table");
953  "Delete",
954  "Delete",
957  "Delete Column");
959  "Rename",
960  "Rename",
963  "Rename Column");
965  "Collapse",
966  "Collapse",
969  "Collapse Column");
971  "Expand",
972  "Expand",
975  "Expand Column");
976  }
977 }
978 
979 
980 
981 static
982 WX_DEFINE_MENU(kEditSeqTableMenu)
992 WX_END_MENU()
993 
994 void CSeqTableGridPanel::x_CreateMenu( wxGridEvent& evt )
995 {
996  wxMenu* menu = CUICommandRegistry::GetInstance().CreateMenu(kEditSeqTableMenu);
997  if (menu) {
998  m_MenuCol = evt.GetCol();
999  m_Grid->PopupMenu(menu, evt.GetPosition());
1000  }
1001 }
1002 
1004 {
1005  m_MapRowLabelToIndex.clear();
1006  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
1007  if( !gridAdapter ) {
1008  return;
1009  }
1010  int num_rows = gridAdapter->GetNumberRows();
1011  for (int i=0; i<num_rows; i++)
1012  {
1013  string s = ToStdString(gridAdapter->GetRowLabelValue(i));
1014  m_MapRowLabelToIndex[s]= i;
1015  }
1016 }
1017 
1018 
1019 bool cmpTableValues(const pair< pair<string,int>,int> &a, const pair< pair<string,int>,int> &b) // we don't seem to have tuple yet (?!) so pairs it is
1020 {
1021  double l, r;
1022  if (a.first.first == b.first.first) return a.first.second < b.first.second;
1025  return l<r;
1026  return a.first.first < b.first.first;
1027 }
1028 
1029 /*!
1030  * wxEVT_GRID_COL_SORT event handler for ID_GRID
1031  */
1032 
1033 void CSeqTableGridPanel::OnSortTableByColumn( wxGridEvent& event ) // see "Sorting support" in http://docs.wxwidgets.org/trunk/classwx_grid.html
1034 {
1035  if (m_Grid->GetSortingColumn() == -1 || m_Grid->GetSortingColumn() == m_CollapseGlyphCol)
1036  {
1037  m_Grid->Refresh();
1038  return;
1039  }
1040 
1041  int col = m_Grid->GetSortingColumn();
1042  if (col != m_SortCol)
1043  {
1044  m_SortCol = col;
1045  return;
1046  }
1047  bool ascend = m_Grid->IsSortOrderAscending();
1048  x_ExpandTable();
1049  x_SortTableByColumn(col,ascend);
1050  m_CollapseCol = col;
1052  m_SortByRowLabel = true;
1053  m_SortByRowLabelAscend = true;
1054  m_Grid->Refresh();
1055 }
1056 
1058 {
1059  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
1060  if( !gridAdapter ) {
1061  return;
1062  }
1063  CRef<objects::CSeq_table> values_table = gridAdapter->GetValuesTable();
1064 
1065  CConstRef<objects::CSeqTable_column> column = values_table->GetColumns()[col+1];
1066  if (!column->IsSetData() || !column->GetData().IsString())
1067  {
1068  //m_Grid->Refresh();
1069  return;
1070  }
1071  int num_rows = 0;
1072  int num_cols = static_cast<int>(values_table->GetColumns().size());
1073 
1074  for (int j=0; j<num_cols; j++)
1075  {
1076  switch (values_table->GetColumns()[j]->GetData().Which())
1077  {
1079  if (values_table->SetColumns()[j]->SetData().SetId().size() > num_rows)
1080  num_rows = static_cast<int>(values_table->SetColumns()[j]->SetData().SetId().size());
1081  break;
1083  if (values_table->SetColumns()[j]->SetData().SetString().size() > num_rows)
1084  num_rows = static_cast<int>(values_table->SetColumns()[j]->SetData().SetString().size());
1085  break;
1086  default:
1087  break;
1088  }
1089  }
1090 
1091  vector<vector<bool> > selection(num_rows, vector<bool>(num_cols,false));
1092  for (int i=0; i<num_rows; i++)
1093  for (int j=0; j<num_cols; j++)
1094  if (m_Grid->IsInSelection(i,j))
1095  selection[i][j] = true;
1096 
1097  for (int j=0; j<num_cols; j++)
1098  {
1099  switch (values_table->GetColumns()[j]->GetData().Which())
1100  {
1102  values_table->SetColumns()[j]->SetData().SetId().resize(num_rows);
1103  break;
1105  values_table->SetColumns()[j]->SetData().SetString().resize(num_rows);
1106  break;
1107  default:
1108  break;
1109  }
1110  }
1111  CRef<objects::CSeq_table> old_table(new CSeq_table);
1112  old_table->Assign(*values_table);
1113 
1114  vector < pair< pair<string,int>,int> > sorted;
1115  for (int i=0; i<num_rows; i++)
1116  {
1117  string s1 = column->GetData().GetString()[i];
1118  string s2 = ToStdString(gridAdapter->GetRowLabelValue(i));
1119  pair<string,int> p(s1,m_MapRowLabelToIndex[s2]);
1120  sorted.push_back(pair< pair<string,int>,int>(p,i));
1121  }
1122  std::sort(sorted.begin(),sorted.end(),cmpTableValues);
1123 
1124  if (!ascend)
1125  std::reverse(sorted.begin(),sorted.end());
1126  m_Grid->ClearSelection();
1127  for (int i=0; i<num_rows; i++)
1128  {
1129  int old_i = sorted[i].second;
1130  for (int j=0; j<num_cols; j++)
1131  {
1132  switch (values_table->GetColumns()[j]->GetData().Which())
1133  {
1135  values_table->SetColumns()[j]->SetData().SetId()[i] = old_table->SetColumns()[j]->GetData().GetId()[old_i];
1136  break;
1138  values_table->SetColumns()[j]->SetData().SetString()[i] = old_table->SetColumns()[j]->GetData().GetString()[old_i];
1139  break;
1140  default:
1141  break;
1142  }
1143  if (selection[old_i][j])
1144  m_Grid->SelectBlock(i,j,i,j,true);
1145  }
1146  }
1147 }
1148 
1149 
1150 
1151 void CSeqTableGridPanel::x_UpdateCollapsedRow(unsigned int num_cols, int expand_row, vector<bool> &all_present, vector<bool> &all_same, vector<wxString> &values)
1152 {
1153  unordered_map<int, int>::iterator it = m_CollapseCell.find(expand_row);
1154  if (it == m_CollapseCell.end())
1155  return;
1156  for (unsigned int j = 0; j < num_cols; j++)
1157  if (j != m_CollapseCol && j != m_CollapseGlyphCol)
1158  {
1159  if (it->second == 1)
1160  {
1161  wxString val = m_Grid->GetCellValue(expand_row,j);
1162  if (val != _("All present, mixed") && val != _("Some missing, one unique") && val != _("Some missing, mixed") &&
1163  !(all_present[j] && all_same[j]))
1164  {
1165  m_CollapseCache[pair<int,int>(expand_row,j)] = m_Grid->GetCellValue(expand_row,j);
1166  }
1167  if (all_present[j] && !all_same[j])
1168  {
1169  m_Grid->SetCellValue(expand_row,j,_("All present, mixed"));
1170  m_Grid->GetOrCreateCellAttr(expand_row,j)->SetReadOnly(true);
1171  }
1172  if (!all_present[j] && all_same[j] && !values[j].IsEmpty())
1173  {
1174  m_Grid->SetCellValue(expand_row,j,_("Some missing, one unique"));
1175  m_Grid->GetOrCreateCellAttr(expand_row,j)->SetReadOnly(true);
1176  }
1177  if (!all_present[j] && !all_same[j])
1178  {
1179  m_Grid->SetCellValue(expand_row,j,_("Some missing, mixed"));
1180  m_Grid->GetOrCreateCellAttr(expand_row,j)->SetReadOnly(true);
1181  }
1182  }
1183  else
1184  {
1185  wxString val = m_Grid->GetCellValue(expand_row,j);
1186  if (val == _("All present, mixed") || val == _("Some missing, one unique") || val == _("Some missing, mixed"))
1187  m_Grid->SetCellValue(expand_row,j,m_CollapseCache[pair<int,int>(expand_row,j)]);
1189  m_Grid->GetOrCreateCellAttr(expand_row,j)->SetReadOnly(false);
1190  }
1191  values[j].Clear();
1192  all_present[j] = true;
1193  all_same[j] = true;
1194  }
1195  if (it->second == 1)
1196  m_Grid->SetCellValue(expand_row,m_CollapseGlyphCol,_("+"));
1197  else
1198  m_Grid->SetCellValue(expand_row,m_CollapseGlyphCol,_("-"));
1199 }
1200 
1201 
1203 {
1204  if (initialize)
1205  {
1207  m_CollapseCell.clear();
1208  m_Grid->SetRowMinimalAcceptableHeight(0);
1209  }
1210 
1211  if (!m_Grid || m_CollapseGlyphCol < 0 || m_CollapseCol < 0 || m_CollapseGlyphCol == m_CollapseCol) return;
1212  wxBusyCursor wait;
1213 
1214  unsigned int num_cols = m_Grid->GetNumberCols();
1215  unsigned int num_rows = m_Grid->GetNumberRows();
1216 
1217  bool collapse = false;
1218  vector<bool> all_present(num_cols,true),all_same(num_cols,true);
1219  vector<wxString> values(num_cols);
1220  int expand_row = -1;
1221 
1222  for (unsigned int i = 0; i < num_rows; i++)
1223  {
1224  unordered_map<int, int>::iterator it = m_CollapseCell.find(i);
1225  if (it != m_CollapseCell.end() && it->second == -1)
1226  {
1227  expand_row = i;
1228  continue;
1229  }
1230  if (expand_row >=0 && !m_Grid->IsRowShown(i))
1231  {
1232  for (unsigned int j = 0; j < num_cols; j++)
1233  if (!m_Grid->IsReadOnly(expand_row,j))
1234  m_Grid->SetCellValue(i,j,m_Grid->GetCellValue(expand_row,j));
1235  }
1236  if ((it != m_CollapseCell.end() && it->second == 1) || m_Grid->IsRowShown(i))
1237  expand_row = -1;
1238  }
1240  m_Grid->BeginBatch();
1241  expand_row = -1;
1242  for (unsigned int i = 0; i < num_rows; i++)
1243  {
1244  unordered_map<int, int>::iterator it = m_CollapseCell.find(i);
1245  if (!collapse && i > 0 && m_Grid->GetCellValue(i,m_CollapseCol) == m_Grid->GetCellValue(i-1,m_CollapseCol) && (it == m_CollapseCell.end() || it->second == 0))
1246  {
1247  collapse = true;
1248  for (unsigned j = 0; j < num_cols; j++)
1249  if (j != m_CollapseCol && j != m_CollapseGlyphCol)
1250  {
1251  if (m_Grid->GetCellValue(i-1,j).IsEmpty())
1252  all_present[j] = false;
1253  values[j] = m_Grid->GetCellValue(i-1,j);
1254  }
1255  expand_row = i-1;
1256  if (initialize)
1257  {
1258  m_CollapseCell[expand_row] = 1;
1259  m_Grid->SetCellAlignment(expand_row,m_CollapseGlyphCol,wxALIGN_CENTRE,wxALIGN_CENTRE);
1260  }
1261  }
1262 
1263  if (collapse && i > 0 &&( m_Grid->GetCellValue(i,m_CollapseCol) != m_Grid->GetCellValue(expand_row,m_CollapseCol) || (it != m_CollapseCell.end() && it->second != 0) ))
1264  {
1265  collapse = false;
1266  x_UpdateCollapsedRow(num_cols, expand_row, all_present, all_same, values);
1267  }
1268 
1269  if (collapse)
1270  {
1271  for (unsigned j = 0; j < num_cols; j++)
1272  if (j != m_CollapseCol && j != m_CollapseGlyphCol)
1273  {
1274  if (m_Grid->GetCellValue(i,j).IsEmpty())
1275  all_present[j] = false;
1276  else
1277  {
1278  if (values[j].IsEmpty())
1279  values[j] = m_Grid->GetCellValue(i,j);
1280  if (m_Grid->GetCellValue(i,j) != values[j])
1281  all_same[j] = false;
1282  }
1283  }
1284  unordered_map<int, int>::iterator it = m_CollapseCell.find(expand_row);
1285  if (it != m_CollapseCell.end() && it->second == 1)
1286  {
1287  m_Grid->FastSetRowSize(i, 0);
1288  }
1289  else
1290  {
1291  int row_size = m_Grid->GetRowSize(expand_row);
1292  m_Grid->FastSetRowSize(i,row_size);
1293  }
1294  }
1295  else
1296  m_Grid->SetCellValue(i,m_CollapseGlyphCol,wxEmptyString);
1297  }
1298 
1299  if (collapse && num_rows > 0)
1300  {
1301  unsigned int i = num_rows-1;
1302 
1303  x_UpdateCollapsedRow(num_cols, expand_row, all_present, all_same, values);
1304  unordered_map<int, int>::iterator it = m_CollapseCell.find(expand_row);
1305  if (it != m_CollapseCell.end() && it->second == 1)
1306  {
1307  m_Grid->FastSetRowSize(i, 0);
1308  }
1309  else
1310  {
1311  int row_size = m_Grid->GetRowSize(expand_row);
1312  m_Grid->FastSetRowSize(i,row_size);
1313  }
1314  }
1316  m_Grid->EndBatch();
1317 }
1318 
1320 {
1321  if (!m_Grid || m_CollapseGlyphCol < 0 || m_CollapseCol < 0 || m_CollapseGlyphCol == m_CollapseCol) return;
1322 
1323  wxBusyCursor wait;
1324  unsigned int num_cols = m_Grid->GetNumberCols();
1325  unsigned int num_rows = m_Grid->GetNumberRows();
1326 
1327  int expand_row = -1;
1328  vector<bool> all_present(num_cols,true),all_same(num_cols,true);
1329  vector<wxString> values(num_cols);
1331  m_Grid->BeginBatch();
1332  for (unsigned int i = 0; i < num_rows; i++)
1333  {
1334  unordered_map<int, int>::iterator it = m_CollapseCell.find(i);
1335  if (it != m_CollapseCell.end() && it->second == -1)
1336  {
1337  expand_row = i;
1338  continue;
1339  }
1340  if (expand_row >=0 && !m_Grid->IsRowShown(i))
1341  {
1342  for (unsigned j = 0; j < num_cols; j++)
1343  if (!m_Grid->IsReadOnly(expand_row,j))
1344  m_Grid->SetCellValue(i,j,m_Grid->GetCellValue(expand_row,j));
1345  int row_size = m_Grid->GetRowSize(expand_row);
1346  m_Grid->FastSetRowSize(i,row_size);
1347  }
1348  else if (m_Grid->IsRowShown(i))
1349  expand_row = -1;
1350  }
1351 
1352  for (unsigned int i = 0; i < num_rows; i++)
1353  {
1354  unordered_map<int, int>::iterator it = m_CollapseCell.find(i);
1355  if (it != m_CollapseCell.end() && it->second == -1)
1356  {
1357  m_Grid->SetCellValue(i,m_CollapseGlyphCol,wxEmptyString);
1358  x_UpdateCollapsedRow(num_cols, i, all_present, all_same, values);
1359  }
1360  }
1362  m_Grid->EndBatch();
1363 }
1364 
1366 {
1367  wxWindow* w = this->GetParent();
1368  while (w != NULL) {
1369  SrcEditDialog* parent = dynamic_cast<SrcEditDialog*>(w);
1370  if (parent) {
1371  return parent;
1372  } else {
1373  w = w->GetParent();
1374  }
1375  }
1376  return NULL;
1377 }
1378 
1379 void CSeqTableGridPanel::OnRenameColumn( wxCommandEvent& event )
1380 {
1381  SrcEditDialog* dlg = x_GetParent();
1382  if (!dlg)
1383  {
1384  m_MenuCol = -1;
1385  return;
1386  }
1387 
1388  if (!m_Grid->IsSelection())
1389  {
1390  m_MenuCol = -1;
1391  wxMessageBox( wxT("Please select a single column to rename"), wxT("Error"), wxOK | wxICON_ERROR, this);
1392  return;
1393  }
1394 
1395  const wxGridCellCoordsArray& selected_blocks = m_Grid->GetSelectionBlockTopLeft();
1396  size_t num_blocks = selected_blocks.size();
1397 
1398  const wxArrayInt& cols = m_Grid->GetSelectedCols();
1399  size_t num_cols = cols.size();
1400 
1401  const wxGridCellCoordsArray& selected_block_right = m_Grid->GetSelectionBlockBottomRight();
1402  if (num_blocks != selected_block_right.size()) {
1403  m_MenuCol = -1;
1404  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
1405  return;
1406  }
1407 
1408  int col = -1;
1409  if (num_blocks == 1)
1410  {
1411  int left_col = selected_blocks[0].GetCol();
1412  int right_col = selected_block_right[0].GetCol();
1413  num_cols = right_col - left_col + 1;
1414  if (num_cols == 1)
1415  col = left_col;
1416  }
1417  else if (num_cols == 1)
1418  col = cols[0];
1419 
1420  if ( col >= 0 )
1421  {
1422  wxArrayString srcModNameStrings;
1423  dlg->GetQualChoices(srcModNameStrings);
1424  CRenameColumnDlg choice(NULL, srcModNameStrings);
1425  if (choice.ShowModal() == wxID_OK)
1426  {
1427  wxString qual = choice.GetSelection();
1428  choice.Close();
1429  if (!qual.IsEmpty())
1430  {
1431  m_Modified = true;
1432  m_Grid->GetTable()->SetColLabelValue(col, qual);
1433  dlg->ChangeColumnName(col, ToStdString(qual));
1434  dlg->ResetSubPanels();
1435  m_Grid->Refresh();
1436  }
1437  }
1438  }
1439  else
1440  wxMessageBox( wxT("Please select a single column to rename"), wxT("Error"), wxOK | wxICON_ERROR, this);
1441  m_MenuCol = -1;
1442 }
1443 
1444 void CSeqTableGridPanel::OnCollapseColumn( wxCommandEvent& event )
1445 {
1446  if (m_CollapseGlyphCol < 0 )
1447  {
1448  m_MenuCol = -1;
1449  wxMessageBox( wxT("This table was not set as collapsible"), wxT("Error"), wxOK | wxICON_ERROR, this);
1450  return;
1451  }
1452 
1453  if ( m_MenuCol >= 0 && m_MenuCol != m_CollapseGlyphCol) //m_SetOfReadOnlyCols.find(col) == m_SetOfReadOnlyCols.end() )
1454  {
1455  x_ExpandTable();
1459  }
1460  else
1461  wxMessageBox( wxT("Please select a single editable column to collapse"), wxT("Error"), wxOK | wxICON_ERROR, this);
1462  m_MenuCol = -1;
1463 }
1464 
1465 void CSeqTableGridPanel::OnExpandColumn( wxCommandEvent& event )
1466 {
1467  if (m_CollapseCol < 0 )
1468  {
1469  m_MenuCol = -1;
1470  wxMessageBox( wxT("This table does not have a collapsed column"), wxT("Error"), wxOK | wxICON_ERROR, this);
1471  return;
1472  }
1473 
1474  x_ExpandTable();
1475  m_MenuCol = -1;
1476 }
1477 
1479 {
1480  int col = m_CollapseCol;
1481  x_ExpandTable();
1482  return col;
1483 }
1484 
1486 {
1487  x_ExpandTable();
1488  m_CollapseCol = col;
1490 }
1491 
1492 void CSeqTableGridPanel::OnDeleteColumn( wxCommandEvent& event )
1493 {
1494  SrcEditDialog* dlg = x_GetParent();
1495  if (!dlg)
1496  {
1497  m_MenuCol = -1;
1498  return;
1499  }
1500 
1501  if (!m_Grid->IsSelection()) {
1502  m_MenuCol = -1;
1503  return;
1504  }
1505  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
1506  if( !gridAdapter ) {
1507  m_MenuCol = -1;
1508  return;
1509  }
1510 
1511  const wxGridCellCoordsArray& selected_blocks = m_Grid->GetSelectionBlockTopLeft();
1512  size_t num_blocks = selected_blocks.size();
1513 
1514  const wxArrayInt& cols = m_Grid->GetSelectedCols();
1515  size_t num_cols = cols.size();
1516 
1517  if (num_blocks == 0 && num_cols == 0) {
1518  wxMessageBox( wxT("Nothing selected!"), wxT("Error"), wxOK | wxICON_ERROR, this);
1519  return;
1520  } else if (num_blocks > 1) {
1521  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
1522  return;
1523  }
1524  const wxGridCellCoordsArray& selected_block_right = m_Grid->GetSelectionBlockBottomRight();
1525  if (num_blocks != selected_block_right.size()) {
1526  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
1527  return;
1528  }
1529 
1530  m_Modified = true;
1531  int collapse_col = m_CollapseCol;
1532  x_ExpandTable();
1533  int shift_glyph = 0;
1534  int shift_col = 0;
1535  if (num_blocks == 1)
1536  {
1537  int left_col = selected_blocks[0].GetCol();
1538  int right_col = selected_block_right[0].GetCol();
1539  for (int i = left_col; i <= right_col; i++)
1540  {
1541  gridAdapter->DeleteCols(i+1,1);
1542  if (m_CollapseGlyphCol == i)
1543  m_CollapseGlyphCol = -1;
1544  if (collapse_col == i)
1545  collapse_col = -1;
1546  if (i < m_CollapseGlyphCol)
1547  shift_glyph++;
1548  if (i < collapse_col)
1549  shift_col++;
1550 
1551  }
1552  }
1553  else if (num_cols > 0)
1554  {
1555  for (unsigned int i = 0; i < num_cols; i++)
1556  {
1557  gridAdapter->DeleteCols(cols[i] + 1,1);
1558  if (m_CollapseGlyphCol == cols[i])
1559  m_CollapseGlyphCol = -1;
1560  if (collapse_col == cols[i])
1561  collapse_col = -1;
1562  if (cols[i] < m_CollapseGlyphCol)
1563  shift_glyph++;
1564  if (cols[i] < collapse_col)
1565  shift_col++;
1566 
1567  }
1568  }
1569 
1570  if (m_CollapseGlyphCol >= 0 && collapse_col >= 0)
1571  {
1572  m_CollapseGlyphCol -= shift_glyph;
1573  m_CollapseCol = collapse_col - shift_col;
1575  }
1576 
1577  dlg->x_RepopulateAddQualList();
1578  dlg->ResetSubPanels();
1579  m_Grid->Refresh();
1580  m_MenuCol = -1;
1581 }
1582 
1583 
1584 
1585 /*!
1586  * wxEVT_COMMAND_BUTTON_CLICKED event handler for eCmdCopyTableValues
1587  */
1588 void CSeqTableGridPanel::OnCopyCells( wxCommandEvent& event )
1589 {
1590  x_OnCopyCells();
1591  m_MenuCol = -1;
1592 }
1593 
1595 {
1596  if (!m_Grid->IsSelection()) {
1597  return;
1598  }
1599 
1600  const wxGridCellCoordsArray& selected_blocks = m_Grid->GetSelectionBlockTopLeft();
1601  size_t num_blocks = selected_blocks.size();
1602 
1603  const wxArrayInt& rows = m_Grid->GetSelectedRows();
1604  int num_rows = static_cast<int>(rows.size());
1605 
1606  const wxArrayInt& cols = m_Grid->GetSelectedCols();
1607  size_t num_cols = cols.size();
1608 
1609  if (num_blocks == 0 && num_rows == 0 && num_cols == 0) {
1610  wxMessageBox( wxT("Nothing selected!"), wxT("Error"), wxOK | wxICON_ERROR, this);
1611  return;
1612  } else if (num_blocks > 1
1613  || (num_blocks > 0 && num_rows > 0)
1614  || (num_blocks > 0 && num_cols > 0)
1615  || (num_rows > 0 && num_cols > 0)) {
1616  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
1617  return;
1618  }
1619  const wxGridCellCoordsArray& selected_block_right = m_Grid->GetSelectionBlockBottomRight();
1620  if (num_blocks != selected_block_right.size()) {
1621  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
1622  return;
1623  }
1624 
1625  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
1626  if( !gridAdapter ) {
1627  return;
1628  }
1629  CRef<objects::CSeq_table> values_table = gridAdapter->GetValuesTable();
1630 
1631  m_Copied.Reset(new objects::CSeq_table());
1632  int top_row = 0;
1633  int left_col = 0;
1634  int bot_row = values_table->GetNum_rows() - 1;
1635  int right_col = static_cast<int>(values_table->GetColumns().size()) - 1;
1636  if (num_blocks == 1) {
1637  top_row = selected_blocks[0].GetRow();
1638  left_col = selected_blocks[0].GetCol();
1639  bot_row = selected_block_right[0].GetRow();
1640  right_col = selected_block_right[0].GetCol();
1641  num_rows = bot_row - top_row + 1;
1642  num_cols = right_col - left_col + 1;
1643 
1644  for (unsigned int i = 0; i < num_cols; i++) {
1645  CConstRef<objects::CSeqTable_column> old_column = values_table->GetColumns()[left_col + i + 1];
1646  CRef<objects::CSeqTable_column> new_column(new objects::CSeqTable_column());
1647  new_column->SetHeader().Assign(old_column->GetHeader());
1648  unsigned j;
1649  if (old_column->IsSetData() && old_column->GetData().IsString())
1650  for (j = (unsigned)top_row; j <= (unsigned)bot_row && j < old_column->GetData().GetString().size(); j++) {
1651  if (j < old_column->GetData().GetString().size()) {
1652  new_column->SetData().SetString().push_back(old_column->GetData().GetString()[j]);
1653  } else {
1654  new_column->SetData().SetString().push_back("");
1655  }
1656  }
1657  m_Copied->SetColumns().push_back(new_column);
1658  }
1659  m_Copied->SetNum_rows(num_rows);
1660  } else if (num_cols > 0) {
1661  for (unsigned int i = 0; i < num_cols; i++) {
1662  CConstRef<objects::CSeqTable_column> old_column = values_table->GetColumns()[cols[i] + 1];
1663  CRef<objects::CSeqTable_column> new_column(new objects::CSeqTable_column());
1664  new_column->Assign(*old_column);
1665  if (old_column->IsSetData() && old_column->GetData().IsString())
1666  while (new_column->GetData().GetString().size() < values_table->GetNum_rows()) {
1667  new_column->SetData().SetString().push_back("");
1668  }
1669  m_Copied->SetColumns().push_back(new_column);
1670  }
1671  m_Copied->SetNum_rows(values_table->GetNum_rows());
1672  } else if (num_rows > 0) {
1673  for (unsigned int i = 1; i < values_table->GetColumns().size(); i++) {
1674  CConstRef<objects::CSeqTable_column> old_column = values_table->GetColumns()[i];
1675  CRef<objects::CSeqTable_column> new_column(new objects::CSeqTable_column());
1676  new_column->SetHeader().Assign(old_column->GetHeader());
1677  for (unsigned int j = 0; j < num_rows; j++) {
1678  if (j<rows.size() && old_column->IsSetData() && old_column->GetData().IsString() && rows[j] < old_column->GetData().GetString().size()) {
1679  string str = old_column->GetData().GetString()[rows[j]];
1680  new_column->SetData().SetString().push_back(str);
1681  } else {
1682  new_column->SetData().SetString().push_back("");
1683  }
1684  }
1685  m_Copied->SetColumns().push_back(new_column);
1686  }
1687  m_Copied->SetNum_rows(num_rows);
1688  }
1689 }
1690 
1691 
1695  int top, int bot)
1696 {
1697  int j, k = 0;
1698  for (j = top; j <= bot; j++) {
1699  while (dst->SetData().SetInt().size() <= j) {
1700  dst->SetData().SetInt().push_back(0);
1701  }
1702  if (src->GetData().IsInt()) {
1703  dst->SetData().SetInt()[j] = src->GetData().GetInt()[k];
1704  } else if (src->GetData().IsString()) {
1705  dst->SetData().SetInt()[j] = NStr::StringToInt(src->GetData().GetString()[k]);
1706  } else {
1707  // skip it
1708  }
1709  k++;
1710  if (k >= src->GetData().GetSize()) {
1711  k = 0;
1712  }
1713  }
1714 
1715 }
1716 
1717 
1721  int top, int bot,
1722  bool append, string delim)
1723 {
1724  int j, k = 0;
1725  for (j = top; j <= bot; j++) {
1726  while (dst->SetData().SetString().size() <= j) {
1727  dst->SetData().SetString().push_back("");
1728  }
1729 
1730  string val = "";
1731  if (src->GetData().IsString()) {
1732  val = src->GetData().GetString()[k];
1733  } else if (src->GetData().IsInt()) {
1734  val = NStr::NumericToString(src->GetData().GetInt()[k]);
1735  }
1736  if (!append || NStr::IsBlank(val)) {
1737  dst->SetData().SetString()[j] = val;
1738  } else {
1739  dst->SetData().SetString()[j] += delim + val;
1740  }
1741 
1742  k++;
1743  if (k >= src->GetData().GetSize()) {
1744  k = 0;
1745  }
1746  }
1747 }
1748 
1749 
1750 static void s_CopyColumn
1753  int top, int bot,
1754  bool append, string delim)
1755 {
1756  if (dst->GetData().IsInt()) {
1757  s_CopyToIntColumn(src, dst, top, bot);
1758  } else if (dst->GetData().IsString()) {
1759  s_CopyToStringColumn(src, dst, top, bot, append, delim);
1760  } else {
1761  wxMessageBox( wxT("Bad column type!"), wxT("Error"), wxOK | wxICON_ERROR, NULL);
1762  }
1763 
1764 }
1765 
1766 
1767 static void s_CopyRow
1770  int left, int right, int src_row, int dst_row,
1771  bool append, string delim)
1772 {
1773  int j, k = 0;
1774 
1775  for (j = left; j <= right; j++) {
1776  CConstRef<objects::CSeqTable_column> src_col = src->GetColumns()[k];
1777  CRef<objects::CSeqTable_column> dst_col = dst->SetColumns()[j];
1778  while (dst_col->SetData().SetString().size() <= dst_row) {
1779  dst_col->SetData().SetString().push_back("");
1780  }
1781  if (src_col->IsSetData() && src_col->GetData().IsString())
1782  {
1783  if (!append || NStr::IsBlank(dst_col->SetData().SetString()[dst_row])) {
1784  dst_col->SetData().SetString()[dst_row] = src_col->GetData().GetString()[src_row];
1785  } else {
1786  dst_col->SetData().SetString()[dst_row] += delim + src_col->GetData().GetString()[src_row];
1787  }
1788  }
1789 
1790  k++;
1791  if (k >= src->GetColumns().size()) {
1792  k = 0;
1793  }
1794  }
1795 }
1796 
1797 
1799 {
1800  if (!m_Choices || m_Choices->GetColumns().size() <= col_pos) {
1801  // ok because there is no set choice list for this column
1802  return true;
1803  }
1804  CConstRef<CSeqTable_column> choices = m_Choices->GetColumns()[col_pos];
1805  if (!choices->IsSetData() || !choices->GetData().IsString()) {
1806  // ok because there is no set choice list for this column
1807  return true;
1808  }
1809  if (values->IsSetData() && values->GetData().IsString())
1810  for (size_t i = 0; i < values->GetData().GetString().size(); i++) {
1811  string new_val = values->GetData().GetString()[i];
1812  bool found = false;
1813  for (size_t j = 0; j < choices->GetData().GetString().size() && !found; j++) {
1814  string option = choices->GetData().GetString()[j];
1815  if (NStr::Equal(new_val, option)) {
1816  found = true;
1817  }
1818  }
1819  if (!found) {
1820  return false;
1821  }
1822  }
1823  return true;
1824 }
1825 
1826 
1828 {
1829  if (!m_Grid->IsSelection()) {
1830  return;
1831  }
1832 
1833  const wxGridCellCoordsArray& selected_blocks = m_Grid->GetSelectionBlockTopLeft();
1834  size_t num_blocks = selected_blocks.size();
1835 
1836  const wxArrayInt& rows = m_Grid->GetSelectedRows();
1837  size_t num_rows = rows.size();
1838 
1839  const wxArrayInt& cols = m_Grid->GetSelectedCols();
1840  size_t num_cols = cols.size();
1841 
1842  if (num_blocks == 0 && num_rows == 0 && num_cols == 0) {
1843  wxMessageBox( wxT("Nothing selected!"), wxT("Error"), wxOK | wxICON_ERROR, this);
1844  return;
1845  } else if (num_blocks > 1
1846  || (num_blocks > 0 && num_rows > 0)
1847  || (num_blocks > 0 && num_cols > 0)
1848  || (num_rows > 0 && num_cols > 0)) {
1849  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
1850  return;
1851  }
1852  const wxGridCellCoordsArray& selected_block_right = m_Grid->GetSelectionBlockBottomRight();
1853  if (num_blocks != selected_block_right.size()) {
1854  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
1855  return;
1856  }
1857 
1858  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
1859  if( !gridAdapter ) {
1860  return;
1861  }
1862  CRef<objects::CSeq_table> values_table = gridAdapter->GetValuesTable();
1863 
1864  int top_row = 0;
1865  int left_col = 0;
1866  int bot_row = values_table->GetNum_rows() - 1;
1867  int right_col = static_cast<int>(values_table->GetColumns().size() - 1);
1868  if (num_blocks == 1) {
1869  top_row = selected_blocks[0].GetRow();
1870  left_col = selected_blocks[0].GetCol();
1871  bot_row = selected_block_right[0].GetRow();
1872  right_col = selected_block_right[0].GetCol();
1873  num_rows = bot_row - top_row + 1;
1874  num_cols = right_col - left_col + 1;
1875 
1876  if (num_rows % copied->GetNum_rows() != 0 || num_cols % copied->GetColumns().size() != 0) {
1877  wxMessageBox( wxT("Source size does not match destination size!"), wxT("Error"), wxOK | wxICON_ERROR, this);
1878  return;
1879  }
1880  // check to make sure that column types match
1881  int j = 0;
1882  for (int i = left_col; i <= right_col; i++) {
1883  CRef<objects::CSeqTable_column> new_column = values_table->SetColumns()[i + 1];
1884  CConstRef<objects::CSeqTable_column> cpy_column = copied->GetColumns()[j];
1885  if (!x_ValuesOkForNewColumn (cpy_column, i)) {
1886  wxMessageBox( wxT("Source values are inappropriate for destination values!"), wxT("Error"), wxOK | wxICON_ERROR, this);
1887  return;
1888  }
1889  j++;
1890  if (j >= copied->GetColumns().size()) {
1891  j = 0;
1892  }
1893  }
1894  // then paste
1895  j = 0;
1896  for (int i = left_col; i <= right_col; i++) {
1897  CRef<objects::CSeqTable_column> new_column = values_table->SetColumns()[i + 1];
1898  CConstRef<objects::CSeqTable_column> cpy_column = copied->GetColumns()[j];
1899  s_CopyColumn (cpy_column, new_column, top_row, bot_row, append, delim);
1900  j++;
1901  if (j >= copied->GetColumns().size()) {
1902  j = 0;
1903  }
1904  }
1905  } else if (num_cols > 0) {
1906  if (num_cols % copied->GetColumns().size() != 0) {
1907  wxMessageBox( wxT("Source size does not match destination size!"), wxT("Error"), wxOK | wxICON_ERROR, this);
1908  return;
1909  }
1910  // check to make sure that column types match
1911  int j = 0;
1912  for (int i = 0; i < num_cols; i++) {
1913  CRef<objects::CSeqTable_column> new_column = values_table->SetColumns()[cols[i] + 1];
1914  CConstRef<objects::CSeqTable_column> cpy_column = copied->GetColumns()[j];
1915  if (!x_ValuesOkForNewColumn (cpy_column, cols[i])) {
1916  wxMessageBox( wxT("Source values are inappropriate for destination values!"), wxT("Error"), wxOK | wxICON_ERROR, this);
1917  return;
1918  }
1919  j++;
1920  if (j >= copied->GetColumns().size()) {
1921  j = 0;
1922  }
1923  }
1924 
1925  // then paste
1926  j = 0;
1927  for (int i = 0; i < num_cols; i++) {
1928  CRef<objects::CSeqTable_column> new_column = values_table->SetColumns()[cols[i] + 1];
1929  CConstRef<objects::CSeqTable_column> cpy_column = copied->GetColumns()[j];
1930  s_CopyColumn (cpy_column, new_column, 0, values_table->GetNum_rows() - 1, append, delim);
1931  j++;
1932  if (j >= copied->GetColumns().size()) {
1933  j = 0;
1934  }
1935  }
1936  } else if (num_rows > 0) {
1937  // TODO
1938  // check to make sure that column types match
1939  int j = 0;
1940  for (int i = 1; i < values_table->GetColumns().size(); i++) {
1941  if (!x_ValuesOkForNewColumn(copied->GetColumns()[j], i - 1)) {
1942  wxMessageBox( wxT("Source values are inappropriate for destination values!"), wxT("Error"), wxOK | wxICON_ERROR, this);
1943  return;
1944  }
1945  j++;
1946  if (j >= copied->GetColumns().size()) {
1947  j = 0;
1948  }
1949  }
1950 
1951  // then paste
1952  j = 0;
1953  for (int i = 0; i < num_rows; i++) {
1954  s_CopyRow (copied, values_table, 1, static_cast<int>(values_table->GetColumns().size()) - 1, j, rows[i], append, delim);
1955  j++;
1956  if (j >= copied->GetNum_rows()) {
1957  j = 0;
1958  }
1959  }
1960  }
1961  m_Modified = true;
1962  m_Grid->Refresh();
1963 }
1964 
1965 
1966 /*!
1967  * wxEVT_COMMAND_BUTTON_CLICKED event handler for eCmdPasteTableValues
1968  */
1969 
1970 void CSeqTableGridPanel::OnPasteCells( wxCommandEvent& event )
1971 {
1972  x_OnPasteCells();
1973  m_MenuCol = -1;
1974 }
1975 
1977 {
1978  if (!m_Copied || !m_Copied->IsSetColumns() || !m_Copied->IsSetNum_rows()
1979  || m_Copied->GetColumns().size() == 0 || m_Copied->GetNum_rows() == 0) {
1980  wxTheClipboard->Open();
1981  wxTextDataObject data;
1982  wxTheClipboard->GetData( data );
1983  string val = ToStdString(data.GetText());
1984  if (!m_Copied) {
1985  m_Copied.Reset(new objects::CSeq_table());
1986  }
1987  if (!m_Copied->IsSetColumns() || m_Copied->GetColumns().size() == 0) {
1988  CRef<objects::CSeqTable_column> col(new objects::CSeqTable_column());
1989  m_Copied->SetColumns().push_back(col);
1990  }
1991  m_Copied->SetColumns().front()->SetData().SetString().push_back(val);
1992  m_Copied->SetNum_rows(1);
1993  wxTheClipboard->Close();
1994  }
1996 }
1997 
1998 
1999 /*!
2000  * wxEVT_COMMAND_BUTTON_CLICKED event handler for eCmdAppendTableValues
2001  */
2002 
2003 void CSeqTableGridPanel::OnPasteAppendCells( wxCommandEvent& event )
2004 {
2005  x_PasteCells (m_Copied, true);
2006  m_MenuCol = -1;
2007 }
2008 
2009 
2010 /*!
2011  * wxEVT_COMMAND_BUTTON_CLICKED event handler for eCmdCopyTableValuesFromId
2012  */
2013 
2014 void CSeqTableGridPanel::OnCopyCellsFromId( wxCommandEvent& event )
2015 {
2016  if (!m_Grid->IsSelection()) {
2017  wxMessageBox( wxT("Nothing selected!"), wxT("Error"), wxOK | wxICON_ERROR, this);
2018  return;
2019  }
2020  const wxArrayInt& rows = m_Grid->GetSelectedRows();
2021  size_t num_rows = rows.size();
2022  if (num_rows > 0) {
2023  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
2024  return;
2025  }
2026 
2027  const wxGridCellCoordsArray& selected_blocks = m_Grid->GetSelectionBlockTopLeft();
2028  size_t num_blocks = selected_blocks.size();
2029 
2030  const wxArrayInt& cols = m_Grid->GetSelectedCols();
2031  size_t num_cols = cols.size();
2032 
2033  if (num_blocks == 0 && num_cols == 0) {
2034  wxMessageBox( wxT("Nothing selected!"), wxT("Error"), wxOK | wxICON_ERROR, this);
2035  return;
2036  } else if (num_blocks > 1
2037  || (num_blocks > 0 && num_cols > 0)) {
2038  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
2039  return;
2040  }
2041  const wxGridCellCoordsArray& selected_block_right = m_Grid->GetSelectionBlockBottomRight();
2042  if (num_blocks != selected_block_right.size()) {
2043  wxMessageBox( wxT("Selection is too complex"), wxT("Error"), wxOK | wxICON_ERROR, this);
2044  return;
2045  }
2046 
2047  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
2048  if( !gridAdapter ) {
2049  return;
2050  }
2051  CRef<objects::CSeq_table> values_table = gridAdapter->GetValuesTable();
2052 
2053  // populate copy_data with ID values
2054  CRef<objects::CSeq_table> copy_data (new objects::CSeq_table());
2055 
2056  int top_row = 0;
2057  int bot_row = values_table->GetNum_rows() - 1;
2058  num_rows = values_table->GetNum_rows();
2059  if (num_blocks == 1) {
2060  top_row = selected_blocks[0].GetRow();
2061  bot_row = selected_block_right[0].GetRow();
2062  num_rows = bot_row - top_row + 1;
2063  }
2064 
2065  CConstRef<objects::CSeqTable_column> id_column = values_table->GetColumns()[0];
2066  CRef<objects::CSeqTable_column> new_column(new objects::CSeqTable_column());
2067  new_column->SetHeader().SetTitle("Copied ID");
2068 
2069  for (int j = top_row; j <= bot_row; j++) {
2070  string label = "";
2071  id_column->GetData().GetId()[j]->GetLabel (&label, objects::CSeq_id::eContent);
2072  new_column->SetData().SetString().push_back(label);
2073  }
2074  copy_data->SetColumns().push_back(new_column);
2075  copy_data->SetNum_rows(static_cast<CSeq_table::TNum_rows>(num_rows));
2076 
2077  x_PasteCells (copy_data);
2078  m_MenuCol = -1;
2079 }
2080 
2081 
2082 /*!
2083  * wxEVT_GRID_CELL_RIGHT_CLICK event handler for ID_GRID
2084  */
2085 
2086 void CSeqTableGridPanel::OnCellRightClick( wxGridEvent& event )
2087 {
2088  x_CreateMenu(event);
2089 }
2090 
2091 void CSeqTableGridPanel::OnCellLeftClick( wxGridEvent& event )
2092 {
2093  int i = event.GetRow();
2094  int j = event.GetCol();
2095  if (i >=0 && j >=0 )
2096  {
2097  unordered_map<int, int>::iterator it = m_CollapseCell.find(i);
2098  if (j == m_CollapseGlyphCol && m_CollapseCol >= 0 && it != m_CollapseCell.end())
2099  {
2100  it->second = -it->second;
2102  return;
2103  }
2104  else
2105  {
2106  m_Grid->SetGridCursor( i,j );
2107  if (m_Grid->CanEnableCellControl())
2108  {
2109  m_edit_cell_row = i;
2110  m_edit_cell_col = j;
2111  m_Grid->EnableCellEditControl();
2112  wxGridCellEditor* editor = m_Grid->GetCellEditor(i,j);
2113  // https://wiki.wxwidgets.org/EventTypes_and_Event-Table_Macros
2114  editor->GetControl()->Connect(wxID_ANY, wxEVT_LEFT_DCLICK, wxMouseEventHandler(CSeqTableGridPanel::OnCellDoubleLeftClick2), NULL, this);
2115  editor->DecRef();
2116  m_Modified = true;
2117  }
2118  }
2119  }
2121 // event.Skip();
2122 }
2123 
2125 {
2126  int i = event.GetRow();
2127  int j = event.GetCol();
2128  if (i >=0 && j >=0 )
2129  {
2130  unordered_map<int, int>::iterator it = m_CollapseCell.find(i);
2131  if (j == m_CollapseGlyphCol && m_CollapseCol >= 0 && it != m_CollapseCell.end())
2132  {
2133  return;
2134  }
2135  else
2136  {
2137  m_Grid->SetGridCursor( i,j );
2138  if (m_Grid->CanEnableCellControl())
2139  {
2140  wxString old_value = m_Grid->GetCellValue(i,j);
2141  CSimpleTextEditor dlg(this, old_value);
2142  if (dlg.ShowModal() == wxID_OK)
2143  {
2144  wxString new_value = dlg.GetValue();
2145  if (new_value != old_value)
2146  {
2147  string val = new_value.ToStdString();
2148  NStr::ReplaceInPlace(val, "\r", "");
2149  NStr::ReplaceInPlace(val, "\n", " ");
2151  m_Grid->SetCellValue(i,j, wxString(val));
2152  m_Modified = true;
2153  }
2154  }
2155  }
2156  }
2157  }
2158 }
2159 
2161 {
2162  if (m_edit_cell_row < 0 || m_edit_cell_col < 0)
2163  return;
2164  wxObject *obj = event.GetEventObject();
2165  wxTextCtrl *ctrl = dynamic_cast<wxTextCtrl*>(obj);
2166  if (!ctrl)
2167  return;
2168  wxString old_value = ctrl->GetValue();
2169  CSimpleTextEditor dlg(this, old_value);
2170  if (dlg.ShowModal() == wxID_OK)
2171  {
2172  wxString new_value = dlg.GetValue();
2173  if (new_value != old_value)
2174  {
2175  string val = new_value.ToStdString();
2176  NStr::ReplaceInPlace(val, "\r", "");
2177  NStr::ReplaceInPlace(val, "\n", " ");
2179  m_Grid->SetCellValue(m_edit_cell_row, m_edit_cell_col, wxString(val));
2180  m_Modified = true;
2181  }
2182  }
2183 }
2184 
2185 
2186 /*!
2187  * wxEVT_GRID_LABEL_RIGHT_CLICK event handler for ID_GRID
2188  */
2189 
2190 void CSeqTableGridPanel::OnLabelRightClick( wxGridEvent& event )
2191 {
2192  x_CreateMenu(event);
2193 }
2194 
2196 {
2197  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
2198  if( !gridAdapter ) {
2199  return;
2200  }
2201  CRef<objects::CSeq_table> values_table = gridAdapter->GetValuesTable();
2202  CRef<objects::CSeq_table> old_table(new CSeq_table);
2203  old_table->Assign(*values_table);
2204 
2205 
2206  int num_rows = gridAdapter->GetNumberRows();
2207  int num_cols = static_cast<int>(values_table->GetColumns().size());
2208  vector<vector<bool> > selection(num_rows, vector<bool>(num_cols,false));
2209  for (int i=0; i<num_rows; i++)
2210  for (int j=0; j<num_cols; j++)
2211  if (m_Grid->IsInSelection(i,j))
2212  selection[i][j] = true;
2213 
2214 
2215  vector < pair< pair<string,int>,int> > sorted;
2216  for (int i=0; i<num_rows; i++)
2217  {
2218  string s = ToStdString(gridAdapter->GetRowLabelValue(i));
2219  pair<string,int> p("",m_MapRowLabelToIndex[s]);
2220  sorted.push_back(pair< pair<string,int>,int>(p,i));
2221  }
2222  std::sort(sorted.begin(),sorted.end(),cmpTableValues);
2223 
2225  std::reverse(sorted.begin(),sorted.end());
2226  m_Grid->ClearSelection();
2227 
2228  for (int j=0; j<num_cols; j++)
2229  {
2230  switch (values_table->GetColumns()[j]->GetData().Which())
2231  {
2233  values_table->SetColumns()[j]->SetData().SetId().resize(num_rows);
2234  break;
2236  values_table->SetColumns()[j]->SetData().SetString().resize(num_rows);
2237  break;
2238  default:
2239  break;
2240  }
2241  }
2242 
2243  for (int i=0; i<num_rows; i++)
2244  {
2245  int old_i = sorted[i].second;
2246  for (int j=0; j<num_cols; j++)
2247  {
2248  switch (values_table->GetColumns()[j]->GetData().Which())
2249  {
2251  if (old_i < old_table->SetColumns()[j]->GetData().GetId().size())
2252  values_table->SetColumns()[j]->SetData().SetId()[i] = old_table->SetColumns()[j]->GetData().GetId()[old_i];
2253  break;
2255  if (old_i < old_table->SetColumns()[j]->GetData().GetString().size())
2256  values_table->SetColumns()[j]->SetData().SetString()[i] = old_table->SetColumns()[j]->GetData().GetString()[old_i];
2257  else
2258  values_table->SetColumns()[j]->SetData().SetString()[i].clear();
2259  break;
2260  default:
2261  break;
2262  }
2263  if (selection[old_i][j])
2264  m_Grid->SelectBlock(i,j,i,j,true);
2265  }
2266  }
2268  m_Grid->Refresh();
2269 }
2270 
2271 void CSeqTableGridPanel::OnLabelLeftClick( wxGridEvent& event )
2272 {
2273  int row = event.GetRow();
2274  int col = event.GetCol();
2275  if ( col == m_CollapseGlyphCol && m_CollapseGlyphCol >= 0)
2276  return;
2277 
2278  if (col == -1 && row == -1 && m_SortByRowLabel)
2279  {
2280  x_ExpandTable();
2281  x_SortByRowLabel();
2282  }
2283  else if (col == -1 && row == -1)
2284  m_SortByRowLabel = true;
2285  if (col == -1 || row == -1)
2286  m_Grid->DisableCellEditControl();
2287  else
2288  m_Grid->EnableCellEditControl();
2289 
2290  if ( col == -1 && row >= 0)
2291  {
2292  x_SelectHiddenRows(row);
2293  return;
2294  }
2296  event.Skip();
2297 }
2298 
2300 {
2301  int index = -1;
2302  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
2303  if (gridAdapter)
2304  {
2305  string s = ToStdString(gridAdapter->GetRowLabelValue(row));
2306  index = m_MapRowLabelToIndex[s];
2307  }
2308  return index;
2309 }
2310 
2311 void CSeqTableGridPanel::OnLabelLeftDClick( wxGridEvent& event )
2312 {
2313  if (event.GetCol() == m_CollapseGlyphCol && m_CollapseGlyphCol >= 0)
2314  return;
2315 
2316  if (event.GetCol() == -1 && event.GetRow() == -1)
2317  {
2318  x_ExpandTable();
2319  m_SortByRowLabel = true;
2320  x_SortByRowLabel();
2321  }
2322  if (event.GetCol() == -1 && event.GetRow() != -1)
2323  {
2324  int row = event.GetRow();
2325  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
2326  if (gridAdapter)
2327  {
2328  string s = ToStdString(gridAdapter->GetRowLabelValue(row));
2329  int index = m_MapRowLabelToIndex[s];
2331  if (dlg)
2332  dlg->JumpToTextView(index);
2333  }
2334  }
2335  if (event.GetCol() == -1 || event.GetRow() == -1)
2336  m_Grid->DisableCellEditControl();
2337  else
2338  m_Grid->EnableCellEditControl();
2340  event.Skip();
2341 }
2342 
2344 {
2345  wxWindow* w = this->GetParent();
2346  while (w != NULL) {
2347  CSeqGridTableNav* parent = dynamic_cast<CSeqGridTableNav*>(w);
2348  if (parent) {
2349  return parent;
2350  } else {
2351  w = w->GetParent();
2352  }
2353  }
2354  return NULL;
2355 }
2356 
2357 
2358 void CSeqTableGridPanel::OnSearchTable( wxCommandEvent& event )
2359 {
2360  CSeqTableGrid *gridAdapter = dynamic_cast<CSeqTableGrid*>(m_Grid->GetTable());
2361  if( !gridAdapter ) return;
2362 
2363  int num_rows = gridAdapter->GetNumberRows();
2364 
2365  wxTextEntryDialog dlg(this,wxT("Enter the sequences you would like to select separated by space"), wxT("Enter Sequence IDs"), m_FindStr, wxOK|wxCANCEL);
2366  if (dlg.ShowModal() == wxID_OK)
2367  {
2368  m_FindStr = dlg.GetValue();
2369  if (m_FindStr.empty()) return;
2370  wxStringTokenizer tkz(m_FindStr);
2371  m_Grid->ClearSelection();
2372  while ( tkz.HasMoreTokens() )
2373  {
2374  wxString token = tkz.GetNextToken();
2375  if (!token.empty())
2376  for (int i=0; i<num_rows; i++)
2377  if (token == gridAdapter->GetRowLabelValue(i))
2378  m_Grid->SelectRow(i,true);
2379  }
2380  }
2381  m_MenuCol = -1;
2382 }
2383 
2384 
2385 
2386 void CSeqTableGridPanel::CopyPasteDataByKeyboard(wxKeyEvent& event) // See http://forums.wxwidgets.org/viewtopic.php?f=20&t=2200
2387 {
2388  if ((event.GetKeyCode() == 'C') && (event.ControlDown() == true))
2389  {
2390  x_OnCopyCells();
2391  }
2392  else if ((event.GetKeyCode() == 'V') && (event.ControlDown() == true))
2393  {
2394  x_OnPasteCells();
2395  }
2396  event.Skip();
2397 }
2398 
2400 {
2401  const wxArrayInt& rows = m_Grid->GetSelectedRows();
2402  size_t num_rows = rows.size();
2403  if (num_rows == 0)
2404  {
2405  const wxGridCellCoordsArray& selected_blocks_left = m_Grid->GetSelectionBlockTopLeft();
2406  const wxGridCellCoordsArray& selected_blocks_right = m_Grid->GetSelectionBlockBottomRight();
2407  if (selected_blocks_left.size() == selected_blocks_right.size())
2408  for (size_t i = 0; i < selected_blocks_left.size(); i++)
2409  {
2410  int top_row = selected_blocks_left[i].GetRow();
2411  int left_col = selected_blocks_left[i].GetCol();
2412  int bot_row = selected_blocks_right[i].GetRow();
2413  int right_col = selected_blocks_right[i].GetCol();
2414  int num_cols = right_col - left_col + 1;
2415  if (num_cols == m_Grid->GetNumberCols())
2416  num_rows += bot_row - top_row + 1;
2417  }
2418  }
2419  CStringConstraintSelect* select_win = NULL;
2420  wxWindow *w = this->GetParent();
2421  while (w != NULL)
2422  {
2423  wxWindowList& wlist = w->GetChildren();
2424  for ( wxWindowList::Node *node = wlist.GetFirst(); node; node = node->GetNext() )
2425  {
2426  wxWindow *current = (wxWindow *)node->GetData();
2427  select_win = dynamic_cast<CStringConstraintSelect*>(current);
2428  if (select_win)
2429  break;
2430  }
2431  if (select_win)
2432  break;
2433  w = w->GetParent();
2434  }
2435  if (select_win)
2436  select_win->UpdateCountSelectedDisplay(static_cast<int>(num_rows));
2437 }
2438 
2440 {
2441  if (!m_Grid->IsRowShown(row))
2442  return;
2443  auto num_rows = m_Grid->GetNumberRows();
2444  vector<bool> selected(num_rows, false);
2445  for (auto i = 0; i < num_rows; i++)
2446  if (m_Grid->IsInSelection(i, m_CollapseGlyphCol))
2447  selected[i] = true;
2448 
2449  m_Grid->ClearSelection();
2450 
2451  bool selected_before = selected[row];
2452  selected[row] = !selected_before;
2453 
2454  auto i = row + 1;
2455  while (i < num_rows && !m_Grid->IsRowShown(i))
2456  {
2457  selected[i] = !selected_before;
2458  i++;
2459  }
2460 
2461  for (auto i = 0; i < num_rows; i++)
2462  if (selected[i])
2463  m_Grid->SelectRow(i, true);
2464 
2466 }
2467 
2469 
2470 
#define ID_GRID
struct zzzz Cell
vector< int > m_diffs
int UpdateRowOrColSize(int &sizeCurrent, int sizeNew)
void FastSetRowSize(int row, int height)
wxString BreakLines(const wxString &text)
virtual wxSize GetBestSize(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc, int row, int col) wxOVERRIDE
virtual void Draw(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc, const wxRect &rect, int row, int col, bool isSelected) wxOVERRIDE
void SetTextColoursAndFont(const wxGrid &grid, const wxGridCellAttr &attr, wxDC &dc, bool isSelected)
virtual void SetAttr(wxGridCellAttr *attr, int row, int col) wxOVERRIDE
virtual wxGridCellAttr * GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind=wxGridCellAttr::Any) const wxOVERRIDE
unordered_map< pair< int, int >, wxGridCellAttr *, pair_hash > m_cache
void MakeColumnReadOnly(int pos, bool val=true)
CSeqTableGridPanel()
Constructors.
void OnCellRightClick(wxGridEvent &event)
wxEVT_GRID_CELL_RIGHT_CLICK event handler for ID_GRID
void x_CollapseTableByColumn(bool initialize=false)
void CollapseByCol(int col)
int GetCollapseColAndExpand(void)
void UpdateColumnChoices(int pos, vector< string > choices)
void x_SelectHiddenRows(int row)
void CreateControls()
Creates the controls and sizers.
static bool ShowToolTips()
Should we show tooltips?
void x_UpdateCountSelectedDisplay(void)
CRef< objects::CSeq_table > m_Table
map< pair< int, int >, wxString > m_CollapseCache
void OnCellDoubleLeftClick2(wxMouseEvent &event)
~CSeqTableGridPanel()
Destructor.
void OnCopyCellsFromId(wxCommandEvent &event)
void OnCellDoubleLeftClick(wxGridEvent &event)
void x_SortTableByColumn(int col, bool ascend)
unordered_map< string, int > m_MapRowLabelToIndex
set< int > m_SetOfReadOnlyCols
unordered_map< int, int > m_CollapseCell
void OnCopyCells(wxCommandEvent &event)
void OnLabelRightClick(wxGridEvent &event)
wxEVT_GRID_LABEL_RIGHT_CLICK event handler for ID_GRID
void x_CreateMenu(wxGridEvent &evt)
void OnRenameColumn(wxCommandEvent &event)
void InitColumnCollapse(int col)
void OnExpandColumn(wxCommandEvent &event)
void x_MakeProblemsColumnReadOnly()
void OnPasteAppendCells(wxCommandEvent &event)
void OnLabelLeftClick(wxGridEvent &event)
void OnDeleteColumn(wxCommandEvent &event)
CSeqGridTableNav * x_GetSeqGridTableNav()
void x_UpdateCollapsedRow(unsigned int num_cols, int expand_row, vector< bool > &all_present, vector< bool > &all_same, vector< wxString > &values)
bool x_ValuesOkForNewColumn(CConstRef< objects::CSeqTable_column > values, int col_pos)
void OnSearchTable(wxCommandEvent &event)
SrcEditDialog * x_GetParent()
CRef< objects::CSeq_table > m_Choices
wxBitmap GetBitmapResource(const wxString &name)
Retrieves bitmap resources.
int GetRowIndex(int row)
void SetValuesTable(CRef< objects::CSeq_table > table)
void x_PasteCells(CRef< objects::CSeq_table > copied, bool append=false, string delim=";")
void OnCollapseColumn(wxCommandEvent &event)
CCollapsibleGrid * m_Grid
void CopyPasteDataByKeyboard(wxKeyEvent &event)
bool Create(wxWindow *parent, wxWindowID id=10078, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(400, 300), long style=wxTAB_TRAVERSAL)
Creation.
void x_ExpandTableByColumn(void)
void OnSortTableByColumn(wxGridEvent &event)
CRef< objects::CSeq_table > m_Copied
CRef< objects::CSeq_table > GetValuesTable()
wxIcon GetIconResource(const wxString &name)
Retrieves icon resources.
void OnLabelLeftDClick(wxGridEvent &event)
void OnCellLeftClick(wxGridEvent &event)
void Init()
Initialises member variables.
void OnPasteCells(wxCommandEvent &event)
virtual bool IsEmptyCell(int row, int col)
virtual void SetColLabelValue(int col, const wxString &label)
virtual wxString GetValue(int row, int col)
virtual int GetNumberRows()
virtual bool DeleteCols(size_t pos=0, size_t numCols=1)
CSeqTableGrid(CRef< objects::CSeq_table > values_table)
virtual void SetValue(int vis_row, int vis_col, const wxString &value)
virtual wxString GetColLabelValue(int col)
virtual wxString GetRowLabelValue(int row)
CRef< objects::CSeq_table > GetValuesTable(void)
CRef< objects::CSeq_table > m_ValuesTable
virtual int GetNumberCols()
virtual bool InsertCols(size_t pos=0, size_t numCols=1)
virtual bool AppendCols(size_t numCols=1)
CUICommandRegistry is a centralized registry where all application commands should be registered.
Definition: ui_command.hpp:146
static CUICommandRegistry & GetInstance()
the main instance associated with the application
Definition: ui_command.cpp:176
wxMenu * CreateMenu(const SwxMenuItemRec *items)
create a menu from a static definition (see WX_*_MENU macros)
Definition: ui_command.cpp:349
int RegisterCommand(CUICommand *cmd)
assumes ownership of the given object returns a command id (useful when registry is used for auto id ...
Definition: ui_command.cpp:198
void GetQualChoices(wxArrayString &srcModNameStrings)
void ChangeColumnName(int col, string qual_name)
void x_RepopulateAddQualList()
void clear()
Definition: map.hpp:169
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
const_iterator find(const key_type &key) const
Definition: set.hpp:137
void erase(iterator pos)
Definition: set.hpp:151
const_iterator end() const
Definition: set.hpp:136
char value[7]
Definition: config.c:431
#define option
#define _(proto)
Definition: ct_nlmzip_i.h:78
static void Init(void)
Definition: cursor6.c:76
static void DLIST_NAME() append(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:78
std::ofstream out("events_result.xml")
main entry point for tests
const string kProblems
const char * kSequenceIdColLabel
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NULL
Definition: ncbistd.hpp:225
@ eContent
Definition: feature.hpp:87
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,...
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
static int StringToInt(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to int.
Definition: ncbistr.cpp:630
static bool IsBlank(const CTempString str, SIZE_TYPE pos=0)
Check if a string is blank (has no text).
Definition: ncbistr.cpp:106
static TNumeric StringToNumeric(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to a numeric value.
Definition: ncbistr.hpp:330
static void TruncateSpacesInPlace(string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string (in-place)
Definition: ncbistr.cpp:3197
static SIZE_TYPE Find(const CTempString str, const CTempString pattern, ECase use_case=eCase, EDirection direction=eForwardSearch, SIZE_TYPE occurrence=0)
Find the pattern in the string.
Definition: ncbistr.cpp:2887
#define NcbiEmptyString
Definition: ncbistr.hpp:122
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5352
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
static bool Equal(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2, ECase use_case=eCase)
Test for equality of a substring with another string.
Definition: ncbistr.hpp:5383
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3401
@ fAllowTrailingSpaces
Ignore trailing space characters.
Definition: ncbistr.hpp:297
@ fConvErr_NoThrow
Do not throw an exception on error.
Definition: ncbistr.hpp:285
@ fAllowLeadingSpaces
Ignore leading spaces in converted string.
Definition: ncbistr.hpp:294
static const char label[]
bool IsString(void) const
Check if variant String is selected.
bool IsSetData(void) const
row data Check if a value has been assigned to Data data member.
const TString & GetString(void) const
Get the variant data.
const TData & GetData(void) const
Get the Data member data.
@ e_String
a set of strings, one per row
<!DOCTYPE HTML >< html > n< header > n< title > PubSeq Gateway Help Page</title > n< style > n table
END_EVENT_TABLE()
int i
int len
static void text(MDB_val *v)
Definition: mdb_dump.c:62
#define wxT(x)
Definition: muParser.cpp:41
constexpr auto sort(_Init &&init)
constexpr bool empty(list< Ts... >) noexcept
const struct ncbi::grid::netcache::search::fields::SIZE size
unsigned int a
Definition: ncbi_localip.c:102
T min(T x_, T y_)
double r(size_t dimension_, const Int4 *score_, const double *prob_, double theta_)
USING_SCOPE(objects)
bool cmpTableValues(const pair< pair< string, int >, int > &a, const pair< pair< string, int >, int > &b)
static void s_CopyRow(CConstRef< objects::CSeq_table > src, CRef< objects::CSeq_table > dst, int left, int right, int src_row, int dst_row, bool append, string delim)
static void s_CopyToIntColumn(CConstRef< objects::CSeqTable_column > src, CRef< objects::CSeqTable_column > dst, int top, int bot)
static void s_CopyColumn(CConstRef< objects::CSeqTable_column > src, CRef< objects::CSeqTable_column > dst, int top, int bot, bool append, string delim)
static void s_CopyToStringColumn(CConstRef< objects::CSeqTable_column > src, CRef< objects::CSeqTable_column > dst, int top, int bot, bool append, string delim)
@ eCmdCollapseTableCol
@ eCmdRenameTableCol
@ eCmdPasteTableValues
@ eCmdAppendTableValues
@ eCmdSearchTable
@ eCmdExpandTableCol
@ eCmdCopyTableValues
@ eCmdDeleteTableCol
@ eCmdCopyTableValuesFromId
static static static wxID_ANY
CRef< CSeqTable_column > FindSeqTableColumnByName(CRef< objects::CSeq_table > values_table, string column_name)
ViewerWindowBase::OnEditMenu ViewerWindowBase::OnJustification EVT_MENU(MID_SHOW_GEOM_VLTNS, ViewerWindowBase::OnShowGeomVltns) EVT_MENU(MID_FIND_PATTERN
static const char * str(char *buf, int n)
Definition: stats.c:84
static const char * column
Definition: stats.c:23
bool IsSynonymForFalse(const string &val)
bool IsSynonymForTrue(const string &val)
#define WX_DEFINE_MENU(name)
New macros for defining menus for use with CUICommandRegistry.
Definition: ui_command.hpp:266
#define WX_END_MENU()
Definition: ui_command.hpp:294
#define WX_MENU_ITEM(cmd)
Definition: ui_command.hpp:270
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
string ToStdString(const wxString &s)
Definition: wx_utils.hpp:161
Modified on Fri Dec 01 04:46:18 2023 by modify_doxy.py rev. 669887