CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_0/src/Fireworks/Core/src/FWGUIEventDataAdder.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     Core
00004 // Class  :     FWGUIEventDataAdder
00005 //
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  Chris Jones
00010 //         Created:  Fri Jun 13 09:58:53 EDT 2008
00011 // $Id: FWGUIEventDataAdder.cc,v 1.51 2011/03/17 10:55:41 amraktad Exp $
00012 //
00013 
00014 // system include files
00015 #include <iostream>
00016 #include <sigc++/signal.h>
00017 #include <boost/bind.hpp>
00018 #include <algorithm>
00019 #include <cctype>
00020 #include <string>
00021 
00022 #include "TGFrame.h"
00023 #include "TGTextEntry.h"
00024 #include "TGButton.h"
00025 #include "TGMsgBox.h"
00026 #include "TClass.h"
00027 #include "TFile.h"
00028 #include "TTree.h"
00029 #include "TBranch.h"
00030 
00031 // user include files
00032 #include "Fireworks/Core/src/FWGUIEventDataAdder.h"
00033 #include "Fireworks/Core/interface/FWPhysicsObjectDesc.h"
00034 #include "Fireworks/Core/interface/FWEventItemsManager.h"
00035 #include "Fireworks/Core/interface/FWEventItem.h"
00036 #include "Fireworks/Core/interface/FWItemAccessorFactory.h"
00037 #include "Fireworks/Core/interface/FWJobMetadataManager.h"
00038 #include "Fireworks/TableWidget/interface/FWTableWidget.h"
00039 #include "Fireworks/TableWidget/interface/FWTableManagerBase.h"
00040 #include "Fireworks/TableWidget/interface/FWTextTableCellRenderer.h"
00041 #include "Fireworks/Core/interface/fwLog.h"
00042 #include "Fireworks/Core/src/FWDialogBuilder.h"
00043 //
00044 // constants, enums and typedefs
00045 //
00046 static const std::string& dataForColumn( const FWJobMetadataManager::Data& iData, int iCol)
00047 {
00048    switch (iCol) {
00049       case 0:
00050          return iData.purpose_;
00051          break;
00052       case 4:
00053          return iData.type_;
00054          break;
00055       case 1:
00056          return iData.moduleLabel_;
00057          break;
00058       case 2:
00059          return iData.productInstanceLabel_;
00060          break;
00061       case 3:
00062          return iData.processName_;
00063          break;
00064       default:
00065          break;
00066    }
00067    static const std::string s_blank;
00068    return s_blank;
00069 }
00070 
00071 static const unsigned int kNColumns = 5;
00072 class DataAdderTableManager : public FWTableManagerBase {
00073 public:
00074    DataAdderTableManager(FWJobMetadataManager *manager):
00075       m_manager(manager), m_selectedRow(-1), m_filter() 
00076    {
00077       reset();
00078    }
00079 
00080    virtual int numberOfRows() const {
00081       return m_row_to_index.size();
00082    }
00083    virtual int numberOfColumns() const {
00084       return kNColumns;
00085    }
00086    
00091    virtual void sortWithFilter(const char *filter)
00092    {
00093       m_filter = filter;
00094       sort(-1, sortOrder());
00095       dataChanged();
00096    }
00097    
00098    virtual int unsortedRowNumber(int iSortedRowNumber) const {
00099       return m_row_to_index[iSortedRowNumber];
00100    }
00101 
00102    virtual void implSort(int col, bool sortOrder);
00103    virtual std::vector<std::string> getTitles() const {
00104       std::vector<std::string> returnValue;
00105       returnValue.reserve(kNColumns);
00106       returnValue.push_back("Purpose");
00107       returnValue.push_back("Module Label");
00108       returnValue.push_back("Product Instance Label");
00109       returnValue.push_back("Process Name");
00110       returnValue.push_back("C++ Class");
00111       return returnValue;
00112    }
00113    
00114    virtual FWTableCellRendererBase* cellRenderer(int iSortedRowNumber, int iCol) const
00115    {
00116       
00117       if(static_cast<int>(m_row_to_index.size())>iSortedRowNumber) {
00118          int unsortedRow =  m_row_to_index[iSortedRowNumber];
00119          const FWJobMetadataManager::Data& data = (m_manager->usableData())[unsortedRow];
00120 
00121          m_renderer.setData(dataForColumn(data,iCol),m_selectedRow==unsortedRow);
00122       } else {
00123          m_renderer.setData(std::string(),false);
00124       }
00125       return &m_renderer;
00126    }
00127 
00128    void setSelection (int row, int mask) {
00129       if(mask == 4) {
00130          if( row == m_selectedRow) {
00131             row = -1;
00132          }
00133       }
00134       changeSelection(row);
00135    }
00136 
00137    virtual const std::string title() const {
00138       return "Viewable Collections";
00139    }
00140 
00141    int selectedRow() const {
00142       return m_selectedRow;
00143    }
00144    //virtual void sort (int col, bool reset = false);
00145    virtual bool rowIsSelected(int row) const {
00146       return m_selectedRow == row;
00147    }
00148 
00149    void reset() {
00150       changeSelection(-1);
00151       m_row_to_index.clear();
00152       m_row_to_index.reserve(m_manager->usableData().size());
00153       for(unsigned int i =0; i < m_manager->usableData().size(); ++i) {
00154          m_row_to_index.push_back(i);
00155       }
00156       dataChanged();
00157    }
00158    sigc::signal<void,int> indexSelected_;
00159 private:
00160    void changeSelection(int iRow) {
00161       if(iRow != m_selectedRow) {
00162          m_selectedRow=iRow;
00163          if(-1 == iRow) {
00164             indexSelected_(-1);
00165          } else {
00166             indexSelected_(iRow);
00167          }
00168          visualPropertiesChanged();
00169       }
00170    }
00171    FWJobMetadataManager* m_manager;
00172    std::vector<int>      m_row_to_index;
00173    int                   m_selectedRow;
00174    std::string           m_filter;
00175    mutable FWTextTableCellRenderer m_renderer;
00176 };
00177 
00178 namespace {
00179 void strip(std::string &source, const char *str)
00180    {
00181       std::string remove(str);
00182       while(true)
00183       {
00184          size_t found = source.find(remove);
00185          if (found == std::string::npos)
00186             break;
00187          source.erase(found, remove.size());
00188       }
00189    }
00190 
00208    class SortAndFilter
00209    {
00210    public:
00211       SortAndFilter(const char *filter, int column, bool order, 
00212                     const std::vector<FWJobMetadataManager::Data> &data)
00213          : m_filter(filter),
00214            m_column(column),
00215            m_order(order),
00216            m_data(data)
00217          {
00218             simplify(m_filter);
00219             m_weights.resize(data.size());
00220             
00221             // Calculate whether or not all the entries match the given filter.
00222             // This is done only once, since it's invariant under permutations
00223             // of the data.
00224             for (size_t i = 0, e = m_weights.size(); i != e; ++i)
00225                m_weights[i] = matchesFilter(m_data[i]);
00226          }
00227 
00231       static void simplify(std::string &str)
00232       {
00233          std::transform(str.begin(), str.end(), str.begin(), tolower);
00234          strip(str, "std::");
00235          strip(str, "edm::");
00236          strip(str, "vector<");
00237          strip(str, "clonepolicy");
00238          strip(str, "ownvector");
00239          strip(str, "rangemap<");
00240          strip(str, "strictweakordering<");
00241          strip(str, "sortedcollection<");
00242          strip(str, "reco::");
00243          strip(str, "edmnew::");
00244       }
00245       
00246       unsigned int matches(const std::string &str) const
00247          {
00248             std::string up(str);
00249             simplify(up);
00250             const char *begin = up.c_str();
00251             
00252             // If the filter is empty, we consider anything as matching 
00253             // (i.e. it will not loop).
00254             // If the filter is not empty but the string to be matched is, we 
00255             // consider it as if it was not matching.
00256             if ((!m_filter.empty()) && str.empty())
00257                return 0;
00258             
00259             // There are two level of matching. "Full string" and 
00260             // "All characters". "Full string" matches return an higher weight 
00261             // and therefore should appear on top.
00262             if (strstr(begin, m_filter.c_str()))
00263                return 2;
00264 
00265             return 0;
00266          }
00267       
00273       unsigned int matchesFilter(const FWJobMetadataManager::Data &data) const
00274          {
00275             std::vector<unsigned int> scores;
00276             scores.reserve(10);
00277             scores.push_back(matches(data.purpose_));
00278             scores.push_back(matches(data.type_));
00279             scores.push_back(matches(data.moduleLabel_));
00280             scores.push_back(matches(data.productInstanceLabel_));
00281             scores.push_back(matches(data.processName_));
00282             std::sort(scores.begin(), scores.end());
00283             return scores.back();
00284          }
00285       
00289       bool operator()(const int &aIndex, const int &bIndex)
00290          {
00291             // In case no column is selected, we sort by relevance of the 
00292             // filter.
00293             if (m_column == -1)
00294                return m_weights[aIndex] >= m_weights[bIndex];
00295 
00296             const FWJobMetadataManager::Data &a = m_data[aIndex];
00297             const FWJobMetadataManager::Data &b = m_data[bIndex];
00298 
00299             if (m_order)
00300                return dataForColumn(a, m_column) < dataForColumn(b, m_column);
00301             else
00302                return dataForColumn(a, m_column) > dataForColumn(b, m_column);
00303          }
00304    private:
00305       std::string m_filter;
00306       int         m_column;
00307       bool        m_order;
00308 
00309       const std::vector<FWJobMetadataManager::Data> &m_data;
00310       std::vector<unsigned int>                      m_weights;
00311    };
00312 
00313    void doSort(int column,
00314                const char *filter,
00315                bool descentSort,
00316                const std::vector<FWJobMetadataManager::Data>& iData,
00317                std::vector<int>& oRowToIndex)
00318    {
00319       std::vector<int> ordered;
00320       ordered.reserve(iData.size());
00321       
00322       for (size_t i = 0, e = iData.size(); i != e; ++i)
00323          ordered.push_back(i);
00324       
00325       SortAndFilter sorter(filter, column, descentSort, iData);
00326       // GE: Using std::sort does not work for some reason... Bah...
00327       std::stable_sort(ordered.begin(), ordered.end(), sorter);
00328 
00329       oRowToIndex.clear();
00330       oRowToIndex.reserve(ordered.size());
00331       // Only keep track of the rows that match.
00332       for (size_t i = 0, e = ordered.size(); i != e; ++i)
00333          if (sorter.matchesFilter(iData[ordered[i]]) != 0)
00334             oRowToIndex.push_back(ordered[i]);
00335    }
00336 }
00337 
00338 void
00339 DataAdderTableManager::implSort(int column, bool sortOrder)
00340 {
00341    doSort(column, m_filter.c_str(), sortOrder, m_manager->usableData(), m_row_to_index);
00342 }
00343 
00344 //
00345 // static data member definitions
00346 //
00347 
00348 //
00349 // constructors and destructor
00350 //
00351 
00352 FWGUIEventDataAdder::FWGUIEventDataAdder(
00353    UInt_t iWidth,UInt_t iHeight,
00354    FWEventItemsManager* iManager,
00355    TGFrame* iParent,
00356    FWJobMetadataManager *iMetadataManager) 
00357    :
00358       m_manager(iManager),
00359       m_metadataManager(iMetadataManager),
00360       m_parentFrame(iParent)
00361 {
00362    m_metadataManager->metadataChanged_.connect(boost::bind(&FWGUIEventDataAdder::metadataUpdatedSlot, this));
00363    createWindow();
00364 }
00365 
00366 // FWGUIEventDataAdder::FWGUIEventDataAdder(const FWGUIEventDataAdder& rhs)
00367 // {
00368 //    // do actual copying here;
00369 // }
00370 
00371 FWGUIEventDataAdder::~FWGUIEventDataAdder()
00372 {
00373    /*
00374     // m_frame->Cleanup();
00375     // delete m_frame;
00376     m_frame=0;
00377     // delete m_tableWidget;
00378     m_tableWidget=0;
00379     delete m_tableManager;
00380     m_tableManager=0;
00381     */
00382 }
00383 
00384 //
00385 // assignment operators
00386 //
00387 // const FWGUIEventDataAdder& FWGUIEventDataAdder::operator=(const FWGUIEventDataAdder& rhs)
00388 // {
00389 //   //An exception safe implementation is
00390 //   FWGUIEventDataAdder temp(rhs);
00391 //   swap(rhs);
00392 //
00393 //   return *this;
00394 // }
00395 
00396 //
00397 // member functions
00398 //
00399 void
00400 FWGUIEventDataAdder::addNewItem()
00401 {
00402    TClass* theClass = TClass::GetClass(m_type.c_str());
00403    if(0==theClass) {
00404       return;
00405    }
00406    const std::string moduleLabel = m_moduleLabel;
00407    if(moduleLabel.empty()) {
00408       return;
00409    }
00410 
00411    const std::string name = m_name->GetText();
00412    if(name.empty()) {
00413       return;
00414    }
00415 
00416    if ( m_manager->find( name ) ) {
00417       TString msg("Event item '");
00418       msg += name;
00419       msg += "' is already registered. Please use another name.";
00420       fwLog(fwlog::kWarning) << msg.Data() << std::endl;
00421       new TGMsgBox(gClient->GetDefaultRoot(), m_frame,
00422                    "Error - Name conflict", msg, kMBIconExclamation, kMBOk);
00423       return;
00424    }
00425 
00426    int largest = -1;
00427    if(m_manager->begin() != m_manager->end()) {
00428       if ( *(m_manager->begin()) )
00429          largest = (*(m_manager->begin()))->layer();
00430    }
00431    for(FWEventItemsManager::const_iterator it = m_manager->begin(),
00432                                            itEnd = m_manager->end();
00433        it!=itEnd;
00434        ++it) {
00435       if((*it) && largest < (*it)->layer()) {
00436          largest = (*it)->layer();
00437       }
00438    }
00439    ++largest;
00440    std::string processName = m_processName;
00441    if(m_doNotUseProcessName->IsOn() && m_doNotUseProcessName->IsEnabled()) {
00442       processName="";
00443    }
00444    FWPhysicsObjectDesc desc(name, theClass, m_purpose,
00445                             FWDisplayProperties::defaultProperties,
00446                             moduleLabel,
00447                             m_productInstanceLabel,
00448                             processName,
00449                             "",
00450                             largest);
00451    m_manager->add(desc);
00452 }
00453 
00454 void
00455 FWGUIEventDataAdder::addNewItemAndClose()
00456 {
00457    addNewItem();
00458    windowIsClosing();
00459 }
00460 
00461 void
00462 FWGUIEventDataAdder::show()
00463 {
00464    // Map main frame
00465    if(0==m_frame) {
00466       createWindow();
00467    }
00468    m_frame->MapWindow();
00469 }
00470 
00471 void
00472 FWGUIEventDataAdder::windowIsClosing()
00473 {
00474    m_name->SetText("");
00475    m_search->SetText("");
00476    m_purpose.clear();
00477    m_type.clear();
00478    m_moduleLabel.clear();
00479    m_processName.clear();
00480    m_productInstanceLabel.clear();
00481    m_apply->SetEnabled(false);
00482    m_applyAndClose->SetEnabled(false);
00483    
00484    m_frame->UnmapWindow();
00485    m_frame->DontCallClose();
00486 }
00487 
00488 void
00489 FWGUIEventDataAdder::updateFilterString(const char *str)
00490 {
00491    m_tableManager->sortWithFilter(str);
00492    m_tableManager->dataChanged();
00493 }
00494 
00495 void
00496 FWGUIEventDataAdder::createWindow()
00497 {
00498    m_tableManager = new DataAdderTableManager(m_metadataManager);
00499    m_tableManager->indexSelected_.connect(boost::bind(&FWGUIEventDataAdder::newIndexSelected,this,_1));
00500 
00501    m_frame = new TGTransientFrame(gClient->GetDefaultRoot(),m_parentFrame,600,400);
00502    m_frame->Connect("CloseWindow()","FWGUIEventDataAdder",this,"windowIsClosing()");
00503 
00504    FWDialogBuilder builder(m_frame);
00505    TGTextButton *cancelButton, *resetButton;
00506    
00507    builder.indent(10)
00508           .spaceDown(15)
00509           .addLabel("Search:", 0).expand(false).spaceUp(4).floatLeft(4)
00510           .addTextEntry("", &m_search).spaceUp(0)
00511           .frameSpaceDown(10)
00512           .addLabel("Viewable Collections", 8)
00513           .frameSpaceDown(5)
00514           .addTable(m_tableManager, &m_tableWidget).expand(true, true)
00515           .addLabel("Name:", 0).expand(false).spaceUp(4).floatLeft(4)
00516           .addTextEntry("", &m_name).spaceUp(0).floatLeft(4)
00517           .addTextButton(" Reset  ", &resetButton).expand(false, false)
00518           .frameSpaceUpDown(5)
00519           .addCheckbox("Do not use Process Name and "
00520                        "instead only get this data "
00521                        "from the most recent Process",
00522                        &m_doNotUseProcessName)
00523           .frameSpaceDown(15)
00524           .hSpacer().floatLeft(0)
00525           .addTextButton(" Close  ", &cancelButton).expand(false).floatLeft(4)
00526           .addTextButton(" Add Data  ", &m_apply).expand(false).floatLeft(4)
00527           .addTextButton(" Add Data && Close  ", &m_applyAndClose).expand(false)
00528                                 .spaceRight(25).spaceDown(15);
00529 
00530    m_search->Connect("TextChanged(const char *)", "FWGUIEventDataAdder", 
00531                      this, "updateFilterString(const char *)");
00532    m_search->SetEnabled(true);
00533    m_tableWidget->SetBackgroundColor(0xffffff);
00534    m_tableWidget->SetLineSeparatorColor(0x000000);
00535    m_tableWidget->SetHeaderBackgroundColor(0xececec);
00536    m_tableWidget->Connect("rowClicked(Int_t,Int_t,Int_t,Int_t,Int_t)",
00537                           "FWGUIEventDataAdder",this,
00538                           "rowClicked(Int_t,Int_t,Int_t,Int_t,Int_t)");
00539 
00540    m_tableWidget->disableGrowInWidth();
00541    m_name->SetState(true);
00542    resetButton->SetEnabled(true);
00543    resetButton->Connect("Clicked()", "FWGUIEventDataAdder", this, "resetNameEntry()");
00544    m_doNotUseProcessName->SetState(kButtonDown);
00545    cancelButton->Connect("Clicked()","FWGUIEventDataAdder", this, "windowIsClosing()");
00546    cancelButton->SetEnabled(true);
00547    m_apply->Connect("Clicked()", "FWGUIEventDataAdder", this, "addNewItem()");
00548    m_applyAndClose->Connect("Clicked()", "FWGUIEventDataAdder", this, "addNewItemAndClose()");
00549    
00550    m_frame->SetWindowName("Add Collection");
00551    m_frame->MapSubwindows();
00552    m_frame->Layout();
00553 }
00554 
00559 void
00560 FWGUIEventDataAdder::metadataUpdatedSlot(void)
00561 {
00562    m_tableManager->reset();
00563    m_tableManager->sort(0, true);
00564 }
00565 
00566 void
00567 FWGUIEventDataAdder::resetNameEntry()
00568 {
00569    m_name->SetText(m_apply->IsEnabled() ? m_moduleLabel.c_str() : "", kFALSE);
00570 }
00571 
00572 void
00573 FWGUIEventDataAdder::newIndexSelected(int iSelectedIndex)
00574 {
00575    if(-1 != iSelectedIndex) {
00576       std::vector<FWJobMetadataManager::Data> &metadata = m_metadataManager->usableData();
00577       m_purpose = metadata[iSelectedIndex].purpose_;
00578       m_type = metadata[iSelectedIndex].type_;
00579       std::string oldModuleLabel = m_moduleLabel;
00580       m_moduleLabel = metadata[iSelectedIndex].moduleLabel_;
00581       m_productInstanceLabel = metadata[iSelectedIndex].productInstanceLabel_;
00582       m_processName = metadata[iSelectedIndex].processName_;
00583       
00584       if(strlen(m_name->GetText())==0 || oldModuleLabel == m_name->GetText()) {
00585          m_name->SetText(m_moduleLabel.c_str());
00586       }
00587       m_apply->SetEnabled(true);
00588       m_applyAndClose->SetEnabled(true);
00589 
00590       //Check to see if this is the last process, if it is then we can let the user decide
00591       // to not use the process name when doing the lookup.  This makes a saved configuration
00592       // more robust.  However, if they choose a collection not from the last process then we need the
00593       // process name in order to correctly get the data they want
00594       bool isMostRecentProcess =true;
00595       int index = 0;
00596       for(std::vector<FWJobMetadataManager::Data>::iterator it = metadata.begin(), itEnd = metadata.end();
00597           it != itEnd && isMostRecentProcess;
00598           ++it,++index) {
00599          if(index == iSelectedIndex) {continue;}
00600          if(it->moduleLabel_ == m_moduleLabel &&
00601             it->purpose_ == m_purpose &&
00602             it->type_ == m_type &&
00603             it->productInstanceLabel_ == m_productInstanceLabel) {
00604             //see if this process is newer than the data requested
00605             
00606             for(size_t pni = 0, pne = m_metadataManager->processNamesInJob().size();
00607                 pni != pne; ++pni) 
00608             {
00609                const std::string &processName = m_metadataManager->processNamesInJob()[pni];
00610                if (m_processName == processName)
00611                   break;
00612 
00613                if(it->processName_ == processName) 
00614                {
00615                   isMostRecentProcess = false;
00616                   break;
00617                }
00618             }
00619          }
00620       }
00621       if(isMostRecentProcess) {
00622          if(!m_doNotUseProcessName->IsEnabled()) {
00623             m_doNotUseProcessName->SetEnabled(true);
00624          }
00625       } else {
00626          //NOTE: must remember state before we get here because 'enable' and 'on' are mutually
00627          // exlcusive :(
00628          m_doNotUseProcessName->SetEnabled(false);
00629       }
00630    }
00631 }
00632 
00633 void 
00634 FWGUIEventDataAdder::rowClicked(Int_t iRow,Int_t iButton,Int_t iKeyMod,Int_t,Int_t)
00635 {
00636    if(iButton==kButton1) {
00637       m_tableManager->setSelection(iRow,iKeyMod);
00638    }
00639 }
00640 
00641 //
00642 // const member functions
00643 //
00644 
00645 //
00646 // static member functions
00647 //