CMS 3D CMS Logo

FWGUIEventDataAdder.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: Core
4 // Class : FWGUIEventDataAdder
5 //
6 // Implementation:
7 // <Notes on implementation>
8 //
9 // Original Author: Chris Jones
10 // Created: Fri Jun 13 09:58:53 EDT 2008
11 //
12 
13 // system include files
14 #include <iostream>
15 #include <sigc++/signal.h>
16 #include <boost/bind.hpp>
17 #include <algorithm>
18 #include <cctype>
19 #include <string>
20 
21 #include "TGFrame.h"
22 #include "TGTextEntry.h"
23 #include "TGButton.h"
24 #include "TGMsgBox.h"
25 #include "TClass.h"
26 #include "TFile.h"
27 #include "TTree.h"
28 #include "TBranch.h"
29 
30 // user include files
42 //
43 // constants, enums and typedefs
44 //
45 static const std::string& dataForColumn( const FWJobMetadataManager::Data& iData, int iCol)
46 {
47  switch (iCol) {
48  case 0:
49  return iData.purpose_;
50  break;
51  case 4:
52  return iData.type_;
53  break;
54  case 1:
55  return iData.moduleLabel_;
56  break;
57  case 2:
58  return iData.productInstanceLabel_;
59  break;
60  case 3:
61  return iData.processName_;
62  break;
63  default:
64  break;
65  }
66  static const std::string s_blank;
67  return s_blank;
68 }
69 
70 static const unsigned int kNColumns = 5;
72 public:
74  m_manager(manager), m_selectedRow(-1), m_filter()
75  {
76  reset();
77  }
78 
79  int numberOfRows() const override {
80  return m_row_to_index.size();
81  }
82  int numberOfColumns() const override {
83  return kNColumns;
84  }
85 
90  virtual void sortWithFilter(const char *filter)
91  {
92  m_filter = filter;
93  sort(-1, sortOrder());
94  dataChanged();
95  }
96 
97  int unsortedRowNumber(int iSortedRowNumber) const override {
98  return m_row_to_index[iSortedRowNumber];
99  }
100 
101  void implSort(int col, bool sortOrder) override;
102  std::vector<std::string> getTitles() const override {
103  std::vector<std::string> returnValue;
104  returnValue.reserve(kNColumns);
105  returnValue.push_back("Purpose");
106  returnValue.push_back("Module Label");
107  returnValue.push_back("Product Instance Label");
108  returnValue.push_back("Process Name");
109  returnValue.push_back("C++ Class");
110  return returnValue;
111  }
112 
113  FWTableCellRendererBase* cellRenderer(int iSortedRowNumber, int iCol) const override
114  {
115 
116  if(static_cast<int>(m_row_to_index.size())>iSortedRowNumber) {
117  int unsortedRow = m_row_to_index[iSortedRowNumber];
118  const FWJobMetadataManager::Data& data = (m_manager->usableData())[unsortedRow];
119 
120  m_renderer.setData(dataForColumn(data,iCol),m_selectedRow==unsortedRow);
121  } else {
122  m_renderer.setData(std::string(),false);
123  }
124  return &m_renderer;
125  }
126 
127  void setSelection (int row, int mask) {
128  if(mask == 4) {
129  if( row == m_selectedRow) {
130  row = -1;
131  }
132  }
133  changeSelection(row);
134  }
135 
136  virtual const std::string title() const {
137  return "Viewable Collections";
138  }
139 
140  int selectedRow() const {
141  return m_selectedRow;
142  }
143  //virtual void sort (int col, bool reset = false);
144  virtual bool rowIsSelected(int row) const {
145  return m_selectedRow == row;
146  }
147 
148  void reset() {
149  changeSelection(-1);
150  m_row_to_index.clear();
151  m_row_to_index.reserve(m_manager->usableData().size());
152  for(unsigned int i =0; i < m_manager->usableData().size(); ++i) {
153  m_row_to_index.push_back(i);
154  }
155  dataChanged();
156  }
157  sigc::signal<void,int> indexSelected_;
158 private:
159  void changeSelection(int iRow) {
160  if(iRow != m_selectedRow) {
161  m_selectedRow=iRow;
162  if(-1 == iRow) {
163  indexSelected_(-1);
164  } else {
165  indexSelected_(iRow);
166  }
168  }
169  }
171  std::vector<int> m_row_to_index;
175 };
176 
177 namespace {
178 void strip(std::string &source, const char *str)
179  {
180  std::string remove(str);
181  while(true)
182  {
183  size_t found = source.find(remove);
184  if (found == std::string::npos)
185  break;
186  source.erase(found, remove.size());
187  }
188  }
189 
207  class SortAndFilter
208  {
209  public:
210  SortAndFilter(const char *filter, int column, bool order,
211  const std::vector<FWJobMetadataManager::Data> &data)
212  : m_filter(filter),
213  m_column(column),
214  m_order(order),
215  m_data(data)
216  {
217  simplify(m_filter);
218  m_weights.resize(data.size());
219 
220  // Calculate whether or not all the entries match the given filter.
221  // This is done only once, since it's invariant under permutations
222  // of the data.
223  for (size_t i = 0, e = m_weights.size(); i != e; ++i)
224  m_weights[i] = matchesFilter(m_data[i]);
225  }
226 
230  static void simplify(std::string &str)
231  {
232  std::transform(str.begin(), str.end(), str.begin(), tolower);
233  strip(str, "std::");
234  strip(str, "edm::");
235  strip(str, "vector<");
236  strip(str, "clonepolicy");
237  strip(str, "ownvector");
238  strip(str, "rangemap<");
239  strip(str, "strictweakordering<");
240  strip(str, "sortedcollection<");
241  strip(str, "reco::");
242  strip(str, "edmnew::");
243  }
244 
245  unsigned int matches(const std::string &str) const
246  {
247  std::string up(str);
248  simplify(up);
249  const char *begin = up.c_str();
250 
251  // If the filter is empty, we consider anything as matching
252  // (i.e. it will not loop).
253  // If the filter is not empty but the string to be matched is, we
254  // consider it as if it was not matching.
255  if ((!m_filter.empty()) && str.empty())
256  return 0;
257 
258  // There are two level of matching. "Full string" and
259  // "All characters". "Full string" matches return an higher weight
260  // and therefore should appear on top.
261  if (strstr(begin, m_filter.c_str()))
262  return 2;
263 
264  return 0;
265  }
266 
272  unsigned int matchesFilter(const FWJobMetadataManager::Data &data) const
273  {
274  std::vector<unsigned int> scores;
275  scores.reserve(10);
276  scores.push_back(matches(data.purpose_));
277  scores.push_back(matches(data.type_));
278  scores.push_back(matches(data.moduleLabel_));
279  scores.push_back(matches(data.productInstanceLabel_));
280  scores.push_back(matches(data.processName_));
281  std::sort(scores.begin(), scores.end());
282  return scores.back();
283  }
284 
288  bool operator()(const int &aIndex, const int &bIndex)
289  {
290  // In case no column is selected, we sort by relevance of the
291  // filter.
292  if (m_column == -1)
293  return m_weights[aIndex] >= m_weights[bIndex];
294 
295  const FWJobMetadataManager::Data &a = m_data[aIndex];
296  const FWJobMetadataManager::Data &b = m_data[bIndex];
297 
298  if (m_order)
299  return dataForColumn(a, m_column) < dataForColumn(b, m_column);
300  else
301  return dataForColumn(a, m_column) > dataForColumn(b, m_column);
302  }
303  private:
305  int m_column;
306  bool m_order;
307 
308  const std::vector<FWJobMetadataManager::Data> &m_data;
309  std::vector<unsigned int> m_weights;
310  };
311 
312  void doSort(int column,
313  const char *filter,
314  bool descentSort,
315  const std::vector<FWJobMetadataManager::Data>& iData,
316  std::vector<int>& oRowToIndex)
317  {
318  std::vector<int> ordered;
319  ordered.reserve(iData.size());
320 
321  for (size_t i = 0, e = iData.size(); i != e; ++i)
322  ordered.push_back(i);
323 
324  SortAndFilter sorter(filter, column, descentSort, iData);
325  // GE: Using std::sort does not work for some reason... Bah...
326  std::stable_sort(ordered.begin(), ordered.end(), sorter);
327 
328  oRowToIndex.clear();
329  oRowToIndex.reserve(ordered.size());
330  // Only keep track of the rows that match.
331  for (size_t i = 0, e = ordered.size(); i != e; ++i)
332  if (sorter.matchesFilter(iData[ordered[i]]) != 0)
333  oRowToIndex.push_back(ordered[i]);
334  }
335 }
336 
337 void
339 {
340  doSort(column, m_filter.c_str(), sortOrder, m_manager->usableData(), m_row_to_index);
341 }
342 
343 //
344 // static data member definitions
345 //
346 
347 //
348 // constructors and destructor
349 //
350 
352  UInt_t iWidth,UInt_t iHeight,
353  FWEventItemsManager* iManager,
354  TGFrame* iParent,
355  FWJobMetadataManager *iMetadataManager)
356  :
357  m_manager(iManager),
358  m_metadataManager(iMetadataManager),
359  m_parentFrame(iParent)
360 {
362  createWindow();
363 }
364 
365 // FWGUIEventDataAdder::FWGUIEventDataAdder(const FWGUIEventDataAdder& rhs)
366 // {
367 // // do actual copying here;
368 // }
369 
371 {
372  /*
373  // m_frame->Cleanup();
374  // delete m_frame;
375  m_frame=0;
376  // delete m_tableWidget;
377  m_tableWidget=0;
378  delete m_tableManager;
379  m_tableManager=0;
380  */
381 }
382 
383 //
384 // assignment operators
385 //
386 // const FWGUIEventDataAdder& FWGUIEventDataAdder::operator=(const FWGUIEventDataAdder& rhs)
387 // {
388 // //An exception safe implementation is
389 // FWGUIEventDataAdder temp(rhs);
390 // swap(rhs);
391 //
392 // return *this;
393 // }
394 
395 //
396 // member functions
397 //
398 void
400 {
401  TClass* theClass = TClass::GetClass(m_type.c_str());
402  if(nullptr==theClass) {
403  return;
404  }
405  const std::string moduleLabel = m_moduleLabel;
406  if(moduleLabel.empty()) {
407  return;
408  }
409 
410  const std::string name = m_name->GetText();
411  if(name.empty()) {
412  return;
413  }
414 
415  if ( m_manager->find( name ) ) {
416  TString msg("Event item '");
417  msg += name;
418  msg += "' is already registered. Please use another name.";
419  fwLog(fwlog::kWarning) << msg.Data() << std::endl;
420  new TGMsgBox(gClient->GetDefaultRoot(), m_frame,
421  "Error - Name conflict", msg, kMBIconExclamation, kMBOk);
422  return;
423  }
424 
425  int largest = -1;
426  if(m_manager->begin() != m_manager->end()) {
427  if ( *(m_manager->begin()) )
428  largest = (*(m_manager->begin()))->layer();
429  }
431  itEnd = m_manager->end();
432  it!=itEnd;
433  ++it) {
434  if((*it) && largest < (*it)->layer()) {
435  largest = (*it)->layer();
436  }
437  }
438  ++largest;
440  if(m_doNotUseProcessName->IsOn() && m_doNotUseProcessName->IsEnabled()) {
441  processName="";
442  }
443  FWPhysicsObjectDesc desc(name, theClass, m_purpose,
445  moduleLabel,
447  processName,
448  "",
449  largest);
450  m_manager->add(desc);
451 }
452 
453 void
455 {
456  addNewItem();
457  windowIsClosing();
458 }
459 
460 void
462 {
463  // Map main frame
464  if(nullptr==m_frame) {
465  createWindow();
466  }
467  m_frame->MapWindow();
468 }
469 
470 void
472 {
473  m_name->SetText("");
474  m_search->SetText("");
475  m_purpose.clear();
476  m_type.clear();
477  m_moduleLabel.clear();
478  m_processName.clear();
479  m_productInstanceLabel.clear();
480  m_apply->SetEnabled(false);
481  m_applyAndClose->SetEnabled(false);
482 
483  m_frame->UnmapWindow();
484  m_frame->DontCallClose();
485 }
486 
487 void
489 {
492 }
493 
494 void
496 {
499 
500  m_frame = new TGTransientFrame(gClient->GetDefaultRoot(),m_parentFrame,600,400);
501  m_frame->Connect("CloseWindow()","FWGUIEventDataAdder",this,"windowIsClosing()");
502 
503  FWDialogBuilder builder(m_frame);
504  TGTextButton *cancelButton, *resetButton;
505 
506  builder.indent(10)
507  .spaceDown(15)
508  .addLabel("Search:", 0).expand(false).spaceUp(4).floatLeft(4)
509  .addTextEntry("", &m_search).spaceUp(0)
510  .frameSpaceDown(10)
511  .addLabel("Viewable Collections", 8)
512  .frameSpaceDown(5)
514  .addLabel("Name:", 0).expand(false).spaceUp(4).floatLeft(4)
515  .addTextEntry("", &m_name).spaceUp(0).floatLeft(4)
516  .addTextButton(" Reset ", &resetButton).expand(false, false)
517  .frameSpaceUpDown(5)
518  .addCheckbox("Do not use Process Name and "
519  "instead only get this data "
520  "from the most recent Process",
522  .frameSpaceDown(15)
523  .hSpacer().floatLeft(0)
524  .addTextButton(" Close ", &cancelButton).expand(false).floatLeft(4)
525  .addTextButton(" Add Data ", &m_apply).expand(false).floatLeft(4)
526  .addTextButton(" Add Data && Close ", &m_applyAndClose).expand(false)
527  .spaceRight(25).spaceDown(15);
528 
529  m_search->Connect("TextChanged(const char *)", "FWGUIEventDataAdder",
530  this, "updateFilterString(const char *)");
531  m_search->SetEnabled(true);
535  m_tableWidget->Connect("rowClicked(Int_t,Int_t,Int_t,Int_t,Int_t)",
536  "FWGUIEventDataAdder",this,
537  "rowClicked(Int_t,Int_t,Int_t,Int_t,Int_t)");
538 
540  m_name->SetState(true);
541  resetButton->SetEnabled(true);
542  resetButton->Connect("Clicked()", "FWGUIEventDataAdder", this, "resetNameEntry()");
543  m_doNotUseProcessName->SetState(kButtonDown);
544  cancelButton->Connect("Clicked()","FWGUIEventDataAdder", this, "windowIsClosing()");
545  cancelButton->SetEnabled(true);
546  m_apply->Connect("Clicked()", "FWGUIEventDataAdder", this, "addNewItem()");
547  m_applyAndClose->Connect("Clicked()", "FWGUIEventDataAdder", this, "addNewItemAndClose()");
548 
549  m_frame->SetWindowName("Add Collection");
550  m_frame->MapSubwindows();
551  m_frame->Layout();
552 }
553 
558 void
560 {
562  m_tableManager->sort(0, true);
563 }
564 
565 void
567 {
568  m_name->SetText(m_apply->IsEnabled() ? m_moduleLabel.c_str() : "", kFALSE);
569 }
570 
571 void
573 {
574  if(-1 != iSelectedIndex) {
575  std::vector<FWJobMetadataManager::Data> &metadata = m_metadataManager->usableData();
576  m_purpose = metadata[iSelectedIndex].purpose_;
577  m_type = metadata[iSelectedIndex].type_;
578  std::string oldModuleLabel = m_moduleLabel;
579  m_moduleLabel = metadata[iSelectedIndex].moduleLabel_;
580  m_productInstanceLabel = metadata[iSelectedIndex].productInstanceLabel_;
581  m_processName = metadata[iSelectedIndex].processName_;
582 
583  if(strlen(m_name->GetText())==0 || oldModuleLabel == m_name->GetText()) {
584  m_name->SetText(m_moduleLabel.c_str());
585  }
586  m_apply->SetEnabled(true);
587  m_applyAndClose->SetEnabled(true);
588 
589  //Check to see if this is the last process, if it is then we can let the user decide
590  // to not use the process name when doing the lookup. This makes a saved configuration
591  // more robust. However, if they choose a collection not from the last process then we need the
592  // process name in order to correctly get the data they want
593  bool isMostRecentProcess =true;
594  int index = 0;
595  for(std::vector<FWJobMetadataManager::Data>::iterator it = metadata.begin(), itEnd = metadata.end();
596  it != itEnd && isMostRecentProcess;
597  ++it,++index) {
598  if(index == iSelectedIndex) {continue;}
599  if(it->moduleLabel_ == m_moduleLabel &&
600  it->purpose_ == m_purpose &&
601  it->type_ == m_type &&
602  it->productInstanceLabel_ == m_productInstanceLabel) {
603  //see if this process is newer than the data requested
604 
605  for(size_t pni = 0, pne = m_metadataManager->processNamesInJob().size();
606  pni != pne; ++pni)
607  {
609  if (m_processName == processName)
610  break;
611 
612  if(it->processName_ == processName)
613  {
614  isMostRecentProcess = false;
615  break;
616  }
617  }
618  }
619  }
620  if(isMostRecentProcess) {
621  if(!m_doNotUseProcessName->IsEnabled()) {
622  m_doNotUseProcessName->SetEnabled(true);
623  }
624  } else {
625  //NOTE: must remember state before we get here because 'enable' and 'on' are mutually
626  // exlcusive :(
627  m_doNotUseProcessName->SetEnabled(false);
628  }
629  }
630 }
631 
632 void
633 FWGUIEventDataAdder::rowClicked(Int_t iRow,Int_t iButton,Int_t iKeyMod,Int_t,Int_t)
634 {
635  if(iButton==kButton1) {
636  m_tableManager->setSelection(iRow,iKeyMod);
637  }
638 }
639 
640 //
641 // const member functions
642 //
643 
644 //
645 // static member functions
646 //
FWDialogBuilder & spaceUp(size_t spacing=3)
size
Write out results.
Definition: BitonicSort.h:8
FWTextTableCellRenderer m_renderer
int unsortedRowNumber(int iSortedRowNumber) const override
when passed the index to the sorted order of the rows it returns the original row number from the und...
TGTextButton * m_applyAndClose
void implSort(int col, bool sortOrder) override
Called by &#39;sort&#39; method to actually handle the sorting of the rows. Arguments are the same as &#39;sort&#39;...
bool sortOrder(void)
The current sort order for the table.
virtual bool rowIsSelected(int row) const
void setSelection(int row, int mask)
FWEventItemsManager * m_manager
FWDialogBuilder & addTextButton(const char *text, TGTextButton **out=nullptr)
std::vector< int > m_row_to_index
sigc::signal< void > metadataChanged_
void sort(int iCol, bool iSortOrder)
Call to have table sorted on values in column iCol with the sort order being descending if iSortOrder...
std::vector< std::string > & processNamesInJob()
int numberOfRows() const override
Number of rows in the table.
void SetHeaderBackgroundColor(Pixel_t)
int numberOfColumns() const override
Number of columns in the table.
void dataChanged()
Classes which inherit from FWTableManagerBase must call this when their underlying data changes...
virtual const std::string title() const
FWDialogBuilder & addLabel(const char *text, size_t fontSize=12, size_t weight=0, TGLabel **out=nullptr)
static const FWDisplayProperties defaultProperties
FWDialogBuilder & addCheckbox(const char *text, TGCheckButton **out=nullptr)
void SetLineSeparatorColor(Pixel_t)
std::vector< std::string > getTitles() const override
returns the title names for each column
FWJobMetadataManager * m_metadataManager
std::string m_productInstanceLabel
void disableGrowInWidth()
FWDialogBuilder & frameSpaceDown(size_t spacing=3)
FWGUIEventDataAdder(UInt_t w, UInt_t, FWEventItemsManager *, TGFrame *, FWJobMetadataManager *)
void updateFilterString(const char *str)
FWDialogBuilder & frameSpaceUpDown(size_t spacing=3)
virtual void sortWithFilter(const char *filter)
std::vector< Data > & usableData()
FWEventItem * add(const FWPhysicsObjectDesc &iItem, const FWConfiguration *pbConf=nullptr, bool doSetEvent=true)
TGCheckButton * m_doNotUseProcessName
TGTransientFrame * m_frame
const FWEventItem * find(const std::string &iName) const
void SetBackgroundColor(Pixel_t) override
FWDialogBuilder & hSpacer(size_t size=0)
FWDialogBuilder & addTextEntry(const char *defaultText, TGTextEntry **out)
void setData(const std::string &, bool isSelected)
const_iterator begin() const
NOTE: iterator is allowed to return a null object for items that have been removed.
FWDialogBuilder & floatLeft(size_t spacing=3)
FWTableCellRendererBase * cellRenderer(int iSortedRowNumber, int iCol) const override
#define fwLog(_level_)
Definition: fwLog.h:50
double b
Definition: hdecay.h:120
tuple msg
Definition: mps_check.py:277
FWDialogBuilder & addTable(FWTableManagerBase *manager, FWTableWidget **out=nullptr)
FWDialogBuilder & expand(size_t expandX=true, size_t expandY=false)
static const std::string & dataForColumn(const FWJobMetadataManager::Data &iData, int iCol)
#define begin
Definition: vmac.h:32
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
double a
Definition: hdecay.h:121
sigc::signal< void, int > indexSelected_
void visualPropertiesChanged()
Classes which inherit from FWTableManagerBase must call this when how the data is shown (e...
col
Definition: cuy.py:1008
FWTableWidget * m_tableWidget
DataAdderTableManager * m_tableManager
void rowClicked(Int_t iRow, Int_t iButton, Int_t iKeyMod, Int_t, Int_t)
DataAdderTableManager(FWJobMetadataManager *manager)
FWDialogBuilder & indent(int left=2, int right=-1)
std::vector< FWEventItem * >::const_iterator const_iterator
static std::string const source
Definition: EdmProvDump.cc:43
FWDialogBuilder & spaceDown(size_t spacing=3)
FWJobMetadataManager * m_manager
static const unsigned int kNColumns
const_iterator end() const
FWDialogBuilder & spaceRight(size_t spacing=3)