scripttableviewer.cxx

Go to the documentation of this file.
00001 //
00002 // Copyright 2010, Lowell Boggs Jr.
00003 //
00004 // This file or directory, containing source code for a computer program,
00005 // is Copyrighted by Lowell Boggs, Jr.  987 Regency Drive, Lewisville
00006 // TX (USA), 75067.  You may use, copy, modify, and distribute this
00007 // source file without charge or obligation so long as you agree to
00008 // the following:
00009 //
00010 //  1.  You must indemnify Lowell Boggs against any and all financial
00011 //      obligations caused by its use, misuse, function, or malfunction.
00012 //      Further, you acknowledge that there is no warranty of any kind,
00013 //      whatsoever.
00014 //
00015 //  2.  You agree not to attempt to patent any portion of this original
00016 //      work -- though you may attempt to patent your own extensions to
00017 //      it if you so choose.
00018 //
00019 //  3.  You keep this copyright notice with the file and all copies
00020 //      of the file and do not change it anyway except language translation.
00021 //
00022 // You are responsible for enforcing your own compliance with these
00023 // conditions and may not use this source file if you cannot agree to the
00024 // above terms and conditions.
00025 //
00026 // Warning:  not all files in this directory structure are covered by the
00027 // same copyright.  Some of them are part of the GNU source distribution
00028 // and you must obey the GPL copyright for those files.
00029 
00030 #include <cxxtls/scripttableviewer.h>
00031 #include <ctype.h>
00032 #include <cxxtls/viewermanager.h>
00033 #include <algorithm>
00034 #include <iostream>
00035 #include <fstream>
00036 #include <cxxtls/strtool.h>
00037 #include <cxxtls/file.h>
00038 #include <portable_io.h>
00039 #include <ctype.h>
00040 #include <cxxtls/fmtd.h>
00041 
00042 using namespace std;
00043 
00044 namespace cxxtls
00045 {
00046 
00047 
00050 #ifdef _MSC_VER
00051     char const *discardErrors = " 2>nul:";
00052 #else
00053     char const *discardErrors = " 2>/dev/null";
00054 #endif
00055 
00056 
00059 static void appendParm(string &output, string const &input, bool atEnd=true);
00060 
00061 
00064 ScriptTableViewer::~ScriptTableViewer()
00065 {
00066 }
00069 ScriptTableViewer::ScriptTableViewer(ViewerManager *vm, string const &scriptName, std::string directory)
00070 : TableEditor(vm, '`')
00071 , scriptname_(scriptName)
00072 , keyKludge_(0)
00073 , title_(application_name())
00074 , directory_(directory)
00075 {
00076     sessions_.push_back(SessionInfo());  // start cursor position plus options
00077     saveScreenLayout();                  // save the empty layout to be consistent
00078                                          // about pushing/popping the session info
00079 
00080     invocationKeys_.push_back(0x0a);  // ^J, \n:  the enter key triggers invocations of the
00081                                       // script using the current cell and row as parameters to it.
00082                                       // The script can add more items to the list by printing
00083                                       // =%==%--CMDKEYS=qQxX....
00084                                       // where 'q', 'Q', 'x', and 'X' are command keys that
00085                                       // the script accepts.  The script does not need to supply
00086                                       // the enter key, but if it did, it would use ^J to represent
00087                                       // the enter key, ^I for the tab key, etc.
00088                                       // Use ^^ to represent the ^ key.
00089 
00090     populateTable("");  // empty script session and contents is the highest level "state" of the script
00091                         // invocation tree
00092 }
00093 
00096 
00097 void ScriptTableViewer::handleReturnedCells()
00098 {
00099 
00100    SessionInfo &caller = sessions_[ sessions_.size() -2 ];
00101    SessionInfo &popup  = sessions_.back();
00102 
00103    for(size_t i = 0; i < popup.returnedCells_.size(); ++i)
00104    {
00105       size_t row = popup.returnedCells_[i].first;
00106       size_t col = popup.returnedCells_[i].second;
00107 
00108       if(row < rows() && col < cols() )
00109       {
00110          char buffer[80];
00111          
00112          // row and col are zero based but users expect 1 based
00113 
00114 
00115          sprintf(buffer, "--CELL_VALUE_%d_%d", int(row+1), int(col+1));
00116 
00117          CellInfo const *cell = cellInfo(row,col);
00118 
00119          caller.commandLine_ = string(buffer) + 
00120                                "=" + 
00121                                "\"" + cell->text_[0] + "\" " + 
00122                                caller.commandLine_;
00123 
00124                  
00125       }
00126 
00127    }
00128 }
00129 
00132 
00133 bool ScriptTableViewer::handle_event( CursorWindow::input_event const * e,
00134                                 CursorWindow::viewport          * vp
00135                               )
00136 {
00137     if(    e->type_ == CursorWindow::input_event::DataKey
00138        ||  e->type_ == CursorWindow::input_event::FunctionKey 
00139       )
00140     {
00141         // first, check to see if this is part 2 of a two part
00142         // command key sequence.  Part 1 is always ^X,
00143 
00144         if(keyKludge_)
00145         {
00146             keyKludge_ = false;
00147 
00148             switch(e->value_)
00149             {
00150                 case 0x03: // ^X^C quit editing
00151                    return true;
00152 
00153                 case 0x0b: // ^X^K quit editing
00154 
00155                     if(sessions_.size() > 1)
00156                     {
00157                        handleReturnedCells();
00158 
00159                        sessions_.pop_back();
00160                        restoreSavedScreenLayout();
00161                        restartSession(vp);
00162                     }
00163                     else
00164                        return true;  // when out of sessions, quit
00165 
00166                 case 0x17: // ^X^W  
00167                     snatchEdit(vp, directory_);
00168                     return false;    
00169                 
00170 
00171                 default: vp->beep(); break;
00172             }
00173 
00174             return false;
00175         }
00176 
00177         // ok, this is not part two a two part key sequence
00178 
00179 
00180         switch(e->value_)
00181         {
00182            case 0x18:  // ^X
00183            {
00184               keyKludge_ = true;
00185            }
00186            return false;
00187 
00188 
00189            case 0x10: // ^P
00190            {
00191                pageRight(vp);
00192            }
00193            return false;
00194 
00195            case 0x11: // ^Q
00196            {
00197                pageLeft(vp);
00198            }
00199            return false;
00200 
00201            case 0x09: // TAB
00202            {
00203                moveRight(vp);
00204            }
00205            return false;
00206 
00207            case CursorWindow::key_btab: // shift tab
00208            {
00209                moveLeft(vp);
00210            }
00211            return false;
00212 
00213 
00214            case 'q':
00215            case 'Q':
00216            {
00217                // if we are in an editable
00218 
00219                CursorInfo cursor = cursorInfo();
00220 
00221                if(   rows_.size() > cursor.row_ 
00222                   && cols_.size() > cursor.col_
00223                  )
00224                {
00225                   if(fieldEditable(cursor))
00226                   {
00227                      break; // current field is editable, so don't pop out
00228                             // of the current page -- rather insert the q
00229                             // into field text by dropping out the
00230                             // switch statement.
00231                   }
00232                }
00233 
00234 
00235                // if we get here, the field is not editable, so tree
00236                // q like a command (like ^X^K, to be precise)
00237 
00238                if(sessions_.size() > 1)
00239                {
00240                   handleReturnedCells();
00241 
00242                   sessions_.pop_back();
00243                   restoreSavedScreenLayout();
00244                   restartSession(vp);
00245                }
00246                else
00247                   return true;  // when out of sessions, quit
00248 
00249                return false;
00250 
00251            }
00252            break;
00253 
00254            case 0x1b:
00255            {
00256                if(sessions_.size() > 1)
00257                {
00258                   handleReturnedCells();
00259                   sessions_.pop_back();
00260                   restoreSavedScreenLayout();
00261                   restartSession(vp);
00262                }
00263                else
00264                   return true;  // when out of sessions, quit
00265            }
00266            return false;
00267 
00268            case 0x0d: // \r carriage return
00269            case 0x0a: // \a newline  enter
00270            {
00271 
00272                CursorInfo cursor = cursorInfo();
00273 
00274                if( fieldExecutable(cursor) )
00275                {
00276                      // only editable fields are executable...
00277 
00278                      sessions_.back().startCursorPosition_ = cursor;
00279      
00280                      sessions_.push_back( sessions_.back() ); // duplicate back session
00281                      saveScreenLayout();
00282      
00283                      invokeCommand(vp, 0x0a);
00284      
00285                }
00286                else
00287                {
00288                   vp->beep();
00289                }
00290 
00291 
00292            }
00293            return false;
00294 
00295 
00296            default:
00297            {
00298                CursorInfo cursor = cursorInfo();
00299 
00300                if( !fieldEditable(cursor) && fieldExecutable(cursor) )
00301                {
00302 
00303 
00304 
00305                    if( find(invocationKeys_.begin(), invocationKeys_.end(), e->value_) != invocationKeys_.end())
00306                    {
00307                        sessions_.back().startCursorPosition_ = cursorInfo();
00308     
00309                        sessions_.push_back( sessions_.back() ); // duplicate back session
00310                        saveScreenLayout();
00311     
00312                        invokeCommand(vp, e->value_);
00313 
00314                        return false; // don't send the key to the table editor
00315     
00316                    }
00317     
00318                }
00319 
00320                break;
00321            }
00322 
00323         }
00324     }
00325 
00326    // by default, act like a table viewer -- which has different arrow key behavior
00327    // than is inforced here
00328 
00329    bool quitNow = false;
00330    
00331    quitNow = TableEditor::handle_event(e,vp);  // perform edit, but ignore quit logic
00332 
00333    quitNow = quitNow; // suppress compiler warning for unused variables.
00334 
00335    if(e->type_ == CursorWindow::input_event::ForceExitKey)
00336      return true; // don't ignore forced exits!
00337 
00338    return false;  // don't quit
00339 }
00340 
00341 
00344 std::string const &ScriptTableViewer::application_name() const
00345 {
00346    static string app_name("TableCommander");
00347 
00348    return app_name;
00349 }
00352 std::string ScriptTableViewer::description() const
00353 {
00354    return "Script Results Viewer";
00355 }
00356 
00359 Viewer* ScriptTableViewer::app(ViewerManager*vm, std::string &fullname)
00360 {
00361   if(fullname.size() == 0)
00362   {
00363     CursorWindow::Dialog d("full script pathname");
00364 
00365     d += new CursorWindow::Dialog::String("name",
00366                                           "path",
00367                                           "*",
00368                                           40
00369                                          );
00370                                 
00371     if(d.popup(vm->window()))
00372       return 0;
00373 
00374     fullname = d.element_value("name");
00375 
00376     if(fullname == "")
00377       return 0;
00378 
00379 
00380     FileName tmp(fullname);
00381     tmp.convert_to_absolute_path();
00382 
00383     fullname = tmp;
00384 
00385   }
00386 
00387   int delimiter=',';
00388 
00389   size_t dotPos = fullname.find_last_of('.');
00390 
00391   if(dotPos < fullname.size())
00392   {
00393     ++dotPos;  // get to 't' or 'c'
00394 
00395     if( dotPos < fullname.size())
00396     {
00397         if(fullname[dotPos] == 't' || fullname[dotPos] == 'T')
00398            delimiter=0x09; // tab  
00399     }
00400   }
00401 
00402   return new ScriptTableViewer(vm,fullname);
00403 }
00404 
00407 void
00408 ScriptTableViewer::
00409 help()
00410 {
00411 
00412   std::auto_ptr< std::list< std::string > >
00413   viewer_help( new std::list< std::string > );
00414 
00415   viewer_help->push_back(string("Help for script:  ") + scriptname_);
00416   viewer_help->push_back("");
00417 
00418   string command = scriptname_ + " --HELP=1";
00419 
00420   if(!sessions_.empty())
00421   {
00422      std::map<std::string,std::string>::iterator state = sessions_.back().options_.find("STATE");
00423 
00424      if(state != sessions_.back().options_.end())
00425      {
00426        command += " --STATE=";
00427        command += state->second;
00428      }
00429   }
00430 
00431   
00432 
00433 
00434   FILE *scriptOutput = popen(command.c_str(), "r");
00435 
00436   bool helpHandledByScript=false;
00437 
00438   if(scriptOutput)
00439   {
00440       char buffer[2048];
00441 
00442       buffer[0] = 0;
00443 
00444       while(fgets(buffer, 2048, scriptOutput))
00445       {
00446         if( 0 == memcmp(buffer, "help:", 5) )
00447         {
00448             char *eol = strchr(buffer, '\n');
00449 
00450             if(eol)
00451             {
00452               *eol = 0;  // remove the trailing \n.
00453             }
00454 
00455             helpHandledByScript=true;
00456 
00457             string tabExpandedText;
00458 
00459             tabExpandedText = StrTool::expand_tabs(buffer+5);
00460 
00461             viewer_help->push_back(tabExpandedText);
00462 
00463             buffer[0] = 0;
00464         }
00465         else
00466             break;
00467 
00468 
00469       }
00470 
00471       pclose(scriptOutput);
00472 
00473       viewer_help->push_back("");
00474   }
00475 
00476 
00477   if(!helpHandledByScript)
00478   {
00479       viewer_help->push_back("  Script command keys:");
00480       viewer_help->push_back("    Enter Key    -- invoke command on current cell");
00481     
00482       if(invocationKeys_.size() > 1)
00483       {
00484          for(size_t i = 1; i < invocationKeys_.size(); ++i)
00485          {
00486              char buffer[256];
00487     
00488              char keyname[40];
00489     
00490              int  c = invocationKeys_[i];
00491     
00492              if(c < ' ')
00493              {
00494                sprintf(keyname, "^%c", c + '@');
00495              }
00496              else
00497              {
00498                sprintf(keyname, "%c", c);
00499              }
00500     
00501     
00502              sprintf(buffer, "    %-9.9s   -- interpreted by script", keyname);
00503     
00504              viewer_help->push_back(buffer);
00505          }
00506       }
00507   }
00508 
00509   viewer_help->push_back("");
00510   viewer_help->push_back("  Movement keys");
00511   viewer_help->push_back("    up arrow    -- move up one cell");
00512   viewer_help->push_back("    down arrow  -- move down one cell");
00513   viewer_help->push_back("    left arrow  -- move left 1 character or cell");
00514   viewer_help->push_back("                   if at the beginning of the cell");
00515   viewer_help->push_back("    right arrow -- move right 1 character or cell");
00516   viewer_help->push_back("                   if at the end of text in the cell");
00517   viewer_help->push_back("    tab         -- move right one cell");
00518   viewer_help->push_back("    shift-tab   -- move left one cell");
00519   viewer_help->push_back("    ^P          -- move right 1 whole page");
00520   viewer_help->push_back("");
00521   viewer_help->push_back("  Command invocation:");
00522   viewer_help->push_back("    Enter       -- trigger the action for this cell");
00523 
00524   manager_->help_helper(*viewer_help);
00525 }
00526 
00529 
00530 static void parseReturnedCells(string const &cellList,
00531                                vector< pair<size_t,size_t> > &returnData
00532                               )
00533 {
00534     // expecting to process value which looks like this:
00535     //
00536     //   (rowNumber,colNumber), (rowNumber,colNumber), ...
00537     //
00538     //  row col pairs are stored in session_.back().returnedCells_;
00539 
00540     char const *ptr = cellList.data();
00541     char const *end = ptr + cellList.size();
00542 
00543     while(ptr != end)
00544     {
00545        // scan until you find a (
00546 
00547        while(ptr != end && *ptr != '(')
00548           ++ptr;
00549 
00550        if(ptr != end)
00551        {
00552            // if not out of data, try parsing (n,n)
00553 
00554            ++ptr;
00555 
00556            char const *start = ptr;
00557 
00558            while(ptr != end && *ptr != ')')
00559              ++ptr;
00560 
00561            if(ptr != end)
00562            {
00563               // scan to ptr should be "number,number)" with optional spaces.
00564 
00565               // cells are 1 based to users
00566 
00567               ++ptr;
00568 
00569               int row = -1;
00570               int col = -1;
00571 
00572               sscanf(start, " %d , %d ", &row, &col);
00573 
00574               if(row <= 0 || col <= 0)
00575                 break;
00576 
00577               pair<size_t, size_t> tmp(row-1,col-1);
00578 
00579               returnData.push_back(tmp);
00580 
00581            }
00582        }
00583     }
00584 }
00585 
00588 void ScriptTableViewer::populateTable(std::string const      &scriptParms,
00589                                       CursorWindow::viewport *vp
00590                                      )
00591 {
00592 
00593     string command = scriptname_ + " " + scriptParms + discardErrors;
00594 
00595     char saved_dir[2048];
00596 
00597     if(0 == getcwd(saved_dir, sizeof(saved_dir)))
00598     {
00599         saved_dir[0] = 0;
00600     }
00601 
00602     int err;
00603 
00604     if(!directory_.empty())
00605        err =chdir(directory_.c_str());
00606 
00607     FILE *scriptOutput = popen(command.c_str(), "r");
00608 
00609     err = chdir(saved_dir);
00610 
00611     if(!scriptOutput)
00612     {
00613        fileError_="script invocation failure:  ";
00614        fileError_+= command;
00615        return;
00616     }
00617 
00618     clear(); // delete all rows and columns.  But not the session_ contents!
00619 
00620     string line;
00621 
00622     bool firstLine=true;   // we have not yet passed the first line of row/col data.
00623 
00624     size_t rowCount=0, colCount=0;
00625 
00626     bool firstOption=true; // first option to be processed
00627 
00628     char buffer[32768];
00629 
00630     while(fgets(buffer, sizeof(buffer), scriptOutput))
00631     {
00632         if(firstOption && vp)
00633         {
00634            // on the very first line of output from the script, check to see if
00635            // we are dealing with a popup request.
00636 
00637            firstOption = false;
00638 
00639            // looking for =%==%--POPUP=
00640 
00641            size_t buffLength = strlen(buffer);
00642 
00643            if(buffLength > 13 && buffer[0] == '=')
00644            {
00645                static string POPUP="=%==%--POPUP=";
00646 
00647 
00648                if(strncmp(POPUP.c_str(), buffer, POPUP.size()) == 0)
00649                {
00650                   // OK, the script has produced =%==%--POPUP=<definition>
00651                   // as its output.
00652 
00653                   // so show the popup, and re-invoke the script with additional
00654                   // parameters defined by the user's inputs from the popup.
00655 
00656                   vector< pair<string, string> >  userInputs;
00657 
00658                   bool aborted = showPopup(vp, buffer, userInputs);
00659 
00660                   if(aborted)
00661                   {
00662                       userInputs.clear();
00663 
00664                       userInputs.push_back( pair<string,string>() );
00665 
00666                       userInputs.back().first  = "POPUP_ABORTED";
00667                       userInputs.back().second = "1";
00668                   }
00669 
00670                   string newParmList = scriptParms;
00671 
00672                   for(size_t i = 0; i < userInputs.size(); ++i)
00673                   {
00674                       string tmp = "--"; 
00675                       
00676                       tmp += userInputs[i].first;
00677 
00678                       tmp += '=';
00679 
00680                       tmp += userInputs[i].second;
00681 
00682                       appendParm(newParmList, tmp, false);  // prepend not append
00683                   }
00684 
00685                   // we have now added the user's popup selections to the
00686                   // the script invocation as variable settings.
00687                   // 
00688                  
00689                   pclose(scriptOutput);
00690                   
00691                   populateTable(newParmList, vp);
00692 
00693                   return;
00694 
00695                }
00696            }
00697         }
00698 
00699 
00700         FieldAttributes rowInfo;
00701 
00702         if(firstLine)
00703         {
00704             char c = buffer[0];
00705 
00706             // the original code included isprint(c) && isalnum(c)
00707             // as well as c >  ' ' && c > 0.
00708             //
00709             // Why in the world did I restrict this to printable
00710             // characters?  It interferes with C++ code appearing
00711             // in table cells.
00712 
00713             if(true
00714                && c != ' '  // can't use space as a delimiter
00715                && c != '='  // can't use equal as a delimiter
00716               )
00717             {
00718                delimiter_ = c;
00719 
00720                line = (buffer+1);
00721             }
00722             else
00723                line = buffer;
00724         }
00725         else
00726         {
00727             char *scan = buffer;
00728 
00729             rowInfo = FieldAttributes::skip(scan, (buffer+strlen(buffer)) );
00730 
00731             line = scan;
00732         }
00733 
00734         size_t lineSize = line.size();
00735 
00736         if(  lineSize 
00737            && line[ lineSize-1 ] == '\n')
00738         {
00739            line.erase(lineSize-1);  // remove trailing new line
00740         }
00741 
00742         if(firstLine && (line.size() > 5) && line[0] == '=')
00743         {
00744           // check to see if this really the first line or rather if we are in an
00745           // option line
00746 
00747           if(0 == memcmp("=%==%--", line.data(), 7) )
00748           {
00749              // ok, this is not a real line of input -- it is a option
00750              // sent to us by the script.  We are going to keep the option
00751              // and when we invoke the script the next time, we are going to
00752              // send the options back to the script as parameters on its command line
00753 
00754 
00755              string data( line.c_str() + 7 );
00756 
00757              size_t equalPt = data.find_first_of('=');
00758 
00759              if(equalPt < line.size())
00760              {
00761                // this line contains =%==%--name=value
00762 
00763                string name = data.substr(0, equalPt);
00764 
00765                string value( data.c_str() + equalPt+1 );
00766 
00767                map<string,string> &options = sessions_.back().options_;
00768 
00769                map<string,string>::iterator location = options.find(name);
00770 
00771                if(location == options.end())
00772                   options[name]=value;
00773                else
00774                {
00775                  location->second = value;
00776                }
00777 
00778                if( name == "TITLE")
00779                {
00780                   title_ = value;
00781                }
00782                else
00783                if( name == "CMDKEYS")
00784                {
00785                    // Store all the characters in the value part of the --CMDKEYS=value declaration
00786                    // as invocation keys.  Interpret ^J to be \n, etc.
00787 
00788                    string::const_iterator first = value.begin(), last = value.end();
00789 
00790                    while(first != last)
00791                    {
00792                        char c = *first++;
00793 
00794                        if(c == '^' && first != last)
00795                        {
00796                            // handle ^X style text
00797 
00798                            c = *first++;   // skip the ^ and look at the next character
00799 
00800                            if(c != '^')
00801                            {
00802                                if( islower(c) )
00803                                   c = tolower(c);
00804 
00805                                if(c >= 'A' && c <= 'Z')
00806                                {
00807                                   c -= '@';
00808                                }
00809                            }
00810                        }
00811 
00812                        if(find(invocationKeys_.begin(), invocationKeys_.end(), c) == invocationKeys_.end())
00813                        {
00814                            // if command key not already in the list, add it to the list
00815                            invocationKeys_.push_back(c);
00816                        }
00817                    }
00818                }
00819                else
00820                if( name == "POPUPRETURN")
00821                {
00822                    // expecting to process value which looks like this:
00823                    //
00824                    //   (rowNumber,colNumber), (rowNumber,colNumber), ...
00825                    //
00826                    //  row col pairs are stored in session_.back().returnedCells_;
00827 
00828                    parseReturnedCells(value, sessions_.back().returnedCells_);
00829 
00830 
00831                }
00832 
00833 
00834                continue;
00835              }
00836              break;
00837 
00838           }
00839         }
00840 
00841 
00842         StrTool::stringlist_t fields;
00843 
00844         StrTool::parse_words(line, 
00845                              &fields, 
00846                              StrTool::all, 
00847                              StrTool::Is_Delim(delimiter_)
00848                             );
00849 
00850         if(firstLine)
00851         {
00852             // if this is the first line, set up the column headers
00853 
00854 
00855             firstLine = false;
00856 
00857             StrTool::stringlist_t::const_iterator first = fields.begin(),
00858                                                   last  = fields.end();
00859 
00860             while(first != last)
00861             {
00862                string const &cur = *first++;
00863 
00864                char const *scan = cur.c_str();
00865                char const *end  = scan + cur.size();
00866 
00867                FieldAttributes colInfo = FieldAttributes::skip(scan, end); 
00868 
00869                // if there is a [x] string, then scan will now point past ].
00870 
00871 
00872                addColumnHeader(scan, end - scan, colInfo, true);
00873 
00874                ++colCount;
00875             }
00876 
00877         }
00878         else
00879         {
00880             char buffer[40];
00881 
00882             sprintf(buffer, "%lu", (unsigned long)rows()+1);
00883 
00884             addRow(buffer,
00885                    1,
00886                    rowInfo.underlined_, 
00887                    rowInfo.bold_, 
00888                    rowInfo.editable_,
00889                    rowInfo.executable_
00890                   );
00891 
00892             ++rowCount;
00893 
00894             StrTool::stringlist_t::const_iterator first = fields.begin(),
00895                                                   last  = fields.end();
00896 
00897             while(first != last)
00898             {
00899                string const &cur = *first++;
00900 
00901                addColumnData(cur);
00902             }
00903 
00904 
00905 
00906         }
00907 
00908     }
00909 
00910     err = pclose(scriptOutput);
00911 
00912     (void)err;
00913 
00914 }
00915 
00918 static void appendParm(string &outputRef, string const &input, bool atEnd)
00919 {
00920    string *outputPtr = &outputRef;    // normally, append text to end of outputRef
00921 
00922    string tmp;
00923 
00924    if(!atEnd)
00925    {
00926        outputPtr = &tmp;   // if not storing at end, produce output to a temporary
00927                            // and prepend instead of appending
00928    }
00929 
00930    if(!(*outputPtr).empty())
00931      (*outputPtr) +=  " ";
00932 
00933    (*outputPtr) += "\"";
00934 
00935    string::const_iterator first = input.begin(), last = input.end();
00936 
00937    while(first != last)
00938    {
00939       char c = *first++;
00940 
00941       if(c == '"' || c == '`' || c == '$' )
00942         (*outputPtr) += "\\";
00943 
00944       (*outputPtr) += c;
00945 
00946    }
00947 
00948    (*outputPtr) += "\"";
00949 
00950    if(!atEnd)
00951    {
00952       tmp += ' ';
00953       
00954       tmp += outputRef;  // attach original data to end instead of vice versa
00955 
00956       outputRef = tmp;   // return whole data set
00957    }
00958 
00959 }
00960 
00963 void ScriptTableViewer::restartSession(CursorWindow::viewport *vp)
00964 {
00965        bool repopulate=true;  // if not CXX_STV_REPOPULATE
00966 
00967        std::map<std::string,std::string>::iterator flagPtr = sessions_.back().options_.find("CXX_STV_REPOPULATE");
00968 
00969        if( flagPtr != sessions_.back().options_.end())
00970        {
00971            if(flagPtr->second == "0")
00972                repopulate=false;
00973        }
00974 
00975 
00976 
00977        if(repopulate)
00978            populateTable(sessions_.back().commandLine_);  
00979 
00980        operator()(vp,  CursorWindow::viewport::repaint_handler::activate);
00981           // the above paint call is required in order to calculate page
00982           // height so you can't optimize the following code by moving it
00983           // above the paint.
00984 
00985        if(   sessions_.back().startCursorPosition_.row_ < rows()
00986           && sessions_.back().startCursorPosition_.col_ < cols()
00987          )
00988        {
00989            if(    sessions_.back().startCursorPosition_.row_ < originRow()
00990               ||  (   sessions_.back().startCursorPosition_.row_  > originRow() + pageHeight_ )
00991              )
00992            {
00993               setOrigin(sessions_.back().startCursorPosition_.row_, 0);
00994 
00995               operator()(vp,  CursorWindow::viewport::repaint_handler::activate);
00996 
00997            }
00998 
00999            TableViewer::setCursorInfo(vp, sessions_.back().startCursorPosition_);
01000        }
01001 
01002 }
01003 
01004 
01007 void ScriptTableViewer::invokeCommand(CursorWindow::viewport *vp, int cmdKey)
01008 {
01009    char keyname[40];
01010 
01011    if(cmdKey < ' ')
01012    {
01013       sprintf(keyname, "^%c", '@' + cmdKey);
01014    }
01015    else
01016    {
01017        sprintf(keyname, "%c", cmdKey);
01018    }
01019 
01020 
01021    if(rows())
01022    {
01023 
01024        string &parms = sessions_.back().commandLine_;
01025 
01026        parms.resize(0);  // empty out any old data.
01027 
01028        CursorInfo cursor = cursorInfo();
01029 
01030        map<string,string>::iterator firstOp = sessions_.back().options_.begin(), 
01031                                     lastOp  = sessions_.back().options_.end();
01032 
01033        while(firstOp != lastOp)
01034        {
01035           map<string,string>::value_type const &cur = *firstOp++;
01036 
01037           static string dashes("--");
01038 
01039           string option= dashes + cur.first + "=" + cur.second;
01040 
01041 
01042           appendParm(parms, option );
01043        }
01044 
01045        appendParm( parms, keyname);    
01046        appendParm( parms, string( fmtd<>(cursor.row_+1)) ); // row
01047        appendParm( parms, string( fmtd<>(cursor.col_+1)) ); // column
01048        appendParm( parms, string( fmtd<>(rows())       ) ); // total rows
01049        appendParm( parms, string( fmtd<>(cols())       ) ); // total columns
01050 
01051        if(layout_[cursor.row_][cursor.col_].text_.size())
01052        {
01053           // current cell text
01054 
01055           appendParm(parms, layout_[cursor.row_][cursor.col_].text_[0]); 
01056        }
01057 
01058        string rowText;
01059 
01060        vector<CellInfo>::const_iterator first = layout_[cursor.row_].begin(),
01061                                         last  = layout_[cursor.row_].end();
01062 
01063        while(first != last)
01064        {
01065           CellInfo const &cur = *first++;
01066 
01067           if(cur.text_.empty())
01068             parms += " \"\"";
01069           else
01070             appendParm(parms, cur.text_[0]);  // first row of cell
01071 
01072        }
01073 
01074 
01075        populateTable(parms,vp);
01076 
01077        operator()(vp,  CursorWindow::viewport::repaint_handler::activate);
01078 
01079 
01080    }
01081 
01082 }
01085 void ScriptTableViewer::repaintTitle(CursorWindow::viewport *vp)
01086 {
01087   vp->set_curpos(0,0);
01088   vp->set_text_attribute(active() ?  manager_->active_title_att
01089                                   :  manager_->inactive_title_att
01090                         );
01091                         
01092   *vp << title_;
01093 
01094   vp->fill_to_eol();
01095 }
01096 
01099 bool ScriptTableViewer::showPopup(CursorWindow::viewport        *vp, 
01100                                   string const                  &encodedDefinition,
01101                                   vector< pair<string,string> > &userInputs
01102                                  )
01103 {
01104     string definition;  // upon entry, the encodedDefinition has '!hh' character sequences
01105                         // in it.  They must be expanded into normal ascii by 
01106                         // converting 'hh' into a hex rep of the character
01107 
01108     // decode the definition by expanding !hh
01109 
01110     size_t i = encodedDefinition.find_first_of('-');  // --POPUP=
01111 
01112     i = encodedDefinition.find_first_of('=',i);  // find the =
01113 
01114     if(i < encodedDefinition.size() )
01115       ++i;  // skip past the =
01116 
01117     for(; i < encodedDefinition.size(); ++i)
01118     {
01119        if( encodedDefinition[i] == '!')
01120        {
01121            ++i;
01122 
01123            if(i < encodedDefinition.size() )
01124            {
01125               char c[3];
01126 
01127               c[2] = 0;
01128 
01129               c[0] = encodedDefinition[i];
01130 
01131               ++i;
01132 
01133               if( i < encodedDefinition.size() )
01134               {
01135                  c[1] = encodedDefinition[i];
01136 
01137                  int charValue=0;
01138 
01139                  sscanf(c, "%x", &charValue);
01140 
01141                  if(charValue)
01142                  {
01143                     definition += charValue;
01144                  }
01145                  else
01146                  {
01147                     definition += '!';
01148                     definition += c[0];
01149                     definition += c[1];
01150                  }
01151 
01152               }
01153               else
01154               {
01155                  definition += '!';
01156                  definition += c;
01157               }
01158 
01159            }
01160            else
01161                definition += '!';
01162        }
01163        else
01164        if(encodedDefinition[i] >= ' ')
01165        {
01166           definition += encodedDefinition[i];
01167        }
01168        else
01169        {
01170          // ignore tabs and other special characters
01171        }
01172     }
01173 
01174     // Definition now contains the real definition which is of the form:
01175     //
01176     //   --POPUP=title; label1 ; value 1; label2 ; value 2;
01177     //
01178     // 
01179     // The user's selections will be returned in order:
01180     //
01181     //     name="POPUP_FIELD_1"
01182     //     value"user entry 1
01183     //
01184     //     name="POPUP_FIELD_2"
01185     //     value"user entry 2
01186     
01187     userInputs.clear();
01188 
01189     
01190     // get the title
01191 
01192     string title="title";
01193 
01194     i = definition.find_first_of(';');
01195 
01196     if(i >= definition.size())
01197     {
01198        return true; // title must end in ;
01199     }
01200 
01201     title = definition.substr(0, i);
01202 
01203     // remove the title from the definition
01204 
01205     definition = definition.substr(i+1, definition.size()- i - 1);
01206 
01207     CursorWindow::Dialog dialog(title);
01208 
01209     int fieldNumber=0;
01210 
01211     while(definition.size())
01212     {
01213        // extract label/value pairs
01214 
01215        string label;
01216        string value;
01217 
01218        // get label.  labels must be ; terminated.
01219 
01220        i = definition.find_first_of(';');
01221 
01222        if( i >= definition.size())
01223        {
01224          return true; // badly formed label/value pair
01225        }
01226 
01227        // remove the label from definition
01228 
01229        label = definition.substr(0,i);
01230 
01231        definition = definition.substr(i+1, definition.size()- i - 1);
01232 
01233        i = definition.find_first_of(';');
01234 
01235        bool done = false;
01236 
01237        if( i >= definition.size() )
01238        {
01239           // call the rest of the definition the value
01240 
01241           value = definition;
01242 
01243           done = true;
01244 
01245        }
01246        else
01247        {
01248            value = definition.substr(0, i);
01249            
01250            definition = definition.substr(i+1, definition.size() - i - 1);
01251 
01252            if(definition.find_first_of(';') >= definition.size())
01253            {
01254               done = true;
01255            }
01256           
01257        }
01258 
01259        // here we have label and value
01260 
01261        char fieldName[40];
01262        
01263        sprintf(fieldName, "POPUP_FIELD_%d", ++fieldNumber);
01264 
01265        userInputs.push_back(  pair<string,string>() );
01266 
01267        userInputs.back().first = fieldName;
01268 
01269        dialog += new CursorWindow::Dialog::String(fieldName,
01270                                                   label,
01271                                                   value,
01272                                                   40
01273                                                  );
01274 
01275 
01276        if(done)
01277          break;
01278 
01279     }
01280 
01281 
01282     // ok, if we get here we have found no errors in the definition
01283 
01284 
01285     dialog += new CursorWindow::Dialog::Ok("ok","");
01286 
01287     if(dialog.popup(vp->window()))
01288     {
01289       return true; // aborted
01290     }
01291 
01292     // now populate the return data
01293 
01294     for(i = 0; i < userInputs.size(); ++i)
01295     {
01296        userInputs[i].second = dialog.element_value(userInputs[i].first);
01297     }
01298 
01299     
01300     return false;  // no errors
01301 }
01302 
01303 } // namespace cxxtls
Generated on Wed Feb 29 22:50:05 2012 for CXXUtilities by  doxygen 1.6.3