00001 #include "runinfo.hh"
00002 #include "TGClient.h"
00003 #include "TApplication.h"
00004 #include "TGFrame.h"
00005 #include "TGCanvas.h"
00006 #include "TGTextEntry.h"
00007 #include "TGDockableFrame.h"
00008 #include "TGButton.h"
00009 #include "TGButtonGroup.h"
00010 #include "TQObject.h"
00011 #include "TGToolTip.h"
00012 #include "TGLabel.h"
00013 #include "TGComboBox.h"
00014 #include "TGMsgBox.h"
00015 #include "TMacro.h"
00016 #include "TList.h"
00017 #include "TObjString.h"
00018
00019 typedef runinfo::stringmap stringmap;
00020 typedef runinfo::stringvec stringvec;
00021 typedef runinfo::DialogField DialogField;
00022 typedef runinfo::FieldList FieldList;
00023
00024
00025 class CommentReader{
00026 runinfo* _info;
00027 public:
00028 CommentReader(runinfo* info) : _info(info) {}
00029 std::istream& operator()(std::istream& in)
00030 { phrase dummy;
00031 if(in>>dummy) _info->SetMetadata("comment",dummy);
00032 return in;
00033 }
00034 };
00035
00036 runinfo::runinfo(long id) :
00037 ParameterList("runinfo","metadata about daq runs")
00038 {
00039 Init();
00040 runid = id;
00041 }
00042
00043
00044 void runinfo::ResetRunStats()
00045 {
00046 starttime = 0;
00047 endtime = 0;
00048 triggers = 0;
00049 events = 0;
00050 }
00051
00052 void runinfo::Init(bool reset)
00053 {
00054 runid=-1;
00055 starttime=0;
00056 endtime=0;
00057 triggers=0;
00058 events=0;
00059
00060 metadata.clear();
00061 prerun_dialog_fields.clear();
00062 postrun_dialog_fields.clear();
00063 force_prerun_dialog = false;
00064 force_postrun_dialog = false;
00065 channel_metadata.clear();
00066
00067 if(!reset)
00068 InitializeParameterList();
00069 }
00070
00071 void runinfo::InitializeParameterList()
00072 {
00073 RegisterParameter("runid", runid, "unique ID number for the run");
00074 RegisterParameter("starttime",starttime,"Timestamp at start of run");
00075 RegisterParameter("endtime",endtime, "Timestamp at end of run");
00076 RegisterParameter("triggers",triggers,"Total triggers requested during run");
00077 RegisterParameter("events", events, "Number of events recorded during run");
00078
00079 RegisterParameter("metadata", metadata,
00080 "User-defined per run info categories");
00081 RegisterParameter("prerun_dialog_fields", prerun_dialog_fields,
00082 "List of fields to query user for at start of run");
00083 RegisterParameter("postrun_dialog_fields", postrun_dialog_fields,
00084 "List of fields to query user for at end of run");
00085 RegisterParameter("force_prerun_dialog", force_prerun_dialog,
00086 "Show prerun dialog even if all required fields valid");
00087 RegisterParameter("force_postrun_dialog", force_postrun_dialog,
00088 "Show postrun dialog even if all required fields valid");
00089
00090 RegisterParameter("channel_metadata", channel_metadata,
00091 "map of channel ID to per-channel metadata");
00092
00093 RegisterReadFunction("comment",CommentReader(this),
00094 "Handle obsolete separate comment parameter (now in metadata)");
00095 }
00096
00097
00098 int runinfo::LoadSavedInfo(TMacro* mac)
00099 {
00100
00101 TList* lines = mac->GetListOfLines();
00102 if(!lines || !lines->GetEntries())
00103 return 1;
00104 std::stringstream s;
00105 TIter next(lines);
00106 TObjString *obj;
00107 while ((obj = (TObjString*) next()))
00108 s<<obj->GetName()<<"\n";
00109
00110 try{
00111 ReadFromByKey(s, GetDefaultKey());
00112 }
00113 catch(std::exception& e){
00114
00115 return 2;
00116 }
00117
00118 return 0;
00119 }
00120
00122
00123 bool AreAllFieldsValid(FieldList* fields, stringmap* metadata)
00124 {
00125
00126 bool allvalid = true;
00127 FieldList::iterator field;
00128 for(field = fields->begin(); field != fields->end(); ++field){
00129 if( !field->IsValueValid( (*metadata)[field->fieldname] ) ){
00130 allvalid = false;
00131 break;
00132 }
00133 }
00134 return allvalid;
00135 }
00136
00137 DialogField::DialogField(const std::string& field,
00138 const std::string& desc,
00139 bool required_,
00140 const std::string& default_) :
00141 ParameterList(field,"Specify a metadata field to query the user for"),
00142 fieldname(field), description(desc), required(required_),
00143 defaultvalue(default_)
00144 {
00145 RegisterParameter("fieldname", fieldname);
00146 RegisterParameter("description", description);
00147 RegisterParameter("allowed_values", allowed_values);
00148 RegisterParameter("required",required);
00149 RegisterParameter("defaultvalue",defaultvalue);
00150 }
00151
00152
00153 bool DialogField::IsValueValid(const std::string& val) const
00154 {
00155 if(!allowed_values.empty() &&
00156 std::find(allowed_values.begin(), allowed_values.end(), val) ==
00157 allowed_values.end() )
00158 return false;
00159 if(required)
00160 return val != "";
00161 return true;
00162 }
00163
00164 class DialogFieldFrame : public TGVerticalFrame{
00165 public:
00166 DialogFieldFrame(const DialogField* field, stringmap* metadata,
00167 const TGWindow* p=0);
00168
00169 virtual ~DialogFieldFrame(){}
00170
00171 TGTextEntry* GetTextEntry() const { return _textentry; }
00172
00173 virtual Bool_t Notify();
00174 private:
00175 const DialogField* _field;
00176 stringmap* _metadata;
00177 TGTextEntry* _textentry;
00178 TGComboBox* _combobox;
00179 };
00180
00181 DialogFieldFrame::DialogFieldFrame(const DialogField* field, stringmap* metadata,
00182 const TGWindow* p) :
00183 TGVerticalFrame(p), _field(field), _metadata(metadata),
00184 _textentry(0), _combobox(0)
00185 {
00186 std::string defaultvalue = field->defaultvalue;
00187 if((*metadata)[field->fieldname] != "")
00188 defaultvalue = (*metadata)[field->fieldname];
00189
00190 TGHorizontalFrame* hframe = new TGHorizontalFrame(this);
00191 AddFrame(hframe, new TGLayoutHints(kLHintsExpandX|kLHintsTop,0,0,5));
00192 std::string label = " ";
00193 if(field->required)
00194 label = "* ";
00195 label += field->fieldname;
00196 hframe->AddFrame(new TGLabel(hframe, label.c_str()), new TGLayoutHints(kLHintsLeft));
00197 if(field->description != ""){
00198 std::string desc = "( ";
00199 desc += field->description + " )";
00200 hframe->AddFrame(new TGLabel(hframe, desc.c_str()), new TGLayoutHints(kLHintsRight));
00201 }
00202
00203 if(field->allowed_values.empty()){
00204 _textentry = new TGTextEntry(this, defaultvalue.c_str());
00205 AddFrame(_textentry, new TGLayoutHints(kLHintsExpandX, 10));
00206 _textentry->Connect("TextChanged(const char*)","TGFrame",this,"Notify()");
00207 }
00208 else{
00209 _combobox = new TGComboBox(this);
00210 stringvec::const_iterator opt;
00211 int id=-1;
00212 for(opt = field->allowed_values.begin(); opt != field->allowed_values.end(); ++opt){
00213 _combobox->AddEntry(opt->c_str(), ++id);
00214 if(*opt == defaultvalue)
00215 _combobox->Select(id,false);
00216 }
00217 _combobox->SetHeight(20);
00218 AddFrame(_combobox, new TGLayoutHints(kLHintsExpandX,10));
00219 _combobox->Connect("Selected(const char*)","TGFrame",this,"Notify()");
00220 }
00221
00222 Notify();
00223 }
00224
00225 Bool_t DialogFieldFrame::Notify()
00226 {
00227 std::string newval="";
00228 if(_textentry)
00229 newval = _textentry->GetText();
00230 else if(_combobox){
00231 TGTextLBEntry* e = (TGTextLBEntry*)(_combobox->GetSelectedEntry());
00232 if(e)
00233 newval = e->GetTitle();
00234 }
00235 (*_metadata)[_field->fieldname] = newval;
00236 int color = kYellow-9;
00237 if( _field->IsValueValid(newval) )
00238 color = kWhite;
00239 Pixel_t pixel = gVirtualX->GetPixel(color);
00240 if(_textentry)
00241 _textentry->SetBackgroundColor(pixel);
00242 else if(_combobox){
00243 _combobox->SetBackgroundColor(pixel);
00244 _combobox->SetEnabled(true);
00245 }
00246
00247 return false;
00248 }
00249
00250 class RunInfoFillHelper : public TGTransientFrame{
00251 public:
00252 static int MetadataDialog(stringmap* metadata, FieldList* fields);
00253 private:
00254 static int _returnval;
00255 RunInfoFillHelper(stringmap* metadata, FieldList* fields);
00256 virtual ~RunInfoFillHelper();
00257 public:
00259 virtual Bool_t ProcessMessage(Long_t b, Long_t, Long_t);
00260 private:
00261 stringmap* _metadata;
00262 FieldList* _fields;
00263 TGCanvas* can;
00264 TGCompositeFrame* mf2;
00265 };
00266
00267 RunInfoFillHelper::~RunInfoFillHelper()
00268 {
00269 }
00270
00271 int RunInfoFillHelper::_returnval=1;
00272 int RunInfoFillHelper::MetadataDialog(stringmap* metadata, FieldList* fields)
00273 {
00274 if(!gApplication)
00275 new TApplication("_app",0,0);
00276 gApplication->NeedGraphicsLibs();
00277 gApplication->InitializeGraphics();
00278 new RunInfoFillHelper(metadata, fields);
00279 return _returnval;
00280 }
00281
00282 Bool_t RunInfoFillHelper::ProcessMessage(Long_t b, Long_t, Long_t)
00283 {
00284 if(b==1){
00285
00286 bool allvalid = true;
00287 for(FieldList::iterator field = _fields->begin(); field != _fields->end(); ++field){
00288 if( !field->IsValueValid( (*_metadata)[field->fieldname] ) ){
00289 allvalid = false;
00290 break;
00291 }
00292 }
00293 if(!allvalid){
00294 new TGMsgBox(gClient->GetRoot(), this, "Invalid Fields","One or more required fields (marked yellow) do not have values assigned. Please enter valid values in these fields and submit again.");
00295 return false;
00296 }
00297 else
00298 _returnval = 0;
00299 }
00300 else if(b==2){
00301 _returnval = 2;
00302 }
00303 CloseWindow();
00304 return false;
00305 }
00306
00307
00308 RunInfoFillHelper::RunInfoFillHelper(stringmap* metadata, FieldList* fields) :
00309 TGTransientFrame(gClient->GetRoot()),
00310 _metadata(metadata), _fields(fields)
00311 {
00312 SetWindowName("Please fill out run information");
00313
00314 TGCanvas* can = new TGCanvas(this,10, 10, kChildFrame);
00315 AddFrame(can, new TGLayoutHints(kLHintsExpandX|kLHintsExpandY,0,0,10));
00316 TGCompositeFrame* mf2 = new TGVerticalFrame(can->GetViewPort(),10,10);
00317 can->SetContainer(mf2);
00318
00319
00320 TGButtonGroup* bg = new TGButtonGroup(this,"",kChildFrame|kHorizontalFrame|kFixedSize);
00321 bg->Resize(300,70);
00322 AddFrame(bg,new TGLayoutHints(kLHintsBottom|kLHintsCenterX));
00323 TGTextButton* ok = new TGTextButton(bg,"OK");
00324 new TGTextButton(bg,"Cancel");
00325 bg->SetLayoutHints(new TGLayoutHints(kLHintsExpandX|kLHintsExpandY,10,10,3,3));
00326 bg->Connect("Clicked(Int_t)","TGCompositeFrame",this,
00327 "ProcessMessage(Long_t,Long_t,Long_t)");
00328
00329 TGTextEntry* first = 0, *last = 0;
00330
00331 for(FieldList::const_iterator field = _fields->begin();
00332 field != _fields->end(); ++field){
00333 DialogFieldFrame* frame = new DialogFieldFrame(&(*field), metadata, mf2);
00334 mf2->AddFrame(frame, new TGLayoutHints(kLHintsExpandX,10,10,5,5));
00335 TGTextEntry* te = frame->GetTextEntry();
00336 if(te){
00337
00338 te->Connect("ReturnPressed()","TGButton",ok,"Clicked()");
00339
00340 if(!first) first = te;
00341
00342 if(last){
00343 last->Connect("TabPressed()","TGTextEntry",te,"SetFocus()");
00344 last->Connect("TabPressed()","TGTextEntry",te,"SelectAll()");
00345 te->Connect("ShiftTabPressed()","TGTextEntry",last,"SetFocus()");
00346 te->Connect("ShiftTabPressed()","TGTextEntry",last,"SelectAll()");
00347 }
00348 last = te;
00349 }
00350 }
00351
00352
00353 if(first && last && first != last){
00354 first->SetFocus();
00355 first->Connect("ShiftTabPressed()","TGTextEntry",last,"SetFocus()");
00356 first->Connect("ShiftTabPressed()","TGTextEntry",last,"SelectAll()");
00357 last->Connect("TabPressed()","TGTextEntry",first,"SetFocus()");
00358 last->Connect("TabPressed()","TGTextEntry",first,"SelectAll()");
00359 }
00360
00361
00362 SetCleanup(kDeepCleanup);
00363 can->GetViewPort()->SetCleanup(kDeepCleanup);
00364
00365 MapSubwindows();
00366 Resize(500,500);
00367 CenterOnParent();
00368 MapWindow();
00369 gClient->WaitFor(this);
00370 }
00371
00372
00373
00374
00375
00376
00377
00379
00380 int runinfo::FillDataForRun(runinfo::FILLTIME when)
00381 {
00382 FieldList* fields = (when == RUNSTART ? &prerun_dialog_fields :
00383 &postrun_dialog_fields );
00384 bool forcedialog = (when == RUNSTART ? force_prerun_dialog :
00385 force_postrun_dialog );
00386 if(fields && !fields->empty() &&
00387 (forcedialog || !AreAllFieldsValid(fields, &metadata)) )
00388 return RunInfoFillHelper::MetadataDialog(&metadata, fields);
00389 return 0;
00390 }