textviewer.cxx

Go to the documentation of this file.
00001 //
00002 // Copyright 2002, 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 
00032 
00033 #include <cxxtls/textviewer.h>
00034 #include <cxxtls/viewermanager.h>
00035 #include <fstream>
00036 #include <cxxtls/strtool.h>
00037 #include <portable_strstream.h>
00038 #include <vector>
00039 #include <portable_io.h>
00040 #include <cxxtls/cursesinterface.h>
00041 
00042 namespace cxxtls
00043 {
00044 
00045 struct TextViewer::impl
00046   //
00048   //
00049 {
00050    FileName                 filename_;   
00051    std::vector<std::string> lines_;      
00052    bool                     active_;     
00053    int                      left_;       
00054    int                      first_row_;  
00055    size_t                   first_mark_; 
00056    size_t                   last_mark_;  
00057    size_t                   page_top_;   
00058    size_t                   cur_;        
00059    size_t                   col_;        
00060    size_t                   page_left_;  
00061    std::string              search_;     
00062 
00063    void set_text_attribute(TextViewer*,
00064                            viewport*,
00065                            size_t line_no,
00066                            bool is_bottom,
00067                            bool highlight=true
00068                            );
00069    void display_line(viewport*, size_t line);  // doesn't set text attributes
00070 
00071    bool find_string(size_t line_no);  
00072 
00073 
00074 };
00075 
00076 TextViewer::
00077 ~TextViewer()
00078 {
00079 }
00080 
00081 TextViewer::
00082 TextViewer(ViewerManager*vm, FileName filename)
00083 :  Viewer(vm),
00084    impl_(new impl)
00085 {
00086    // construct a text viewer and read the file corresponding thereto.
00087 
00088    impl_->filename_   = filename;
00089    impl_->active_     = false;
00090    impl_->left_       = 0;
00091    impl_->first_row_  = 1;
00092    impl_->first_mark_ = 0;
00093    impl_->last_mark_  = 0;
00094    impl_->page_top_   = 0;
00095    impl_->cur_        = 0;
00096    impl_->col_        = 0;
00097    impl_->page_left_  = 0;
00098 
00099    using namespace std;
00100 
00101    std::list<std::string> lines;
00102 
00103    fstream file;
00104 
00105    file.open(filename.c_str(), ios::in);
00106 
00107    if(file.fail())
00108    {
00109      return;
00110    }
00111 
00112    istreambuf_iterator<char> nc(file);
00113    istreambuf_iterator<char> lc;
00114 
00115    string line;
00116 
00117    size_t line_count=0;
00118 
00119    while(nc != lc)
00120    {
00121      char c = *nc++;
00122 
00123      if(c == '\n')
00124      {
00125        lines.push_back(StrTool::expand_tabs(line,0,'~'));
00126        line.resize(0);
00127        ++line_count;
00128      }
00129      else
00130        line += c;
00131 
00132    }
00133 
00134    if(line.size())
00135    {
00136      lines.push_back(StrTool::expand_tabs(line,0,'~'));
00137      ++line_count;
00138    }
00139 
00140    file.close();
00141 
00142    impl_->lines_.resize(line_count);
00143 
00144    std::copy(lines.begin(), lines.end(), impl_->lines_.begin());
00145 
00146 }
00147 
00148 void
00149 TextViewer::impl::
00150 display_line(viewport *vp, size_t line)
00151 {
00152 
00153   if(line >= lines_.size())
00154   {
00155     vp->fill_to_eol();
00156     return;
00157   }
00158   
00159 
00160   std::string const & str = lines_[line];
00161 
00162   size_t width = str.size();
00163 
00164   if(width >= page_left_ && line <= lines_.size() )
00165   {
00166     std::string::const_iterator start = str.begin() + page_left_,
00167                                 end   = str.end();
00168                         
00169     vp->write(start, end);
00170 
00171   }
00172 
00173   vp->fill_to_eol();
00174 
00175 }
00176 
00177 
00178 void
00179 TextViewer::
00180 operator() ( CursorWindow::viewport *     vp,
00181                             int           cmd
00182                           )
00184 {
00185   // WARNING:  do not save vp -- it gets deleted regularly!
00186 
00187   if(cmd == CursorWindow::viewport::repaint_handler::activate)
00188     impl_->active_ = true;
00189   else
00190   if(cmd == CursorWindow::viewport::repaint_handler::deactivate)
00191     impl_->active_ = false;
00192 
00193 
00194   // determine if we need to write a column of '|'s to separate us from
00195   // the window to the left -- and subsequently not write in that column.
00196 
00197   row_col size    = vp->size();
00198   row_col origin  = vp->origin();
00199 
00200   if(origin.col_ != 0)
00201     impl_->left_ = 1;
00202   else
00203     impl_->left_ = 0;
00204 
00205   int i;
00206 
00207   vp->set_text_attribute(manager_->inactive_mark_att);
00208 
00209   for(i=0; impl_->left_ && i < size.col_; ++i)
00210   {
00211     vp->set_curpos(i,0);
00212 
00213     using namespace CursesInterface;
00214 
00215     vp->write(line_chars[VL_MIDDLE]);
00216   }
00217 
00218   // now write the title
00219 
00220   vp->set_curpos(0,impl_->left_);
00221   vp->set_text_attribute( impl_->active_ ? manager_->active_title_att
00222                                          : manager_->inactive_title_att
00223                         );
00224                         
00225   *vp << "Viewing " << impl_->filename_.shorten(size.col_ - 8);
00226 
00227   vp->fill_to_eol();
00228 
00229   // now write the displayable portions of the file text -- handling
00230   // marked lines, left margin and special highlighting of the bottom
00231   // line.
00232 
00233   int row=impl_->first_row_;
00234 
00235   int displayable_rows = size.row_ - row;
00236 
00237   size_t cur_line = impl_->page_top_;
00238 
00239   for(i=0; i < displayable_rows; ++i)
00240   {
00241     // for each displayable row in the window
00242 
00243     if(cur_line >= impl_->lines_.size())
00244       break;
00245 
00246     // we haven't dropped off the bottom of the file data
00247 
00248     impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00249 
00250     vp->set_curpos(row, impl_->left_);
00251 
00252     impl_->display_line(vp, cur_line);
00253 
00254     ++row;
00255     ++cur_line;
00256   }
00257 
00258 
00259   bool first_time=true;
00260 
00261   while(row < size.row_)
00262   {
00263     vp->set_curpos(row,impl_->left_);
00264 
00265     if(first_time)
00266     {
00267       first_time=false;
00268 
00269       vp->set_text_attribute(ViewerManager::active_title_att);
00270       vp->write("*eof*");
00271       impl_->set_text_attribute(this, vp, cur_line, false, false); // not current and not bottom
00272     }
00273     else
00274     {
00275       if(row == size.row_-1)
00276       {
00277         vp->set_text_attribute(manager_->bottom_att);
00278       }
00279       else
00280         impl_->set_text_attribute(this, vp, cur_line, false, false); // not current and not bottom
00281 
00282     }
00283 
00284     vp->fill_to_eol();
00285 
00286     ++row;
00287   }
00288 
00289   {
00290     // make sure cursor is in a valid position
00291 
00292     size_t width = size.col_ - impl_->left_;
00293 
00294     size_t cur_col = impl_->col_ - impl_->page_left_;
00295 
00296     if(cur_col >= width)
00297     impl_->col_ = impl_->page_left_ + width-1;
00298 
00299   }
00300 
00301 
00302   vp->set_curpos(impl_->first_row_ + impl_->cur_ - impl_->page_top_,
00303                  impl_->left_ + (impl_->col_ -  impl_->page_left_)
00304                 );
00305 
00306 }
00307 
00308 
00309 bool
00310 TextViewer::
00311 handle_event( CursorWindow::input_event const * e,
00312                              CursorWindow::viewport          * vp
00313                            )
00315 {
00316 
00317   if(e->type_ == input_event::ForceExitKey)
00318     return 2; // terminate window operations
00319 
00320 
00321   if(e->type_ != input_event::FunctionKey &&
00322      e->type_ != input_event::DataKey
00323     )
00324   return false;  // huh?  Ignore unexpected events
00325 
00326   if(e->value_ == ('K' - '@'))
00327     return 2;
00328 
00329   int edit_func = (*manager_->window()).func[e->value_]; // map user key to function
00330 
00331   // unhighlight the currently selected line to handle the key rehighlighting
00332   // that may be needed
00333 
00334   row_col size    = vp->size();
00335   row_col origin  = vp->origin();
00336 
00337   if(origin.col_ != 0)
00338     impl_->left_ = 1;
00339 
00340   int row=impl_->first_row_;   // row within displayable region of viewport
00341 
00342   size_t cur_line = impl_->cur_;
00343 
00344   row += cur_line - impl_->page_top_;
00345 
00346   impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1, false);
00347        // don't highlight but do all else
00348 
00349   vp->set_curpos(row, impl_->left_);
00350 
00351   if(impl_->lines_.size() > cur_line)
00352     impl_->display_line(vp, cur_line);
00353 
00354   // handle the function -- assuming that the current line is not currently drawn highlighted
00355 
00356   switch(edit_func)
00357   {
00358     case CursorWindow::func_down:  // cursor down 1 line
00359 
00360       if(impl_->lines_.size() == 0)
00361         break;
00362 
00363       if(cur_line < impl_->lines_.size()-1 &&
00364          row < size.row_ - impl_->first_row_
00365         )
00366       {
00367         // not at bottom of displayable area, just move down a line
00368         
00369         ++impl_->cur_; // change cur line to force highlight color change
00370         
00371         impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00372              // re-highlight the current line
00373 
00374         vp->set_curpos(row, impl_->left_);
00375 
00376         impl_->display_line(vp, cur_line);
00377         
00378         ++row;
00379         ++cur_line;  // change active line
00380       }
00381       else
00382       if(cur_line != impl_->lines_.size()-1)
00383       {
00384         // we are on last line of viewport but not last line of the
00385         // file -- scroll page down 1 line
00386         
00387         
00388         ++cur_line;
00389         ++impl_->cur_;
00390         ++impl_->page_top_;
00391         
00392         (*this)(vp,0);  // repaint window
00393         
00394       }
00395 
00396       break;
00397 
00398     case CursorWindow::func_up:  // cursor down 1 line
00399 
00400       if(impl_->lines_.size() == 0)
00401         break;
00402 
00403       if(row != impl_->first_row_)
00404       {
00405         // not at bottom of displayable area, just move down a line
00406 
00407         --impl_->cur_; // change cur line to force highlight color change
00408         
00409         impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00410              // re-highlight the current line
00411 
00412         vp->set_curpos(row, impl_->left_);
00413 
00414         impl_->display_line(vp, cur_line);
00415 
00416         --row;
00417         --cur_line;
00418       }
00419       else
00420       if(cur_line != 0)
00421       {
00422         // scroll up one line
00423         --cur_line;
00424         --impl_->cur_;
00425         --impl_->page_top_;
00426         
00427         (*this)(vp,0);  // repaint window
00428         
00429       }
00430 
00431       break;
00432 
00433 
00434     case CursorWindow::func_next:  // cursor down 1 page
00435 
00436       if(impl_->lines_.size() == 0)
00437         break;
00438 
00439       {
00440         int page_size = size.row_ - impl_->first_row_;
00441         
00442         impl_->cur_ += page_size;
00443         
00444         if(impl_->cur_ >= impl_->lines_.size())
00445         {
00446           impl_->cur_ = impl_->lines_.size() -1;
00447         }
00448         
00449         if( (int)(impl_->cur_) < 0 )
00450           impl_->cur_ = 0;
00451         
00452         impl_->page_top_ += page_size;
00453         
00454         if(impl_->page_top_ >= impl_->cur_)
00455           impl_->page_top_ = impl_->cur_;
00456         
00457         row = impl_->first_row_ + (impl_->cur_ - impl_->page_top_);
00458         cur_line = impl_->cur_;
00459         
00460         (*this)(vp,0);
00461         
00462       }
00463       break;
00464 
00465 
00466     case CursorWindow::func_prior:  // cursor up 1 page
00467 
00468       if(impl_->lines_.size() == 0)
00469         break;
00470 
00471       if(impl_->page_top_ == 0)
00472       {
00473         impl_->cur_ = 0;
00474         
00475         impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1);
00476              // re-highlight the current line
00477 
00478         vp->set_curpos(row, impl_->left_);
00479 
00480         impl_->display_line(vp, cur_line);
00481         
00482         row = impl_->first_row_;
00483         cur_line = 0;
00484       }
00485       else
00486       {
00487         int page_size = size.row_ - impl_->first_row_;
00488         
00489         impl_->cur_ -= page_size;
00490 
00491 
00492 
00493         
00494         if(impl_->cur_ >= impl_->lines_.size())  // cur is unsigned ;-<
00495         {
00496           impl_->cur_ = 0;
00497         }
00498         
00499         if( (int)(impl_->cur_) < 0 )
00500           impl_->cur_ = 0;
00501         
00502         impl_->page_top_ -= page_size;
00503         
00504         if(impl_->page_top_ >= impl_->cur_)  // page top is unsigned
00505           impl_->page_top_ = impl_->cur_;
00506         
00507         row = impl_->first_row_ + (impl_->cur_ - impl_->page_top_);
00508         cur_line = impl_->cur_;
00509         
00510         (*this)(vp,0);
00511         
00512       }
00513       break;
00514 
00515 
00516     case CursorWindow::func_top:  // goto top of file
00517 
00518       if(impl_->lines_.size() == 0)
00519         break;
00520 
00521       row = impl_->first_row_;
00522       cur_line = 0;
00523       impl_->cur_ = 0;
00524       impl_->page_top_ = 0;
00525 
00526       (*this)(vp,0);
00527 
00528       break;
00529 
00530 
00531     case CursorWindow::func_bottom:  // goto top of file
00532 
00533       if(impl_->lines_.size() == 0)
00534         break;
00535 
00536       {
00537         int page_size = size.row_ - impl_->first_row_;
00538 
00539         impl_->cur_ = impl_->lines_.size()-1;
00540         
00541         impl_->page_top_ = impl_->cur_ - page_size + 1;
00542         
00543         if(impl_->page_top_ > impl_->cur_ )
00544           impl_->page_top_ = 0;
00545         
00546         cur_line = impl_->cur_;
00547         
00548         row = impl_->first_row_ + (impl_->cur_ - impl_->page_top_);
00549 
00550         (*this)(vp,0);
00551       }
00552 
00553       break;
00554 
00555     case CursorWindow::func_right:
00556       {
00557         size_t width = size.col_ - impl_->left_;
00558         
00559         ++impl_->col_;
00560         
00561         if(impl_->col_ - impl_->page_left_ >= width )
00562         {
00563           impl_->page_left_ += 10;
00564           impl_->col_       = impl_->page_left_ + width - 1;
00565         
00566           (*this)(vp,0);
00567         }
00568         
00569       }
00570       break;
00571 
00572 
00573     case CursorWindow::func_left:
00574       {
00575         if(impl_->col_)
00576         {
00577           --impl_->col_;
00578         
00579           if(impl_->col_ < impl_->page_left_)
00580           {
00581             impl_->page_left_ -= 10;
00582         
00583             if( (int)(impl_->page_left_) < 0 )
00584               impl_->page_left_ = 0;
00585         
00586             (*this)(vp,0);
00587         
00588           }
00589         
00590         }
00591       }
00592       break;
00593 
00594     case CursorWindow::func_tab:
00595       {
00596         impl_->page_left_ += 10;
00597         impl_->col_       += 10;
00598         (*this)(vp,0);
00599       }
00600       break;
00601 
00602     case CursorWindow::func_btab:
00603     scroll_left:
00604       {
00605         impl_->page_left_ -= 10;
00606         impl_->col_       -= 10;
00607         
00608         if( (int)(impl_->page_left_) < 0 )
00609           impl_->page_left_ = 0;
00610         
00611         if( (int)(impl_->col_) < 0)
00612           impl_->col_ = 0;
00613         
00614         (*this)(vp,0);
00615       }
00616       break;
00617 
00618     case CursorWindow::func_home:
00619       {
00620         bool repaint = false;
00621         
00622         if(impl_->page_left_)
00623         {
00624           impl_->page_left_ = 0;
00625           repaint = true;
00626         }
00627         
00628         impl_->col_       = 0;
00629         
00630         if(repaint)
00631           (*this)(vp,0);
00632       }
00633       break;
00634 
00635 
00636     case CursorWindow::func_end: // move cursor to end of current line
00637 
00638       if(impl_->lines_.size())
00639       {
00640         size_t width = size.col_ - impl_->left_;
00641 
00642         std::string const &cur = impl_->lines_[cur_line];
00643         
00644         impl_->col_ = cur.size();
00645         
00646         if(impl_->col_ < impl_->page_left_)
00647         {
00648           impl_->page_left_ = impl_->col_ - 10;
00649 
00650           if( (int)(impl_->page_left_) < 0)
00651           {
00652             impl_->page_left_ = 0;
00653           }
00654         
00655           (*this)(vp,0);
00656         }
00657         else
00658         if(impl_->col_ >= impl_->page_left_ + width)
00659         {
00660           impl_->page_left_ = impl_->col_ - 10;
00661         
00662           if( (int)(impl_->page_left_) < 0)
00663           {
00664             impl_->page_left_ = 0;
00665           }
00666         
00667           (*this)(vp,0);
00668         }
00669         
00670       }
00671       break;
00672 
00673     case CursorWindow::func_find:  //find first
00674       {
00675         CursorWindow::Dialog d("Find String");
00676         
00677         d += new CursorWindow::Dialog::String("name",
00678                                               "String to search for",
00679                                               "",
00680                                               15
00681                                              );
00682                                 
00683         if(d.popup(manager_->window()))
00684           return false;
00685         
00686         impl_->search_ = d.element_value("name");
00687         
00688         if(impl_->search_.size() == 0)
00689            return false;
00690 
00691         if( impl_->find_string(cur_line-1) )
00692         {
00693           ensure_cursor_visible(vp);
00694         
00695           row = impl_->first_row_ + impl_->cur_ - impl_->page_top_;
00696 
00697           cur_line = impl_->cur_;
00698         }
00699         
00700       }
00701       break;
00702 
00703     case CursorWindow::func_findnxt:  //find first
00704 
00705         if( impl_->find_string(cur_line) )
00706         {
00707           ensure_cursor_visible(vp);
00708         
00709           row = impl_->first_row_ + impl_->cur_ - impl_->page_top_;
00710 
00711           cur_line = impl_->cur_;
00712         }
00713         break;
00714         
00715     case CursorWindow::func_mark:
00716       goto mark_line;
00717 
00718     case CursorWindow::func_data:  // normal keys
00719 
00720       if(impl_->lines_.size() == 0 && e->value_ != 'q' )
00721         break;
00722 
00723       switch(e->value_)
00724       {
00725 
00726         case 'q':  return 2;
00727         
00728         case 'p':
00729         
00730           if(impl_->first_mark_ != impl_->last_mark_)
00731           {
00732 
00733 
00734             CursorWindow::FileSelector d("Put Marked lines to a file", impl_->filename_.dirname() + "*", "");
00735 
00736             FileName fullname = d.popup(manager_->window(), this);
00737 
00738         
00739             if(fullname == "")
00740               return 0;
00741         
00742         
00743             FileName tmp(fullname);
00744             tmp.convert_to_absolute_path();
00745         
00746             fullname = tmp;
00747         
00748             {
00749               using namespace std;
00750         
00751               fstream file;
00752         
00753               file.open(fullname.c_str(), ios::out);
00754         
00755               if(file.fail())
00756               {
00757                 CursorWindow::Message m("Error");
00758                 
00759                 m += "Sorry, could not open the target file for write";
00760                 m += "";
00761                 m += "Press enter to continue";
00762         
00763                 m.popup(manager_->window());
00764                 return 0;
00765         
00766                 break;
00767               }
00768         
00769               ostreambuf_iterator<char> nc(file);
00770         
00771               size_t i;
00772         
00773               for(i= impl_->first_mark_; i < impl_->last_mark_; ++i)
00774               {
00775                 std::string &s = impl_->lines_[i];
00776                 
00777                 std::copy(s.begin(), s.end(), nc);
00778                 
00779                 nc = copy_end_of_line(nc);
00780                 
00781               }
00782         
00783               file.close();
00784         
00785             }
00786         
00787                 
00788           }
00789           break;
00790         
00791         case 'm':
00792         mark_line:
00793           {
00794             if(impl_->first_mark_ == impl_->last_mark_)
00795             {
00796               // no lines currently marked
00797         
00798               impl_->first_mark_ = impl_->cur_;
00799               impl_->last_mark_  = impl_->cur_ + 1;
00800             }
00801             else
00802             {
00803               // there is already a marked region
00804         
00805               if(impl_->last_mark_ == impl_->first_mark_ + 1)
00806               {
00807                 // the marked region is exactly one line
00808                 
00809                 if(impl_->cur_ == impl_->first_mark_)
00810                 {
00811                   // and the cursor is sitting on that one line,
00812                   // then unmark
00813                 
00814                   impl_->last_mark_ = impl_->first_mark_ = 0;
00815                 
00816                 }
00817                 else
00818                 {
00819                   // the cursor is not sitting on the currently marked line
00820                 
00821                   if(impl_->cur_ < impl_->first_mark_)
00822                     impl_->first_mark_ = impl_->cur_;
00823                   else
00824                     impl_->last_mark_ = impl_->cur_ + 1;
00825                 }
00826                 
00827               }
00828               else
00829                 impl_->first_mark_ = impl_->last_mark_ = 0;
00830         
00831             }
00832         
00833             (*this)(vp,0); // repaint to highlight the marks
00834         
00835           }
00836           break;
00837       }
00838       break;
00839 
00840     default:  // ignore random commands
00841 
00842       if(e->value_ == ('\\' - '@'))
00843         goto scroll_left;
00844 
00845       break;
00846   }
00847 
00848   // re-highlight the current row
00849 
00850   impl_->set_text_attribute(this, vp, cur_line, row == size.row_-1); // don't highlight but do all else
00851 
00852   vp->set_curpos(row, impl_->left_);
00853 
00854   impl_->display_line(vp, cur_line);
00855 
00856   vp->set_curpos(row,
00857                  impl_->left_ + (impl_->col_ -  impl_->page_left_)
00858                 );
00859 
00860 
00861  return 0;
00862 
00863 }
00864 
00865 void
00866 TextViewer::
00867 help()
00868 {
00869   std::auto_ptr< std::list< std::string > >
00870     viewer_help( new std::list< std::string > );
00871 
00872   viewer_help->push_back("Help for the text viewer");
00873   viewer_help->push_back("");
00874   viewer_help->push_back("  Use the normal scrolling and cursor movement keys.");
00875   viewer_help->push_back("");
00876   viewer_help->push_back("  The 'm' key toggles inclusion of the current line in");
00877   viewer_help->push_back("  marked region.");
00878   viewer_help->push_back("");
00879   viewer_help->push_back("  The 'p' key lets you saved the marked lines to a file.");
00880   viewer_help->push_back("");
00881   viewer_help->push_back("  The '^S' key lets you begin a search for a string");
00882   viewer_help->push_back("");
00883   viewer_help->push_back("  The '^N' key lets repeat a search for same string used before");
00884   viewer_help->push_back("");
00885   viewer_help->push_back("  The 'Tab' key lets scroll to the right by 10 characters");
00886   viewer_help->push_back("");
00887   viewer_help->push_back("  The 'Ctrl-\\' key lets scroll to the left by 10 characters");
00888   viewer_help->push_back("");
00889   viewer_help->push_back("  The 'shift Tab' key also lets scroll to the left by 10 characters");
00890 
00891 
00892 
00893   manager_->help_helper(*viewer_help);
00894 }
00895 
00896 Viewer*
00897 TextViewer::
00898 app(ViewerManager*vm, std::string &fullname)
00899 {
00900   if(fullname.size() == 0)
00901   {
00902     // do not use the FileSelector here because it can't repaint the screen
00903 
00904     CursorWindow::Dialog d("File name");
00905 
00906     d += new CursorWindow::Dialog::String("name",
00907                                           "path",
00908                                           "*",
00909                                           40
00910                                          );
00911                                 
00912     if(d.popup(vm->window()))
00913       return 0;
00914 
00915     fullname = d.element_value("name");
00916 
00917     if(fullname == "")
00918       return 0;
00919 
00920 
00921     FileName tmp(fullname);
00922     tmp.convert_to_absolute_path();
00923 
00924     fullname = tmp;
00925 
00926   }
00927   return new TextViewer(vm,fullname);
00928 
00929 }
00930 
00931 std::string TextViewer::app_name = "VIEW TEXT";
00932 
00933 std::string TextViewer::description() const
00934 {
00935   return impl_->filename_;
00936 }
00937 
00938 void
00939 TextViewer::impl::
00940 set_text_attribute(TextViewer* viewer,
00941                    viewport*   vp,
00942                    size_t      line,
00943                    bool        is_bottom,
00944                    bool        highlight
00945                   )
00946 {
00947   if(line >= first_mark_ && line < last_mark_)
00948   {
00949     if(highlight)
00950     {
00951       if(active_)
00952       {
00953         vp->set_text_attribute(ViewerManager::highlighted_att);
00954       }
00955       else
00956         vp->set_text_attribute(ViewerManager::inactive_mark_att);
00957     }
00958     else
00959         vp->set_text_attribute(ViewerManager::inactive_mark_att);
00960 
00961   }
00962   else
00963   if(line == cur_)
00964     vp->set_text_attribute(active_ ? (is_bottom ? ViewerManager::bottom_att
00965                                                 : ViewerManager::normal_att)
00966                                    : ViewerManager::inactive_mark_att);
00967   else
00968   if(is_bottom)
00969     vp->set_text_attribute(ViewerManager::bottom_att);
00970   else
00971     vp->set_text_attribute(ViewerManager::normal_att);
00972 }
00973 
00974 struct caseless_compare
00975 {
00976   bool operator() (char a, char b)
00977   {
00978     if(a == b)
00979       return true;
00980     else
00981     {
00982       // the characters are not equal
00983 
00984       if( (a < 'a' && b < 'a')
00985          ||
00986           (a >= 'a' && b >= 'a')
00987         )
00988       {
00989         // the characters are either both upper case or both lower case
00990         // but they are different
00991 
00992         return false;
00993       }
00994       else
00995       {
00996         //
00997         //  the case of the characters is different, so try comparing them again
00998         //
00999         if(islower(a))
01000           a = toupper(a);
01001       
01002         if(islower(b))
01003           b = toupper(b);
01004       }
01005     }
01006 
01007     return a == b;
01008 
01009   }
01010 };
01011 
01012 bool
01013 TextViewer::impl::
01014 find_string(size_t line_before)
01015 {
01016   size_t line = line_before + 1;
01017 
01018   while(line < lines_.size())
01019   {
01020     std::string::iterator start = std::search(lines_[line].begin(),
01021                                               lines_[line].end(),
01022                                               search_.begin(),
01023                                               search_.end(),
01024                                               caseless_compare()
01025                                              );
01026     if(start != lines_[line].end())
01027     {
01028       col_ = start - lines_[line].begin();
01029       break;
01030     }
01031 
01032     ++line;
01033   }
01034 
01035   if(line == lines_.size())
01036     return false;
01037 
01038   // at this point, we have found a line containing the specified
01039   // search string.
01040 
01041   cur_ = line;
01042 
01043   return true;
01044 
01045 }
01046 
01047 
01048 void
01049 TextViewer::
01050 ensure_cursor_visible(viewport* vp)
01051 {
01052   row_col size = vp->size();
01053 
01054   size_t usable_columns = size.col_ - impl_->left_;
01055   size_t usable_rows    = size.row_ - impl_->first_row_;
01056 
01057   size_t column_offset  = impl_->col_ - impl_->page_left_;
01058   size_t row_offset     = impl_->cur_  - impl_->page_top_;
01059 
01060   if(   (row_offset >= usable_rows)
01061      ||
01062         (column_offset >= usable_columns)
01063      ||
01064         (impl_->col_ < impl_->page_left_)
01065     )
01066   {
01067     // cursor is not on current page
01068 
01069     if(row_offset >= usable_rows )
01070     {
01071       impl_->page_top_ = impl_->cur_ - size.row_/2;
01072 
01073       if( (int)(impl_->page_top_) < 0)
01074         impl_->page_top_ = 0;
01075     }
01076 
01077     if(  impl_->col_ < impl_->page_left_
01078        ||
01079          column_offset >= usable_columns
01080       )
01081     {
01082       impl_->page_left_ = impl_->col_ - 10;
01083 
01084       if( (int)(impl_->page_left_) < 0 )
01085         impl_->page_left_ = 0;
01086     }
01087 
01088     (*this)(vp,0);
01089 
01090   }
01091 }
01092 
01093 } // namespace cxxtls
Generated on Wed Feb 29 22:50:05 2012 for CXXUtilities by  doxygen 1.6.3