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

Go to the SVN repository for this file.

1 /* $Id: grid_widget.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: Roman Katargin
27  *
28  * File Description:
29  *
30  */
31 
32 #include <ncbi_pch.hpp>
33 
35 
36 #include <gui/utils/view_event.hpp>
39 
43 
47 
54 
55 #include <wx/sizer.h>
56 #include <wx/menu.h>
57 #include <wx/button.h>
58 #include <wx/msgdlg.h>
59 #include <wx/settings.h>
60 
61 #include <wx/sstream.h>
62 #include <wx/txtstrm.h>
63 #include <wx/clipbrd.h>
64 #include <wx/dataobj.h>
65 
66 #include <functional>
67 #include <sstream>
68 
70 
71 #define ID_EXPORT_TO_CSV 10100
72 #define ID_SEARCH_INCLUDE_VALUE 10101
73 #define ID_SEARCH_EXCLUDE_VALUE 10102
74 
75 BEGIN_EVENT_TABLE( CGridWidget, wxPanel )
76 EVT_GRID_CELL_RIGHT_CLICK(CGridWidget::OnGridCellRightClick)
77 EVT_GRID_CELL_LEFT_DCLICK(CGridWidget::OnGridCellLeftDClick)
78 EVT_GRID_LABEL_LEFT_DCLICK(CGridWidget::OnGridLabelLeftDClick)
79 EVT_GRID_SELECT_CELL(CGridWidget::OnGridSelectCell)
80 EVT_GRID_RANGE_SELECT(CGridWidget::OnGridRangeSelect)
81 EVT_TIMER(-1, CGridWidget::OnTimer)
86 EVT_MENU(wxID_COPY, CGridWidget::OnCopy)
88 EVT_BUTTON( ID_REFRESH_BUTTON, CGridWidget::OnRefreshClick )
90 
92 : m_Grid(NULL)
93 , m_GridAdapter(NULL)
94 , m_Timer(this)
95 , m_ToolbarSizer(NULL)
96 , m_QueryPanel(NULL)
97 , m_StaticLine(NULL)
98 , m_RefreshButton(NULL)
99 , m_SelectAll(true)
100 , m_ShowSelectAll(true)
101 , m_PopupGridX(-1)
102 , m_PopupGridY(-1)
103 , m_isShowRefreshButton(false)
104 , m_isShowGridLines(true)
105 , m_UseCursorSelection(true)
106 {
107 }
108 
109 CGridWidget::CGridWidget(wxWindow* parent, wxWindowID id,
110  const wxPoint& pos, const wxSize& size, long style)
111  : m_Grid(), m_GridAdapter(), m_Timer(this), m_ToolbarSizer(NULL)
112  , m_QueryPanel(NULL)
113  , m_StaticLine(NULL)
114  , m_RefreshButton(NULL)
115  , m_SelectAll(true)
116  , m_ShowSelectAll(true)
117  , m_isShowRefreshButton(false)
118  , m_isShowGridLines(true)
119  , m_UseCursorSelection(true)
120 {
121  Create(parent, id, pos, size, style);
122 }
123 
125 {
126  if (m_QueryPanel)
128 
129  if (m_GridEvtExt) {
130  PopEventHandler();
131  }
132 }
133 
134 bool CGridWidget::Create(wxWindow* parent, wxWindowID id,
135  const wxPoint& pos, const wxSize& size, long style)
136 {
137 #ifdef __WXOSX_COCOA__ // GB-8581
138  SetBackgroundStyle(wxBG_STYLE_COLOUR);
139  SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
140 #endif
141 
142  if ( ! wxPanel::Create(parent, id, pos, size, style))
143  return false;
144 
145  CreateControls();
146 
147  return true;
148 }
149 
151 {
152  if (m_GridEvtExt) {
153  PopEventHandler();
154  }
155 
156  m_GridEvtExt.Reset(evtExt);
157 
158  if(m_GridEvtExt) {
159  m_GridEvtExt->x_SetGridWidget(this);
160  PushEventHandler(m_GridEvtExt);
161  }
162 }
163 
165 {
166  wxBoxSizer* itemBoxSizer = new wxBoxSizer(wxVERTICAL);
167  this->SetSizer(itemBoxSizer);
168 
169  m_Grid = new CGrid(this, wxID_ANY);
170  itemBoxSizer->Add(m_Grid, 1, wxGROW|wxALL, 0);
171 
172  // x_InitGrid(NULL);
173 }
174 
175 void CGridWidget::Init(ITableData& table_data, ICommandProccessor* cmdProccessor)
176 {
177  m_TableData.Reset(&table_data);
178  x_InitGrid(cmdProccessor);
179 }
180 
182 {
183  wxFont font = m_Grid->GetDefaultCellFont();
184  wxFont fixed_font(font.GetPointSize(), wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
185  fixed_font.SetSymbolicSize(wxFONTSIZE_LARGE);
186  m_Grid->SetDefaultCellFont(fixed_font);
187 }
188 
189 static const char* kQuery = ".Query";
190 
192  if (!m_Grid)
193  return;
194 
195  if (m_TableData) {
196  m_GridAdapter = new CwxGridTableAdapter(*m_TableData, cmdProccessor);
197  if (!m_RegPath.empty()) {
200  }
201 
202  m_ToolbarSizer = new wxBoxSizer(wxHORIZONTAL);
203 
204  if (m_QueryPanel)
205  m_QueryPanel->Destroy();
208  m_QueryPanel->Create(this);
210 
211  string section = m_TableData->GetTableTypeId();
213  CRegistryReadView view = gui_reg.GetReadView("TableDataQuery." + section);
214  vector<string> vec;
215  view.GetStringVec("Defaults", vec);
217  for (size_t i = 0; i < vec.size()/2; ++i) {
218  defaults.push_back
219  (CQueryParsePanel::TNamedQueries::value_type(vec[2*i], vec[2*i + 1]));
220  }
221  m_QueryPanel->SetDefaultQueries(defaults);
222 
223  if (!m_RegPath.empty()) {
226  }
227 
228  m_ToolbarSizer->Add(m_QueryPanel, wxGROW|wxBOTTOM|wxALIGN_LEFT);
229 
230  // adding it should be configurable by the widget user
231  if(m_RefreshButton) {
232  m_RefreshButton->Destroy();
233  }
235  m_RefreshButton = new wxButton( this, ID_REFRESH_BUTTON, _("Refresh"), wxDefaultPosition, wxDefaultSize, 0 );
236  m_ToolbarSizer->Add(m_RefreshButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
237  }
238  if (!m_ShowSelectAll) {
240  m_SelectAll = false;
241  }
242 
243  GetSizer()->Insert(0, m_ToolbarSizer, 0, wxGROW|wxBOTTOM|wxALIGN_LEFT);
244  if(m_StaticLine) {
245  m_StaticLine->Destroy();
246  }
247  m_StaticLine = new wxStaticLine( this, wxID_STATIC, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
248  GetSizer()->Insert(1, m_StaticLine, 0, wxGROW, 1);
249  m_Grid->SetTable(m_GridAdapter, true);
250 
251  LoadSettings();
252  GetSizer()->Layout();
253 
254  m_Grid->EnableEditing(true);
255 
256  m_Grid->EnableGridLines(m_isShowGridLines);
257  }
258 }
259 
260 void CGridWidget::OnHyperlinkHover(wxHyperlinkEvent& event)
261 {
262  CGridWidgetEvent evt(CGridWidgetEvent::eUrlHover, event.GetURL());
263  Send(&evt, ePool_Parent);
264 }
265 
266 void CGridWidget::OnGridCellRightClick(wxGridEvent& evt)
267 {
268  if (!m_TableData || evt.GetCol() < 0)
269  return;
270 
271 
272  wxMenu menu;
273 
274  if (m_GridAdapter) {
275  unique_ptr<wxMenu> edit_menu(m_GridAdapter->CreateMenu());
276  if (edit_menu.get()) {
277  Merge(menu, *edit_menu);
278  }
279  }
280 
281  TConstScopedObjects sel_objects;
282  GetSelectedObjects(sel_objects);
283  if (!sel_objects.empty()) {
284  vector< CIRef<IObjectCmdContributor> > contributors;
286 
287  for( size_t i = 0; i < contributors.size(); i++ ){
288  IObjectCmdContributor& obj = *contributors[i];
289 
290  IObjectCmdContributor::TContribution contrib = obj.GetMenu(sel_objects);
291  unique_ptr<wxMenu> obj_menu(contrib.first);
292  if (obj_menu.get()) {
293  Merge(menu, *obj_menu);
294  }
295  }
296  }
297 
298  if (menu.GetMenuItemCount() > 0) {
299  menu.AppendSeparator();
300  }
301  menu.Append(wxID_COPY);
302  menu.Append(ID_EXPORT_TO_CSV, "Export to CSV...");
303  menu.Append(ID_SEARCH_INCLUDE_VALUE, "Filter Include this Value");
304  menu.Append(ID_SEARCH_EXCLUDE_VALUE, "Filter Exclude this Value");
305 
306 
307  m_PopupGridX = evt.GetCol();
308  m_PopupGridY = evt.GetRow();
309 
310  CleanupSeparators(menu);
311 
312  m_Grid->PopupMenu(&menu, evt.GetPosition());
313 }
314 
315 void CGridWidget::OnGridCellLeftDClick(wxGridEvent& evt)
316 {
317  x_LeftDClick(evt.GetRow());
318 }
319 
321 {
322  if (evt.GetRow() < 0)
323  return;
324 
325  x_LeftDClick(evt.GetRow());
326 }
327 
328 void CGridWidget::x_LeftClick(int row, int modifiers)
329 {
331  event.SetSelectedRow(static_cast<int>(m_GridAdapter->GetOriginalRow(row)));
332  event.SetModifiers(modifiers);
333  Send(&event, ePool_Parent);
334 }
335 
337 {
339  event.SetSelectedRow(static_cast<int>(m_GridAdapter->GetOriginalRow(row)));
340  Send(&event, ePool_Parent);
341 }
342 
343 static bool s_BlockSelChangeUpdate = false;
344 
345 void CGridWidget::OnGridSelectCell(wxGridEvent& evt)
346 {
348  return;
349 
350  x_LeftClick(evt.GetRow(), evt.GetModifiers());
351  m_Timer.Start(300, true);
352  evt.Skip();
353 }
354 
355 void CGridWidget::OnGridRangeSelect(wxGridRangeSelectEvent& evt)
356 {
358  return;
359 
360  if(evt.GetTopRow() == evt.GetBottomRow()) {
361  x_LeftClick(evt.GetTopRow(), evt.GetModifiers());
362  }
363  m_Timer.Start(300, true);
364  evt.Skip();
365 }
366 
367 void CGridWidget::OnTimer(wxTimerEvent&)
368 {
370  Send(&evt, ePool_Parent);
371 }
372 
374 {
375  m_Grid->Disable();
376 }
377 
379 {
380  x_CompleteQuery();
381  m_Grid->Enable();
382 }
383 
385 {
386  m_Grid->BeginBatch();
387 
388  m_Grid->ClearSelection();
389 
390  // If the view is currently only showing selected rows (selected from
391  // a previous query), undo that since we now (probably) have
392  // different rows selected.
393  bool hide_unselected = m_GridAdapter->GetHideUnselected();
394  if (hide_unselected) {
395  // Do this before updating the selection set sets it uses that
396  // for the number calculations.
398  }
399 
400  vector<size_t> query_results = m_QueryDS->GetQueryResults();
401  m_GridAdapter->SetSelection(query_results);
402 
403  if (m_QueryPanel->IsSelectAll()) {
404  // Sets currently selected row to first row in selection (in select-all
405  // mode we need a current selection in case we switch to single-select)
407 
408  // Updated the displayed rows in the grid widget. SetHideUnselected()
409  // does that for us, if we are in hide-unselected mode.
410  if (hide_unselected) {
411  SetHideUnselected(true);
412  }
413  else {
414  for (size_t i=0; i<query_results.size(); ++i) {
415  size_t row_idx = query_results[i];
416  size_t current_idx = m_GridAdapter->GetCurrentRow(row_idx);
417  if (i == 0) {
418  m_Grid->SetGridCursor(static_cast<int>(current_idx), 0);
419  }
420  if (current_idx < (size_t)m_Grid->GetNumberRows()) {
421  m_Grid->SelectRow(static_cast<int>(current_idx), true);
422  }
423  }
424  }
425  }
426  else {
427  // In single-select mode. Set current selection as the first
428 
429  if (hide_unselected) {
431  }
432 
433  // Set first selected element as current selection
434  IterateSelection(0);
435  }
436 
437  m_Grid->EndBatch();
438 }
439 
441 {
442  m_Grid->BeginBatch();
443 
444  m_SelectAll = b;
445 
446  m_Grid->ClearSelection();
447 
448  if (b) {
449  vector<size_t> query_results = m_QueryDS->GetQueryResults();
450 
451  for (size_t i=0; i<query_results.size(); ++i) {
452  size_t row_idx = query_results[i];
453  size_t current_idx = m_GridAdapter->GetCurrentRow(row_idx);
454  if (current_idx < (size_t)m_Grid->GetNumberRows()) {
455  m_Grid->SelectRow(static_cast<int>(current_idx), true);
456  }
457  }
458  }
459  else {
460  size_t row_idx = m_GridAdapter->GetCurrentSelection();
461  size_t current_idx = m_GridAdapter->GetCurrentRow(row_idx);
462  if (current_idx < (size_t)m_Grid->GetNumberRows()) {
463  m_Grid->SelectRow(static_cast<int>(current_idx), true);
464  x_ScrollToRow(static_cast<int>(current_idx));
465  }
466  }
467 
468  m_Grid->EndBatch();
469 }
470 
472 {
473  if (!m_QueryPanel->IsSelectAll()) {
474  m_Grid->ClearSelection();
475 
477 
478  size_t data_row_idx = m_GridAdapter->GetCurrentSelection();
479  size_t grid_row_idx = m_GridAdapter->GetCurrentRow(data_row_idx);
480  if (grid_row_idx < (size_t)m_Grid->GetNumberRows()) {
481  m_Grid->SelectRow(static_cast<int>(grid_row_idx), true);
482  x_ScrollToRow(static_cast<int>(grid_row_idx));
483  }
484  }
485 }
486 
488 {
490 
492 
493  m_Grid->Refresh();
494 }
495 
497 {
499 
500  vector<size_t> origRows;
501 
502  if (m_TableSelection) {
503  m_TableSelection->GetRows(*m_TableData, evt, origRows);
504  } else {
505  TConstObjects objs;
506  evt.GetAllObjects(objs);
507  evt.GetOther(objs);
508  set<const CObject*> objSet(objs.begin(), objs.end());
509 
510  for (int i = 0; i < m_GridAdapter->GetRowsCount(); ++i) {
511  size_t row = m_GridAdapter->GetOriginalRow(i);
512  SConstScopedObject obj = m_TableData->GetRowObject(row);
513  if (obj.object && objSet.find(obj.object) != objSet.end())
514  origRows.push_back(row);
515  }
516  }
517 
518  m_Grid->BeginBatch();
519 
520  m_Grid->ClearSelection();
521 
522  set<size_t> rowSet(origRows.begin(), origRows.end());
523  for (int i = 0; i < m_GridAdapter->GetRowsCount(); ++i) {
524  size_t row = m_GridAdapter->GetOriginalRow(i);
525  if (rowSet.find(row) != rowSet.end())
526  m_Grid->SelectRow(static_cast<int>(row), true);
527  }
528 
529  m_Grid->EndBatch();
530  return origRows.empty() ? 0 : origRows[0];
531 }
532 
534 {
535  set<int> raw_rows;
536 
537  if (!m_Grid)
538  return;
539 
540 // Block selection
541  wxGridCellCoordsArray selTopLeft = m_Grid->GetSelectionBlockTopLeft();
542  wxGridCellCoordsArray selBottomRight = m_Grid->GetSelectionBlockBottomRight();
543  size_t blockCount = selTopLeft.GetCount();
544 
545  if (blockCount > 0 && blockCount == selBottomRight.GetCount()) {
546  for (size_t i = 0; i < blockCount; ++i) {
547  for (int j = selTopLeft[i].GetRow(); j <= selBottomRight[i].GetRow(); ++j)
548  raw_rows.insert(j);
549  }
550  }
551 
552 // Row selection
553  wxArrayInt selRows = m_Grid->GetSelectedRows();
554  for (size_t i = 0; i < selRows.size(); ++i)
555  raw_rows.insert(selRows[i]);
556 
557 // Cell Selection
558  wxGridCellCoordsArray selCells = m_Grid->GetSelectedCells();
559  for (size_t i = 0; i < selCells.GetCount(); ++i)
560  raw_rows.insert(selCells[i].GetRow());
561 
562 
563  for (set<int>::const_iterator it = raw_rows.begin(); it != raw_rows.end(); ++it) {
564  size_t row = m_GridAdapter->GetOriginalRow((size_t)*it);
565  if (row != (size_t)-1)
566  rows.insert((int)row);
567  }
568 }
569 
571 {
572  if (m_TableSelection) {
573  set<int> selRows;
574  x_GetSelectedRows(selRows);
575  vector<size_t> origRows;
576 
577  for (set<int>::const_iterator it = selRows.begin(); it != selRows.end(); ++it) {
578  size_t row = m_GridAdapter->GetOriginalRow((size_t)*it);
579  if (row != (size_t)-1)
580  origRows.push_back(row);
581  }
582 
583  m_TableSelection->GetSelection(*m_TableData, origRows, evt);
584  } else {
585  TConstScopedObjects sobjs;
586  GetSelectedObjects (sobjs);
587 
588  TConstObjects objs;
589  ITERATE(TConstScopedObjects, it, sobjs) {
590  objs.push_back(it->object);
591  }
592 
593  evt.AddObjectSelection(objs);
594  }
595 }
596 
597 
599 {
600  set<int> selRows;
601  x_GetSelectedRows(selRows);
602 
603  vector<size_t> origRows;
604 
605  for (set<int>::const_iterator it = selRows.begin(); it != selRows.end(); ++it) {
606  size_t row = m_GridAdapter->GetOriginalRow((size_t)*it);
607  if (row != (size_t)-1)
608  origRows.push_back(row);
609  }
610 
611  for (size_t col = 0; col < m_TableData->GetColsCount(); ++col) {
612  if (m_TableData->GetColumnType(col) == ITableData::kObject) {
613  vector<size_t>::const_iterator it2;
614  for (it2 = origRows.begin(); it2 != origRows.end(); ++it2) {
615  SConstScopedObject so = m_TableData->GetObjectValue(*it2, col);
616  if (so.object)
617  objects.push_back(so);
618  }
619  }
620  }
621 
622  vector<size_t>::const_iterator it3;
623  for (it3 = origRows.begin(); it3 != origRows.end(); ++it3) {
624  SConstScopedObject so = m_TableData->GetRowObject(*it3);
625  if (so.object)
626  objects.push_back(so);
627  }
628 }
629 
631 {
632  // Return selected objecst for users performing an action such as a menu
633  // action for a single item in a priority order. This is a little arbitrary, but
634  // a reasonably intuitive selection hierarchy might be:
635  // 1. First fully selected row
636  // 2. Grid selection (from first row)
637  // 3. Grid cursor row - if nothing else is selected (note that the grid cursor
638  // may sometimes not be visible (think this is a wx bug) so we should only
639  // use it if nothing else is selected
640 
641  /// Row selection
642  vector<int> selRows;
643  wxArrayInt rows = m_Grid->GetSelectedRows();
644  for (size_t i = 0; i < rows.size(); ++i)
645  selRows.push_back(rows[i]);
646 
647  // Block selection
648  if (selRows.size() == 0) {
649  wxGridCellCoordsArray selTopLeft = m_Grid->GetSelectionBlockTopLeft();
650  wxGridCellCoordsArray selBottomRight = m_Grid->GetSelectionBlockBottomRight();
651  size_t blockCount = selTopLeft.GetCount();
652 
653  if (blockCount > 0 && blockCount == selBottomRight.GetCount()) {
654  for (size_t i = 0; i < blockCount; ++i) {
655  for (int j = selTopLeft[i].GetRow(); j <= selBottomRight[i].GetRow(); ++j)
656  selRows.push_back(j);
657  }
658  }
659  }
660 
661  // Cell Selection
662  if (selRows.size() == 0) {
663  wxGridCellCoordsArray selCells = m_Grid->GetSelectedCells();
664  for (size_t i = 0; i < selCells.GetCount(); ++i)
665  selRows.push_back(selCells[i].GetRow());
666  }
667 
668  // Grid cursor selection
669  if (selRows.size() == 0) {
670  int curRow = m_Grid->GetGridCursorRow();
671  if (curRow >= 0)
672  selRows.push_back(curRow);
673  }
674 
675  vector<size_t> origRows;
676 
677  for (vector<int>::const_iterator it = selRows.begin(); it != selRows.end(); ++it) {
678  size_t row = m_GridAdapter->GetOriginalRow((size_t)*it);
679  _TRACE("Sel row: " << *it << " orig row: " << row);
680  if (row != (size_t)-1)
681  origRows.push_back(row);
682  }
683 
684  for (size_t col = 0; col < m_TableData->GetColsCount(); ++col) {
685  if (m_TableData->GetColumnType(col) == ITableData::kObject) {
686  vector<size_t>::const_iterator it2;
687  for (it2 = origRows.begin(); it2 != origRows.end(); ++it2) {
688  SConstScopedObject so = m_TableData->GetObjectValue(*it2, col);
689  if (so.object)
690  objects.push_back(so);
691  }
692  }
693  }
694 
695  vector<size_t>::const_iterator it3;
696  for (it3 = origRows.begin(); it3 != origRows.end(); ++it3) {
697  SConstScopedObject so = m_TableData->GetRowObject(*it3);
698  if (so.object)
699  objects.push_back(so);
700  }
701 }
702 
703 void CGridWidget::x_ScrollToRow(int row_idx)
704 {
705  bool visible = m_Grid->IsVisible(row_idx, 0, false);
706  if (!visible) {
707  // Need to scroll to new row via MakeCellVisible, and then
708  // to the correct horizontal position via Scroll(x,y) which
709  // keeps the updated row (y) position and scrolls to the
710  // previous x (horizonal) position. This does cause some
711  // flicker since both commands seem to update the window
712  // immediately (at least on windows) despite using
713  // wxGrids beginbatch/endbatch.
714  m_Grid->BeginBatch();
715  int x, xdummy, y;
716  m_Grid->GetViewStart(&x, &y);
717  m_Grid->MakeCellVisible(row_idx, 0);
718  m_Grid->GetViewStart(&xdummy,&y);
719  m_Grid->Scroll(x, y);
720  m_Grid->EndBatch();
721  }
722 }
723 
725 {
726  if (!m_Grid)
727  return;
728 
729 // Block selection
730  wxGridCellCoordsArray selTopLeft = m_Grid->GetSelectionBlockTopLeft();
731  wxGridCellCoordsArray selBottomRight = m_Grid->GetSelectionBlockBottomRight();
732  size_t blockCount = selTopLeft.GetCount();
733 
734  if (blockCount > 0 && blockCount == selBottomRight.GetCount()) {
735  for (size_t i = 0; i < blockCount; ++i) {
736  for (int j = selTopLeft[i].GetRow(); j <= selBottomRight[i].GetRow(); ++j)
737  rows.insert(j);
738  }
739  }
740 
741 // Row selection
742  wxArrayInt selRows = m_Grid->GetSelectedRows();
743  for (size_t i = 0; i < selRows.size(); ++i)
744  rows.insert(selRows[i]);
745 
746 // Cell Selection
747  wxGridCellCoordsArray selCells = m_Grid->GetSelectedCells();
748  for (size_t i = 0; i < selCells.GetCount(); ++i)
749  rows.insert(selCells[i].GetRow());
750 
751  if (m_UseCursorSelection && rows.empty()) {
752  int curRow = m_Grid->GetGridCursorRow();
753  if (curRow >= 0)
754  rows.insert(curRow);
755  }
756 }
757 
759 {
760  int count1 = m_GridAdapter->GetNumberRows();
762  int count2 = m_GridAdapter->GetNumberRows();
763 
764  // Send message to grid to make it update the number of displayed rows. It does not
765  // do this automatically just because the datasource changes the number of rows
766  // it is reporting.
767  if (count1 > count2) {
768  wxGridTableMessage msg( m_GridAdapter, wxGRIDTABLE_NOTIFY_ROWS_DELETED, count2, count1-count2);
769  m_Grid->ProcessTableMessage(msg);
770  }
771  else if (count1 < count2) {
772  wxGridTableMessage msg( m_GridAdapter, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, count2-count1);
773  m_Grid->ProcessTableMessage(msg);
774  }
775 }
776 
777 void CGridWidget::SetRegistryPath(const string& reg_path)
778 {
779  m_RegPath = reg_path;
780 
781  if (m_GridAdapter) {
784  }
785 
786  if (m_QueryPanel) {
789  }
790 }
791 
793 {
794 }
795 
797 {
798  if (m_GridAdapter) {
800  }
801 
802  if (m_QueryPanel) {
804  }
805 
806 }
807 
808 void CGridWidget::OnExportToCSV(wxCommandEvent& WXUNUSED(event))
809 {
810  if (!m_GridAdapter)
811  return;
812 
813  CwxCSVExportDlg dlg(this);
814 
815  vector<wxString> selectedColumns;
816  const int colNum = m_GridAdapter->GetNumberCols();
817  for (int i = 0; i < colNum; ++i) {
818  selectedColumns.push_back(m_GridAdapter->GetColLabelValue(i));
819  }
820  dlg.SetColumnsList(selectedColumns);
821  dlg.Layout();
822  dlg.Fit();
823  dlg.Refresh();
824 
825  string regPath = m_GridAdapter->GetRegPath();
826  if (!regPath.empty())
827  dlg.SetRegistryPath(regPath + ".ExportToCSV");
828 
829  if (dlg.ShowModal() != wxID_OK)
830  return;
831 
832  wxString fileName = dlg.GetFileName();
833  if (fileName.empty() )
834  return;
835 
836  wxString err_msg;
837 
838  try {
839  bool withHeader = dlg.GetWithHeaders();
840  bool selected_only = dlg.GetSelectedOnly();
841 
842  unique_ptr<CNcbiOstream> os(new CNcbiOfstream(fileName.fn_str(), IOS_BASE::out));
843  if (os.get() == NULL)
844  NCBI_THROW(CException, eUnknown, "File is not accessible");
845 
846  if (selected_only) {
847  vector<int> rows, cols;
848  if (!x_GetRectSelection(rows, cols)) {
849  wxMessageBox(wxT("Can't export non rectangular selection."), wxT("Export to CSV"),
850  wxOK | wxICON_EXCLAMATION, this);
851  return;
852  }
853 
854  if (rows.empty() || cols.empty())
855  return;
856 
857  CwxGridTableExport(*m_GridAdapter, *os, rows, cols, withHeader, ',');
858  } else {
859  vector<int> cols;
860  dlg.GetSelectedColumns(cols);
861  if (cols.size() != colNum) {
862  vector<int> rows;
863  for (int i = 0; i < m_GridAdapter->GetRowsCount(); ++i) {
864  rows.push_back(i);
865  }
866  CwxGridTableExport(*m_GridAdapter, *os, rows, cols, withHeader, ',');
867  }
868  else
869  CwxGridTableExport(*m_GridAdapter, *os, withHeader, ',');
870  }
871  os->flush();
872  }
873  catch (const CException& e) {
874  err_msg = ToWxString(e.GetMsg());
875  }
876 
877  if (!err_msg.empty()) {
878  wxMessageBox(wxT("Failed to save file: ") + err_msg, wxT("Error"),
879  wxOK | wxICON_ERROR, this);
880  }
881 }
882 
883 void CGridWidget::OnSearchIncludeCellValue(wxCommandEvent& WXUNUSED(event))
884 {
885  if (m_PopupGridX < 0 || m_PopupGridX >= m_GridAdapter->GetColsCount() ||
886  m_PopupGridY < 0 || m_PopupGridY >= m_GridAdapter->GetRowsCount())
887  return;
888 
890  string cell_value;
891 
893  cell_value = NStr::TruncateSpaces(cell_value);
894 
895  // Add quotes if needed - for any cell that is not a number
896  if (cell_value=="") {
897  cell_value = "\"\"";
898  }
899  else if ((cell_value.find_first_of(' ') != string::npos) ||
900  (cell_value.find_first_of('\t') != string::npos)) {
901  cell_value = "\"" + cell_value + "\"";
902  }
903  else {
904  try {
905  NStr::StringToDouble(cell_value);
906  }
907  catch (CStringException&) {
908  cell_value = "\"" + cell_value + "\"";
909  }
910  }
911 
912  string query_constraint = "(" + col_name + " = " + cell_value + ")";
913 
914  m_QueryPanel->AddQueryText(query_constraint);
915 }
916 
917 void CGridWidget::OnSearchExcludeCellValue(wxCommandEvent& WXUNUSED(event))
918 {
919  if (m_PopupGridX < 0 || m_PopupGridX >= m_GridAdapter->GetColsCount() ||
920  m_PopupGridY < 0 || m_PopupGridY >= m_GridAdapter->GetRowsCount())
921  return;
922 
925 
926  string query_constraint = "(" + col_name + " != " + cell_value + ") ";
927 
928  m_QueryPanel->AddQueryText(query_constraint);
929 }
930 
931 void CGridWidget::OnCopy(wxCommandEvent& event)
932 {
933  vector<int> rows, cols;
934  if (!x_GetRectSelection(rows, cols)) {
935  wxMessageBox(wxT("Can't copy non rectangular selection."), wxT("Error"),
936  wxOK | wxICON_ERROR, this);
937  return;
938  }
939 
940  if (rows.empty() || cols.empty())
941  return;
942 
943  wxString err_msg;
944 
945  try {
946  wxStringOutputStream stream;
947  wxTextOutputStream os(stream);
948 
949  {{ // ostringstream gives '\n' as endl, but we want to pass to clipboard native endl's
950  ostringstream oss;
951  CwxGridTableExport(*m_GridAdapter, oss, rows, cols, false);
952  os << wxString::FromUTF8(oss.str().c_str());
953  }}
954 
955  if (wxTheClipboard->Open()) {
956  wxTheClipboard->SetData( new wxTextDataObject(stream.GetString()));
957  wxTheClipboard->Close();
958  }
959  }
960  catch (const CException& e) {
961  err_msg = ToWxString(e.GetMsg());
962  }
963 
964  if (!err_msg.empty()) {
965  wxMessageBox(wxT("Copy to Clipboard failed: ") + err_msg, wxT("Error"),
966  wxOK | wxICON_ERROR, this);
967  }
968 }
969 
970 bool CGridWidget::x_GetRectSelection(vector<int>& rows, vector<int>&cols)
971 {
972  int colNum = m_Grid->GetNumberCols();
973  map<int, bm::bvector<> > selected;
974 
975 // Block selection
976  wxGridCellCoordsArray selTopLeft = m_Grid->GetSelectionBlockTopLeft();
977  wxGridCellCoordsArray selBottomRight = m_Grid->GetSelectionBlockBottomRight();
978  size_t blockCount = selTopLeft.GetCount();
979 
980  if (blockCount > 0 && blockCount == selBottomRight.GetCount()) {
981  for (size_t i = 0; i < blockCount; ++i) {
982  for (int row = selTopLeft[i].GetRow(); row <= selBottomRight[i].GetRow(); ++row) {
983  for (int col = selTopLeft[i].GetCol(); col <= selBottomRight[i].GetCol(); ++col) {
984  selected[row].set(col);
985  }
986  }
987  }
988  }
989 
990 // Cell Selection
991  wxGridCellCoordsArray selCells = m_Grid->GetSelectedCells();
992  for (size_t i = 0; i < selCells.GetCount(); ++i) {
993  int row = selCells[i].GetRow(), col = selCells[i].GetCol();
994  selected[row].set(col);
995  }
996 
997 // Row selection
998  wxArrayInt selRows = m_Grid->GetSelectedRows();
999  for (size_t i = 0; i < selRows.size(); ++i) {
1000  int row = selRows[i];
1001  selected[row].set_range(0, colNum - 1);
1002  }
1003 
1004  if (selected.empty()) {
1005  int curRow = m_Grid->GetGridCursorRow();
1006  if (curRow >= 0) {
1007  selected[curRow].set(m_Grid->GetGridCursorCol());
1008  }
1009  }
1010 
1011  if (selected.empty())
1012  return true;
1013 
1014  map<int, bm::bvector<> >::const_iterator it = selected.begin();
1015  bm::bvector<> front = it->second;
1016  for (++it; it != selected.end(); ++it) {
1017  if (it->second != front)
1018  return false;
1019  }
1020 
1021  for (bm::bvector<>::enumerator it2 = front.first(); it2 != front.end(); ++it2) {
1022  cols.push_back(*it2);
1023  }
1024 
1025  for (it = selected.begin(); it != selected.end(); ++it) {
1026  rows.push_back(it->first);
1027  }
1028 
1029  return true;
1030 }
1031 
1032 void CGridWidget::OnUpdateCopy(wxUpdateUIEvent& event)
1033 {
1034  event.Enable(true);
1035 }
1036 
1037 void CGridWidget::OnRefreshClick(wxCommandEvent& event)
1038 {
1039  // send a message to the validate view that is it should re-read it's data and refresh itself
1041  Send(&evt, ePool_Parent);
1042 }
1043 
EVT_UPDATE_UI(eCmdAlnShowMethodsDlg, CAlnMultiWidget::OnUpdateShowMethodDlg) EVT_UPDATE_UI(eCmdMethodProperties
#define true
Definition: bool.h:35
#define false
Definition: bool.h:36
virtual void SetRegistryPath(const string &path)
Definition: dialog.cpp:59
CEvent - generic event implementation TODO TODO - Attachments.
Definition: event.hpp:86
void OnTimer(wxTimerEvent &event)
bool m_isShowRefreshButton
void OnSearchExcludeCellValue(wxCommandEvent &event)
void OnHyperlinkHover(wxHyperlinkEvent &event)
void OnGridCellLeftDClick(wxGridEvent &evt)
CRef< CTDQueryDataSource > m_QueryDS
void GetSelectedRows(set< int > &rows) const
void OnGridSelectCell(wxGridEvent &evt)
CIRef< ITableSelection > m_TableSelection
post-cell select timer
void x_CompleteQuery()
void x_UpdateRowsToSelection(bool b)
string m_RegPath
void OnSearchIncludeCellValue(wxCommandEvent &event)
void GetSelectedObjects(TConstScopedObjects &objects) const
void x_LeftDClick(int Row)
void SetEventExt(IGridEvtExt *evtExt)
bool m_UseCursorSelection
virtual void QueryEnd(CMacroQueryExec *exec)
Re-enable any widgets disabled during the query.
size_t SetSelection(CSelectionEvent &evt)
void GetSelectedObjectsOrdered(TConstScopedObjects &objects)
Get objects in a priority order (favor row selections)
void x_InitGrid(ICommandProccessor *cmdProccessor)
void IterateSelection(int dir)
Advance to previous/next selected row from query (in current sort order)
virtual void SaveSettings() const
CIRef< ITableData > m_TableData
interface to the table data (unsorted)
virtual void SetHideUnselected(bool b)
If true, only rows that were selected by prevous query will be shown.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxBORDER_NONE)
wxButton * m_RefreshButton
int m_PopupGridX
Remember location of cell from popup (right click) so we can use that location (potentially) in funct...
void OnGridCellRightClick(wxGridEvent &evt)
void GetSelection(CSelectionEvent &evt) const
Get all selected objects.
CQueryParsePanel * m_QueryPanel
controls assigned to the toolbar:
wxTimer m_Timer
void OnUpdateCopy(wxUpdateUIEvent &event)
void OnExportToCSV(wxCommandEvent &event)
void OnGridRangeSelect(wxGridRangeSelectEvent &evt)
void OnRefreshClick(wxCommandEvent &event)
wxBoxSizer * m_ToolbarSizer
toolbar that contains the query toolbar and additional buttons added by AddControl() (Refresh)
virtual void LoadSettings()
void UseFixedFont()
void OnGridLabelLeftDClick(wxGridEvent &evt)
@ ID_REFRESH_BUTTON
! how do the numbers get assigned so they do not clash?
virtual void QueryStart()
Disable any widgets that the user should not use during the query.
CwxGridTableAdapter * m_GridAdapter
adapter that matches the grid cells to sorted entries from m_TableData
virtual void SetSelectAll(bool b)
Set to true to show all rows selected by most recent query as selected.
bool m_SelectAll
when true, rows selected from query panel are all shown as selected
CGrid * m_Grid
the grid widget
bool m_ShowSelectAll
when true (by default) the Select All checkbox is shown
void CreateControls()
Creates the controls and sizers.
void Init(ITableData &table_data, ICommandProccessor *cmdProccessor)
bool x_GetRectSelection(vector< int > &rows, vector< int > &cols)
bool m_isShowGridLines
void x_ScrollToRow(int row_idx)
virtual void SetRegistryPath(const string &reg_path)
wxStaticLine * m_StaticLine
void OnCopy(wxCommandEvent &event)
CIRef< IGridEvtExt > m_GridEvtExt
void x_GetSelectedRows(set< int > &rows) const
void x_LeftClick(int Row, int modifiers)
CGrid.
Definition: grid.hpp:50
static CGuiRegistry & GetInstance()
access the application-wide singleton
Definition: registry.cpp:400
CRegistryReadView GetReadView(const string &section) const
get a read-only view at a particular level.
Definition: registry.cpp:428
class CMacroQueryExec
CQueryParsePanel.
virtual void SaveSettings() const
virtual void SetRegistryPath(const string &reg_path)
void SetDefaultQueries(const TNamedQueries &q)
Set the set of default queries for the current data source.
void HideSelectAll(void)
Hide the Select All checkbox.
bool IsSelectAll()
Return true if select all checkbox is checked.
virtual void Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize)
Create window.
virtual void LoadSettings()
vector< pair< string, string > > TNamedQueries
void AddQueryText(const string &query_mod)
Add given string to currently displayed query text.
class CRegistryReadView provides a nested hierarchical view at a particular key.
Definition: reg_view.hpp:58
void GetStringVec(const string &key, vector< string > &val) const
Definition: reg_view.cpp:263
CSelectionEvent CSelectionEvent is used for broadcasting selection between views.
Definition: obj_event.hpp:68
void GetAllObjects(TConstObjects &objs) const
Definition: obj_event.cpp:314
void GetOther(TConstObjects &objs) const
Definition: obj_event.cpp:338
bool AddObjectSelection(const CObject &obj)
Definition: obj_event.cpp:177
CStringException –.
Definition: ncbistr.hpp:4505
class IQueryDataSource
std::vector< size_t > GetQueryResults() const
@ eWidgetSelectionChanged
a view has been destroyed
Definition: view_event.hpp:55
wxString GetFileName() const
void GetSelectedColumns(vector< int > &columns) const
Gets the columns, selected by the user.
bool GetWithHeaders() const
void SetColumnsList(const vector< wxString > &columns)
Sets the columns lists.
bool GetSelectedOnly() const
virtual void SetSelection(const vector< size_t > &query_sel)
virtual size_t GetOriginalRow(size_t queryRow) const
virtual void SaveSettings() const
virtual void IterateSelection(int dir)
virtual wxString GetValue(int row, int col)
virtual wxString GetColLabelValue(int col)
virtual void SetRegistryPath(const string &reg_path)
virtual size_t GetCurrentRow(size_t queryRow) const
Undo/Redo interface for editing operations.
virtual bool GetHideUnselected() const
virtual size_t GetCurrentSelection() const
virtual void HideUnselected(bool b)
IObjectCmdContributor - contributes commands applicable to scoped objects.
pair< wxMenu *, wxEvtHandler * > TContribution
virtual TContribution GetMenu(TConstScopedObjects &objects)=0
returns a menu with commands applicable to the objects and optional command handler for the commands ...
Constant iterator designed to enumerate "ON" bits.
Definition: bm.h:603
const_iterator begin() const
Definition: map.hpp:151
const_iterator end() const
Definition: map.hpp:152
bool empty() const
Definition: map.hpp:149
Definition: map.hpp:338
Definition: set.hpp:45
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
const_iterator begin() const
Definition: set.hpp:135
bool empty() const
Definition: set.hpp:133
const_iterator find(const key_type &key) const
Definition: set.hpp:137
const_iterator end() const
Definition: set.hpp:136
#define _(proto)
Definition: ct_nlmzip_i.h:78
std::ofstream out("events_result.xml")
main entry point for tests
#define EVT_HYPERLINK_HOVER(id, fn)
Definition: grid.hpp:95
#define ID_SEARCH_EXCLUDE_VALUE
Definition: grid_widget.cpp:73
static const char * kQuery
#define ID_EXPORT_TO_CSV
Definition: grid_widget.cpp:71
static bool s_BlockSelChangeUpdate
#define ID_SEARCH_INCLUDE_VALUE
Definition: grid_widget.cpp:72
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NULL
Definition: ncbistd.hpp:225
#define _TRACE(message)
Definition: ncbidbg.hpp:122
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
const string & GetMsg(void) const
Get message string.
Definition: ncbiexpt.cpp:461
virtual void RemoveListener(CEventHandler *listener)
Remove a listener.
void GetExtensionAsInterface(const string &ext_point_id, vector< CIRef< I > > &interfaces)
GetExtensionAsInterface() is a helper function that extracts all extensions implementing the specifie...
vector< CConstRef< CObject > > TConstObjects
Definition: objects.hpp:64
CConstRef< CObject > object
Definition: objects.hpp:52
virtual void AddListener(CEventHandler *listener, int pool_name=ePool_Default)
Add a listener.
vector< SConstScopedObject > TConstScopedObjects
Definition: objects.hpp:65
virtual bool Send(CEvent *evt, EDispatch disp_how=eDispatch_Default, int pool_name=ePool_Default)
Sends an event synchronously.
@ eEvent_Message
message from one class to another
Definition: event.hpp:99
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
IO_PREFIX::ofstream CNcbiOfstream
Portable alias for ofstream.
Definition: ncbistre.hpp:500
static double StringToDouble(const CTempStringEx str, TStringToNumFlags flags=0)
Convert string to double.
Definition: ncbistr.cpp:1387
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3182
END_EVENT_TABLE()
int i
#define wxT(x)
Definition: muParser.cpp:41
constexpr auto front(list< Head, As... >, T=T()) noexcept -> Head
double value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:228
const struct ncbi::grid::netcache::search::fields::SIZE size
#define EXT_POINT__SCOPED_OBJECTS__CMD_CONTRIBUTOR
This Extension Point allows external components to add commands that can be applied to scoped CObject...
static static static wxID_ANY
ViewerWindowBase::OnEditMenu ViewerWindowBase::OnJustification EVT_MENU(MID_SHOW_GEOM_VLTNS, ViewerWindowBase::OnShowGeomVltns) EVT_MENU(MID_FIND_PATTERN
void Merge(wxMenu &menu_1, const wxMenu &menu_2)
merges all items form menu_2 into menu_1, preserving the structure if possible
Definition: wx_utils.cpp:579
wxString ToWxString(const string &s)
Definition: wx_utils.hpp:173
string ToStdString(const wxString &s)
Definition: wx_utils.hpp:161
void CleanupSeparators(wxMenu &menu)
Removes extra separators (in the begining or at the end of the menu, ot those that precede other sepa...
Definition: wx_utils.cpp:668
Modified on Sat Dec 09 04:49:16 2023 by modify_doxy.py rev. 669887