viewermanager.cxx

Go to the documentation of this file.
00001 
00002 //
00003 // Copyright 2002, Lowell Boggs Jr.
00004 //
00005 // This file or directory, containing source code for a computer program,
00006 // is Copyrighted by Lowell Boggs, Jr.  987 Regency Drive, Lewisville
00007 // TX (USA), 75067.  You may use, copy, modify, and distribute this
00008 // source file without charge or obligation so long as you agree to
00009 // the following:
00010 //
00011 //  1.  You must indemnify Lowell Boggs against any and all financial
00012 //      obligations caused by its use, misuse, function, or malfunction.
00013 //      Further, you acknowledge that there is no warranty of any kind,
00014 //      whatsoever.
00015 //
00016 //  2.  You agree not to attempt to patent any portion of this original
00017 //      work -- though you may attempt to patent your own extensions to
00018 //      it if you so choose.
00019 //
00020 //  3.  You keep this copyright notice with the file and all copies
00021 //      of the file and do not change it anyway except language translation.
00022 //
00023 // You are responsible for enforcing your own compliance with these
00024 // conditions and may not use this source file if you cannot agree to the
00025 // above terms and conditions.
00026 
00030 
00031 
00032 #include <cxxtls/viewermanager.h>
00033 #include <cxxtls/file.h>
00034 #include <cxxtls/options.h>
00035 #include <cxxtls/etagsdb.h>
00036 #include <cxxtls/strtool.h>
00037 #include <cxxtls/cursesinterface.h>
00038 #include <cxxtls/user.h>
00039 #include <cxxtls/cpptagdb.h>
00040 #include <cxxtls/strtool.h>
00041 #include <cxxtls/foreach.h>
00042 
00043 #include <stdlib.h>
00044 #include <portable_io.h>
00045 #include <fstream>
00046 #include <iomanip>
00047 
00048 using namespace std;
00049 
00050 namespace cxxtls
00051 {
00052 
00053 static int trash;
00054 
00055 typedef CursorWindow::viewport::repaint_handler repaint_handler;
00056 
00057 int ViewerManager::normal_att        = CursorWindow::normal;
00058 int ViewerManager::active_title_att  = CursorWindow::reverse_bold;
00059 int ViewerManager::inactive_title_att= CursorWindow::underlined;
00060 int ViewerManager::active_mark_att   = CursorWindow::reverse_ul;
00061 int ViewerManager::inactive_mark_att = CursorWindow::bold;
00062 int ViewerManager::bottom_att        = CursorWindow::underlined;  // bottom line of viewport
00063 int ViewerManager::highlighted_att   = CursorWindow::reversed;
00064 
00065 
00066 class ViewerSelector
00067   //
00071   //
00072 : public Viewer
00073 {
00074 public:
00075 
00076   size_t cur_row_;                 
00077   size_t display_top_;             
00078   int    first_row_;               
00079   bool   active_;
00080 
00081   ViewerSelector(ViewerManager* m)
00082   : Viewer(m),
00083     cur_row_(0),
00084     display_top_(0),
00085     first_row_(2),
00086     active_(true)
00087   {
00088     trash=2;
00089   }
00090 
00091   void operator() ( CursorWindow::viewport * vp,int cmd);
00093 
00094   bool handle_event( CursorWindow::input_event const * e,
00095                      CursorWindow::viewport          * vp
00096                    );
00097 
00098   static string app_name;
00099 
00100   string const &application_name() const { return app_name; }
00101                 
00102   void repaint(CursorWindow::viewport *vp)
00103   {
00104      (*this)(vp, activate );
00105   }
00106 
00107   void output_row_text(CursorWindow::viewport * vp, int i)
00108   {
00109     // do not set the text attributes here!
00110 
00111 
00112     int maxw = vp->size().col_ - 15;
00113 
00114     if(i < (int)manager_->viewers_.size() )
00115     {
00116       string tmp = manager_->viewers_[i].first->application_name();
00117 
00118       if(tmp.size() > 10)
00119         tmp.erase(10,tmp.size());
00120         
00121       Viewer* viewer = manager_->viewers_[i].first;
00122         
00123       FileName thisfile(viewer->description());
00124 
00125       *vp << (viewer->is_dirty() ? "*" : " ")
00126           << std::setw(10) << tmp
00127           << "  " << thisfile.shorten(maxw)
00128           ;
00129     }
00130   }
00131 
00132   string description() const
00133   {
00134     return "Lets you choose a viewer";
00135   }
00136 };
00137 
00138 string ViewerSelector::app_name("ViewrSelct");
00139 
00140 
00141 ViewerManager::
00142 ViewerManager()
00143 : active_viewport_(0),
00144   vs_(0),
00145   override_active_viewport_(10000),
00146   dir_opener_(0)
00147 {
00148   setup_key_bindings();
00149 
00150   vs_.reset(new ViewerSelector(this));
00151 
00152   ViewerManager::normal_att        = CursorWindow::normal_att;
00153   ViewerManager::active_title_att  = CursorWindow::active_title_att;
00154   ViewerManager::inactive_title_att= CursorWindow::inactive_title_att;
00155   ViewerManager::active_mark_att   = CursorWindow::active_mark_att;
00156   ViewerManager::inactive_mark_att = CursorWindow::inactive_mark_att;
00157   ViewerManager::bottom_att        = CursorWindow::bottom_att;
00158   ViewerManager::highlighted_att   = CursorWindow::highlighted_att;
00159 
00160 
00161 }
00162 
00163 ViewerManager::
00164 ~ViewerManager()
00165 {
00166   // delete the viewports, then the viewers
00167 
00168   vector<viewport*>::iterator vp_next = viewports_.begin(),
00169                                              vp_last = viewports_.end();
00170 
00171   while(vp_next != vp_last)
00172   {
00173     viewport* entry = *vp_next++;
00174 
00175     delete entry;
00176 
00177   }
00178 
00179   vector<vpentry>::iterator vr_next = viewers_.begin(),
00180                                  vr_last = viewers_.end();
00181                                         
00182   while(vr_next != vr_last)
00183   {
00184     vpentry &entry = *vr_next++;
00185 
00186     delete entry.first;
00187 
00188   }
00189 
00190   // close will occur automatically when the cw_ object is destroyed.
00191 }
00192 
00193 void
00194 ViewerManager::
00195 open()
00196 {
00197   UserInfo me = UserInfo::get();
00198 
00199   FileName tooldir = me.home_dir_ + "/.tools_home";
00200 
00201   tool_dir_ = tooldir;
00202 
00203   cw_.open();
00204 }
00205 
00206 void
00207 ViewerManager::
00208 close()
00209 {
00210   cw_.close();
00211 }
00212 
00213 static bool jump2dir=false; // ^X^J means for bash to jump to a directory
00214                             // whose name is stored in ~/.tools_home/exitDir.txt
00215                             // when the program terminates.  You need a shell
00216                             // alias for edit to make this work.
00217 
00218 
00219 
00220 void
00221 ViewerManager::
00222 recordExitDir() const
00223 {
00224   if(jump2dir && exit_dir_.size())
00225   {
00226      FileName exitFileName( tool_dir_ + "/exitDir.txt" );
00227 
00228      ofstream exitFile(exitFileName.c_str());
00229 
00230      exitFile << exit_dir_ << endl;
00231   }
00232 }
00233 
00234 void
00235 ViewerManager::
00236 exit()
00237 {
00238   cw_.close();
00239 
00240   recordExitDir();
00241 
00242   ::exit(0);
00243 }
00244 
00245 
00246 void
00247 ViewerManager::
00248 add(Viewer* v, string fullname)
00249 {
00250   // a given viewer pointer can only appear in the viewers_ list once
00251   // which means the fullname is just a hint.
00252 
00253   vector<vpentry>::iterator first = viewers_.begin(),
00254                                  last = viewers_.end();
00255 
00256   while(first != last)
00257   {
00258     vpentry &entry = *first++;
00259 
00260     if(entry.first == v)
00261     {
00262        break;
00263     }
00264 
00265   }
00266 
00267   if(first == last)
00268   {
00269     // need to add a new viewer
00270 
00271     viewers_.push_back( vpentry(v, fullname) );
00272 
00273   }
00274 
00275   activate(v);  // do the magic to make it visible -- find a
00276                 // viewport to put it in.
00277 
00278 }
00279 
00280 
00281 
00282 
00283 bool
00284 ViewerManager::
00285 activate(Viewer* v)
00286 {
00287 
00288   vector<viewport*>::iterator vp_next = viewports_.begin(),
00289                               vp_last = viewports_.end();
00290 
00291   size_t count = 0;
00292 
00293   while(vp_next != vp_last)
00294   {
00295     viewport* entry = *vp_next++;
00296 
00297     repaint_handler *rh = entry->get_repaint_handler();
00298 
00299     Viewer* vp = dynamic_cast<Viewer*>(rh);
00300 
00301     if(vp == v)
00302     {
00303       // found it -- there is a viewport with this viewer in it.
00304       // make it the current viewport.
00305 
00306       entry->activate();
00307       override_active_viewport_ = count;
00308 
00309       std::string viewerName = find_viewer_name(vp);
00310 
00311       order_.activate( viewerName );
00312 
00313       return false;
00314 
00315 
00316     }
00317 
00318     ++count;
00319 
00320   }
00321 
00322   // No viewport has this viewer as its repaint_handler.
00323   // Replace the current viewer's repaint handler with this viewer
00324 
00325 
00326   vector<vpentry>::iterator vr_next = viewers_.begin(),
00327                             vr_last = viewers_.end();
00328                                         
00329   while(vr_next != vr_last)
00330   {
00331     vpentry &entry = *vr_next;
00332 
00333     if(entry.first == v)
00334       break;
00335 
00336     ++vr_next;
00337 
00338   }
00339 
00340   if(vr_next != vr_last)
00341   {
00342     // ok, viewer is valid, now replace the current viewport's repaint_handler
00343     // with the specified viewer
00344 
00345     if(active_viewport_ >= viewports_.size())
00346     {
00347       viewports_.push_back(cw_.new_viewport(v).release());
00348       active_viewport_ = viewports_.size() -1;
00349     }
00350     else
00351       viewports_[active_viewport_]->set_repaint_handler(v);
00352 
00353     viewports_[active_viewport_]->activate();
00354 
00355     repaint_handler *rh = viewports_[active_viewport_]->get_repaint_handler();
00356 
00357     Viewer* vp = dynamic_cast<Viewer*>(rh);
00358 
00359     std::string viewerName = find_viewer_name(vp);
00360 
00361     order_.activate( viewerName );
00362 
00363     return false;
00364 
00365   }
00366 
00367 
00368   return true;   // Darn, there is no such viewer.
00369 }
00370 
00371 void
00372 ViewerManager::
00373 vsplit(Viewer* v, string fullname)
00374 {
00375   // a given viewer pointer can only appear in the viewers_ list once
00376   // which means the fullname is just a hint.
00377 
00378   if(viewports_.size())
00379   {
00380      // first, make sure that this viewer is not already in the list
00381      // if it is, and it isn't displayed, display it in the bottom
00382      // half window.  If it is already displayed, make that viewport
00383      // active.
00384 
00385      size_t i;
00386 
00387      for(i=0; i < viewports_.size(); ++i)
00388      {
00389        repaint_handler *rh = viewports_[i]->get_repaint_handler();
00390 
00391        Viewer* vp = dynamic_cast<Viewer*>(rh);
00392 
00393        if(vp == v)
00394        {
00395          // already displayed
00396         
00397          viewports_[i]->activate();
00398          active_viewport_ = i;
00399          return;
00400         
00401        }
00402 
00403      }
00404 
00405      // If we get here, it means that no viewport is already displaying
00406      // this viewer.  Check to see if there is an undisplayed viewer with
00407      // this address
00408 
00409      bool found=false;
00410 
00411      for(i=0; i < viewers_.size(); ++i)
00412      {
00413         if( viewers_[i].first == v )
00414         {
00415           found = true;
00416           break;
00417         }
00418      }
00419 
00420      if(!found)
00421      {
00422        // stick this viewer in the viewer's table
00423 
00424        viewers_.push_back( vpentry(v,fullname) );
00425 
00426      }
00427 
00428 
00429      // make sure this viewer is visible in the bottom of the current
00430      // viewport's space
00431 
00432      viewports_.push_back( viewports_[active_viewport_]->vsplit(v).release() );
00433 
00434      active_viewport_ = viewports_.size()-1;
00435 
00436      viewports_[active_viewport_]->activate();
00437 
00438   }
00439 }
00440 
00441 
00442 void
00443 ViewerManager::
00444 hsplit(Viewer* v, string fullname)
00445 {
00446   // a given viewer pointer can only appear in the viewers_ list once
00447   // which means the fullname is just a hint.
00448 
00449   if(viewports_.size())
00450   {
00451      // first, make sure that this viewer is not already in the list
00452      // if it is, and it isn't displayed, display it in the right
00453      // half window.  If it is already displayed, make that viewport
00454      // active.
00455 
00456      size_t i;
00457 
00458      for(i=0; i < viewports_.size(); ++i)
00459      {
00460        repaint_handler *rh = viewports_[i]->get_repaint_handler();
00461 
00462        Viewer* vp = dynamic_cast<Viewer*>(rh);
00463 
00464        if(vp == v)
00465        {
00466          // already displayed
00467         
00468          viewports_[i]->activate();
00469          active_viewport_ = i;
00470          return;
00471         
00472        }
00473 
00474      }
00475 
00476      // If we get here, it means that no viewport is already displaying
00477      // this viewer.  Check to see if there is an undisplayed viewer with
00478      // this address
00479 
00480      bool found=false;
00481 
00482      for(i=0; i < viewers_.size(); ++i)
00483      {
00484         if( viewers_[i].first == v )
00485         {
00486           found = true;
00487           break;
00488         }
00489      }
00490 
00491      if(!found)
00492      {
00493        // stick this viewer in the viewer's table
00494 
00495        viewers_.push_back( vpentry(v,fullname) );
00496 
00497      }
00498 
00499 
00500      // make sure this viewer is visible in the right half of the current
00501      // viewport's space
00502 
00503      viewports_.push_back( viewports_[active_viewport_]->hsplit(v).release() );
00504 
00505      active_viewport_ = viewports_.size()-1;
00506 
00507      viewports_[active_viewport_]->activate();
00508 
00509   }
00510 }
00511 
00512 
00513 void
00514 ViewerManager::
00515 dispatch_event(ViewerManager::input_event const & event)
00516 {
00517    // give event to the active viewport, if any.  If the
00518    // event handler returns true, it means the viewer needs
00519    // to be deleted -- so delete it.
00520 
00521    if(viewports_.size())
00522    {
00523       viewport* port = viewports_[active_viewport_];
00524 
00525       repaint_handler* rh = port->get_repaint_handler();
00526 
00527       Viewer* r = dynamic_cast<Viewer*>(rh);
00528 
00529       if(r->handle_event(&event, port))
00530       {
00531         std::string viewerName = find_viewer_name(r);
00532 
00533         order_.discard(viewerName);
00534 
00535         // first, close the viewport holding this viewer
00536         
00537         viewports_.erase( viewports_.begin() + active_viewport_ );
00538         
00539         delete port; // say goodnight dorothy, kansas just went bye bye
00540         
00541         // next remove the viewer from the viewer's list
00542         
00543         for(size_t i = 0; i < viewers_.size(); ++i)
00544         {
00545           if( viewers_[i].first == r )
00546           {
00547             viewers_.erase(viewers_.begin() + i );
00548             break;
00549           }
00550         }
00551 
00552         if(r != vs_.get())
00553         {
00554           // unless the viewer was the 'viewer selector', delete
00555           // the viewer.  The viewer selector hangs around forever...
00556         
00557           delete r;
00558         }
00559         
00560         if(viewers_.size() == 0)
00561         {
00562             exit();
00563         }
00564         else
00565         if(viewports_.size() == 0)
00566         {       
00567           // here we have lost our viewports but still have
00568           // some viewers hanging around (other than the
00569           // viewer selector which is handled as a special case
00570           // and never appears in the viewers_ array.
00571         
00572           active_viewport_ = 0;
00573         
00574           size_t youngest_viewer = viewers_.size() -1;
00575 
00576           MRU<std::string>::iterator mruPtr = order_.mostRecent();
00577 
00578           if(mruPtr != order_.end())
00579           {
00580              std::string mru = *mruPtr;
00581 
00582              for(size_t i = 0; i < viewers_.size(); ++i)
00583              {
00584                  if(mru == viewers_[i].second)
00585                  {
00586                     youngest_viewer = i;
00587                     break;
00588                  }
00589              }
00590 
00591           }
00592 
00593         
00594           viewports_.push_back(cw_.new_viewport
00595                                  ( viewers_[youngest_viewer].first ).release()
00596                               );
00597 
00598           viewports_[0]->activate();
00599         
00600         }
00601         
00602         if(override_active_viewport_ < viewports_.size())
00603         {
00604           // Handle an odd case in the appChooser::handle_event
00605           // where you choose viewer that already exists
00606           // and the 'active_viewport' causes a crash.
00607         
00608         
00609           active_viewport_ = override_active_viewport_;
00610         
00611           override_active_viewport_ = 10000;
00612         }
00613 
00614         
00615         if(active_viewport_ >= viewports_.size() )
00616         {
00617           active_viewport_ = viewports_.size() -1 ;
00618         }
00619 
00620 
00621         
00622         if( (int)(active_viewport_) < 0)
00623           active_viewport_ = 0;
00624 
00625         if(viewports_.size())
00626           viewports_[active_viewport_]->activate();
00627         
00628       }
00629       else
00630       {
00631         if(override_active_viewport_ < viewports_.size())
00632         {
00633           active_viewport_ = override_active_viewport_;
00634           override_active_viewport_ = 10000;
00635         
00636         }
00637       }
00638 
00639    }
00640 }
00641 
00642 list<string> ViewerManager::key_bindings_doc;
00643 
00644 void
00645 ViewerManager::
00646 setup_key_bindings()
00647 {
00648    // All view related master key bindings begin with ^V.
00649 
00650    master_key_map::sequence adder(master_keys_, new_application);
00651                             adder += 'X' - '@';  // ^X
00652                             adder += 'N' - '@';  // ^N
00653                             adder.complete();
00654    key_bindings_doc.push_back("^X ^N -- new application covering current viewer");
00655 
00656    master_key_map::sequence sheller(master_keys_, interactive_shell);
00657                             sheller += 'X' - '@';  // ^X
00658                             sheller += 'Z' - '@';  // ^Z
00659                             sheller.complete();
00660    key_bindings_doc.push_back("^X ^Z -- bring up an interactive shell");
00661 
00662 
00663    master_key_map::sequence addeditor(master_keys_, new_editor);
00664                             addeditor += 'X' - '@';  // ^X
00665                             addeditor += 'F' - '@';  // ^F
00666                             addeditor.complete();
00667    key_bindings_doc.push_back("^X ^F -- new editor covering current viewer");
00668 
00669    master_key_map::sequence addviewer(master_keys_, new_viewer);
00670                             addviewer += 'X' - '@';  // ^X
00671                             addviewer += 'V' - '@';  // ^V
00672                             addviewer.complete();
00673    key_bindings_doc.push_back("^X ^V -- new viewer covering current viewer");
00674 
00675    master_key_map::sequence vsplitter(master_keys_, horizontal_split);
00676                             vsplitter += 'X' - '@';  // ^X
00677                             vsplitter += '3';        // 3
00678                             vsplitter.complete();
00679    key_bindings_doc.push_back("^X ^3 -- split viewer horizontally");
00680                         
00681    master_key_map::sequence hsplitter(master_keys_, vertical_split);
00682                             hsplitter += 'X' - '@';  // ^X
00683                             hsplitter += '2';        // 2
00684                             hsplitter.complete();
00685    key_bindings_doc.push_back("^X ^2 -- split viewer vertically");
00686                         
00687    master_key_map::sequence unsplitter(master_keys_, unsplit);
00688                             unsplitter += 'X' - '@';  // ^X
00689                             unsplitter += '1';        // 1
00690                             unsplitter.complete();
00691    key_bindings_doc.push_back("^X ^1 -- unify screen (hide all but one viewer)");
00692                         
00693    master_key_map::sequence nexter(master_keys_, next);
00694                             nexter += 'X' - '@';  // ^X
00695                             nexter += 'o';        //  o
00696                             nexter.complete();
00697    key_bindings_doc.push_back("^X  o -- switch windows");
00698 
00699    master_key_map::sequence nexter1(master_keys_, next);
00700                             nexter1 += CursorWindow::key_f2;  // F2
00701                             nexter1.complete();
00702    key_bindings_doc.push_back("F2    -- switch windows");
00703                 
00704    master_key_map::sequence helper(master_keys_, display_help);
00705                             helper += CursorWindow::key_f1;  // F1
00706                             helper.complete();
00707    key_bindings_doc.push_back("F1    -- get help");
00708 
00709                 
00710 //    master_key_map::sequence helper2(master_keys_, display_help);
00711 //                             helper2 += 'H' - '@';  // ^H
00712 //                             helper2.complete();
00713 //    key_bindings_doc.push_back("^H    -- get help");
00714                 
00715    master_key_map::sequence helper1(master_keys_, display_help);
00716                             helper1 += 'X' - '@';  // ^X
00717                             helper1 += 'H' - '@';  // ^H
00718                             helper1.complete();
00719    key_bindings_doc.push_back("^X ^H -- get help");
00720                 
00721    master_key_map::sequence buffers(master_keys_, selector);
00722                             buffers += 'X' - '@';  // ^X
00723                             buffers += 'B' - '@';  // ^B
00724                             buffers.complete();
00725    key_bindings_doc.push_back("^X ^B -- select viewer from list");
00726                         
00727    master_key_map::sequence killer(master_keys_, die);
00728                             killer += 'X' - '@';  // ^X
00729                             killer += 'C' - '@';  // ^C
00730                             killer.complete();
00731    key_bindings_doc.push_back("^X ^C -- close all viewers and quit");
00732 
00733    master_key_map::sequence kill_and_jumper(master_keys_, die_and_jump);
00734                             kill_and_jumper += 'X' - '@';  // ^X
00735                             kill_and_jumper += 'J' - '@';  // ^J
00736                             kill_and_jumper.complete();
00737    key_bindings_doc.push_back("^X ^J -- same as ^C but leave curdir in ~/.tools_home/exitDir.txt");
00738 
00739                         
00740 }
00741 
00742 class appChooser
00743 : public Viewer
00744 {
00745 public:
00746 
00759 
00760   size_t display_top_;
00761   size_t cur_row_;
00762   int    first_row_;
00763   bool   active_;
00764 
00765   appChooser(ViewerManager* vm)
00766   : Viewer(vm),
00767     display_top_(0),
00768     cur_row_(0),
00769     first_row_(2),
00770     active_(true)
00771   {
00772   }
00773 
00774 
00775   void operator() ( CursorWindow::viewport * vp,int cmd);
00777 
00778   bool handle_event( CursorWindow::input_event const * e,
00779                      CursorWindow::viewport          * vp
00780                    );
00781 
00782   void repaint(CursorWindow::viewport *vp)
00783   {
00784      (*this)(vp, activate );
00785   }
00786 
00787   void output_row_text(CursorWindow::viewport * vp, int i)
00788   {
00789     // do not set the text attributes here!
00790 
00791     if( (size_t) i < manager_->apps_.size() )
00792       *vp << manager_->apps_[i].second
00793           ;
00794   }
00795 
00796   static string app_name;
00797 
00798   string const& application_name() const { return app_name; }
00799 
00800   string description() const 
00801   {
00802     return "lets you run a new application";
00803   }
00804 };
00805 
00806 string appChooser::app_name("AppChooser");
00807 
00808 void
00809 ViewerManager::
00810 handle_master_command(int cmd)
00811 {
00812   // a master command is a command that involves window control.  Master
00813   // commands are handled directly by the viewer manager and are not sent to
00814   // individual viewers.
00815 
00816   switch(cmd)
00817   {
00818     //case vertical_split  :  vsplit(new appChooser(this), "appChooser"); return;
00819     //case horizontal_split:  hsplit(new appChooser(this), "appChooser"); return;
00820 
00821     case vertical_split  :  splitscreen_new_editor(false); return;
00822     case horizontal_split:  splitscreen_new_editor(true); return;
00823 
00824     case unsplit         :  unify();  return;
00825     case selector        :  vs(); return;
00826     case die             :  jump2dir=false; exit_dir_="" ; handle_die_request(); return;
00827     case die_and_jump    :  jump2dir=true;  exit_dir_="" ; handle_die_request(); return;
00828     case new_application :  add(new appChooser(this), "appchooser"); return;
00829     case new_viewer      :  popup_new_viewer(); return;
00830     case new_editor      :  popup_new_viewer(true); return;
00831 
00832     case next            :  {
00833                               if(viewports_.size() > 1)
00834                               {
00835                                 // there are more than one viewports
00836                                 // then 'switch windows' means to move
00837                                 // to another visible viewport.  Basically
00838                                 // it means moving to the created most
00839                                 // recently before this one
00840                                 
00841                                 if(active_viewport_)
00842                                   --active_viewport_;
00843                                 else
00844                                   active_viewport_ = viewports_.size() -1;
00845                                 
00846                                 viewports_[active_viewport_]->activate();
00847 
00848                                 // after activating the viewport, which repaints it, flag the
00849                                 // fullname associated withe the viewer as being the most recently
00850                                 // used.
00851 
00852                                 repaint_handler *rh =  viewports_[active_viewport_]->get_repaint_handler();
00853                                 Viewer          *active = dynamic_cast<Viewer*>(rh);
00854 
00855                                 for(size_t i = 0; i < viewers_.size(); ++i)
00856                                 {
00857                                     if(viewers_[i].first == active)
00858                                     {
00859                                         order_.activate(viewers_[i].second);
00860                                         break;
00861                                     }
00862                                 }
00863 
00864 
00865                               }
00866                               else
00867                               if(viewers_.size() > 1)
00868                               {
00869                                 // if only one viewport is visible, switch
00870                                 // out the viewer currently being shown.  So
00871                                 // find a viewer which was created earlier
00872                                 // than the one currently active viewer.
00873                                 //
00874                                 
00875                                 Viewer* v = active_viewer();
00876                                 
00877                                 size_t i;
00878                                 
00879                                 for(i=0; i < viewers_.size(); ++i)
00880                                 {
00881                                   if(viewers_[i].first == v)
00882                                   {
00883                                     break;
00884                                   }
00885                                 }
00886                                 
00887                                 if(i == 0)
00888                                   i = viewers_.size() -1;
00889                                 else
00890                                   --i;
00891                                 
00892                                 activate(viewers_[i].first);
00893 
00894 
00895                                 order_.activate(viewers_[i].second);
00896                                 
00897                               }
00898                               return;
00899                             }
00900     case display_help    :  help(); return;
00901 
00902     case interactive_shell:
00903                           {
00904                             row_col old_size;
00905                             row_col new_size;
00906 
00907                             int err;
00908                         
00909                             old_size = window()->size();
00910                             window()->close();
00911                         
00912                             string curdir = active_directory();
00913                             char old_dir[2000];
00914 
00915                             if( 0 == getcwd(old_dir, sizeof(old_dir)) )
00916                                old_dir[0] = 0;
00917                         
00918                             err = chdir(curdir.c_str());
00919                         
00920                             printf("Current directory is: ");
00921                             fflush(stdout);
00922                             err = system("pwd");
00923 
00924                             Viewer* av = active_viewer();
00925 
00926                                     
00927                         
00928 #ifndef _MSC_VER
00929 // unix
00930                             printf("\nThe file or directory you are working on is:\n  %s\n", 
00931                                      av?av->description().c_str():""
00932                                   );
00933                             printf("Starting your shell.  Please use 'exit' to return\n");
00934                             err = fflush(stdout);
00935                             {
00936                               char const *bash = getenv("BASH");
00937                         
00938                               if(bash)
00939                                 err = system("bash -i");
00940                               else
00941                                 err = system("/bin/sh -i");
00942                         
00943                             }
00944 #else
00945 // windows
00946                                   
00947                            err = system("cmd /c cls");
00948                             printf("\nThe file or directory you are working on is:\n  %s\n", 
00949                                      av?av->description().c_str():""
00950                                   );
00951                             printf("Starting CMD.EXE.  Please use 'exit' to return\n");
00952                            err = fflush(stdout);
00953                            err = system("cmd");
00954 #endif
00955 
00956                             err =chdir(old_dir);
00957 
00958                             window()->open();
00959                             new_size = window()->size();
00960                             window()->resize_viewports(old_size, new_size);
00961                         
00962                             (void)(err);
00963                           }
00964                           return;
00965 
00966   }
00967 }
00968 
00969 void
00970 ViewerManager::
00971 run()
00972 {
00973    // Prompt the user for input and handle his commands.  This may mean
00974    // direct interpretation of system level commands here or it may mean
00975    // directing keystrokes to the various command handlers in the viewers.
00976 
00977    if(viewports_.size() == 0)
00978    {
00979      Viewer* chooser = new appChooser(this);
00980 
00981      viewers_.push_back( vpentry(chooser, "appChooser") );
00982 
00983      viewports_.push_back( cw_.new_viewport(chooser).release() );
00984 
00985      viewports_.back()->activate();
00986    }
00987 
00988    CursorWindow::input_event e;
00989 
00990    //
00991    //  The run command lets the user enter keys.  It interprets patterns
00992    //  in these keys.  When a pattern is not recognized, it sends all the
00993    //  keys to the active viewport and goes back to the main input state.
00994    //
00995 
00996    for(;;)
00997    {
00998       // forever do:  read keys and intepret them
00999 
01000       // start of loop assumes we have no partial key pattern yet
01001 
01002       e = cw_.read_input();
01003 
01004       if(e.type_ != CursorWindow::input_event::DataKey &&
01005          e.type_ != CursorWindow::input_event::FunctionKey
01006         )
01007       {
01008         continue;  // fix this later, should be dispatching the
01009       }
01010 
01011       // we have just read a key
01012 
01013       master_key_map::search s(master_keys_);
01014 
01015       int possible_cmd;
01016 
01017       if(!s(e.value_))
01018       {
01019          // nope, this is not the first key of a pattern
01020         
01021          dispatch_event(e);
01022         
01023       }
01024       else
01025       if( (++s, s.finished(&possible_cmd) ) )
01026       {
01027         // handle the case of one character command sequences
01028         
01029         handle_master_command(possible_cmd);
01030       }
01031       else
01032       {
01033         // this is possibly the first key in a pattern -- read until
01034         // we find a pattern or if we don't.  If we don't, then send
01035         // send all the keys to the active viewport.  If we do, use
01036         // the pattern ourselves.
01037         
01038         vector<input_event> l;
01039 
01040         l.push_back(e);
01041         
01042         for(;;)
01043         {
01044           // read until sequence complete or invalid
01045         
01046           e = cw_.read_input();
01047         
01048           if(e.type_ != input_event::FunctionKey &&
01049              e.type_ != input_event::DataKey
01050             )
01051           {
01052             // something weird going on -- give all the keys to the
01053             // currently active viewer
01054         
01055             size_t i = 0;
01056         
01057             for(i=0; i < l.size(); ++i)
01058               dispatch_event(l[i]);
01059         
01060             dispatch_event(e);
01061         
01062             break;
01063           }
01064           else
01065           if(s(e.value_))
01066           {
01067             // this is a valid member of a sequence
01068 
01069             l.push_back(e);
01070 
01071             ++s;
01072         
01073             int id;
01074 
01075             if(s.finished(&id))
01076             {
01077                handle_master_command(id);
01078                break;
01079             }
01080 
01081           }
01082           else
01083           {
01084             // This new key ends the sequence
01085         
01086             size_t i = 0;
01087         
01088             for(i=0; i < l.size(); ++i)
01089               dispatch_event(l[i]);
01090         
01091             dispatch_event(e);
01092 
01093             break;
01094           }
01095         
01096         }
01097       }
01098    }
01099 }
01100 
01101 
01102 
01103 
01104 void
01105 ViewerManager::
01106 unify()
01107 {
01108   // close all viewports but the currently active viewport and
01109   // give it full screen
01110 
01111   Viewer *viewer = dynamic_cast<Viewer*>
01112                        (viewports_[active_viewport_]->get_repaint_handler());
01113 
01114   size_t i;
01115 
01116   for(i = 0; i < viewports_.size(); ++i)
01117   {
01118      delete viewports_[i];
01119   }
01120 
01121   viewports_.erase(viewports_.begin(), viewports_.end());
01122 
01123   active_viewport_ = 0;
01124 
01125   viewports_.push_back(cw_.new_viewport(viewer).release());
01126 
01127   viewports_[active_viewport_]->activate();
01128 
01129 }
01130 
01131 
01132 void
01133 ViewerManager::
01134 vs()
01135 {
01136   // replace the viewer in the current viewport with the viewer
01137   // selector viewer.
01138 
01139   //
01140   // make sure the viewer selector is not already up -- if it is,
01141   // make it the active viewport
01142   //
01143   size_t i;
01144 
01145   for(i=0; i < viewports_.size(); ++i)
01146   {
01147     repaint_handler* rh = viewports_[i]->get_repaint_handler();
01148     Viewer*          vp = dynamic_cast<Viewer*>(rh);
01149 
01150     if(vp == vs_.get())
01151     {
01152       active_viewport_ = i;
01153       viewports_[i]->activate();
01154       return;
01155     }
01156   }
01157 
01158   // ok, if we get here it means that the viewer selector is not up
01159   // so replace the viewer in the current viewport
01160 
01161   if(viewports_.size())
01162   {
01163     viewports_[active_viewport_]->set_repaint_handler(vs_.get());
01164     viewports_[active_viewport_]->activate();
01165     return;
01166   }
01167 
01168   // if we get here, it means there are no viewports.  This shouldn't
01169   // happen and it is harmless to ignore this case.
01170 
01171   return;
01172 
01173 }
01174 
01175 
01176 void
01177 ViewerSelector::
01178 operator() ( CursorWindow::viewport * vp,int cmd)
01179 {
01180   // WARNING:  do not save vp -- it gets deleted regularly!
01181 
01182   // Handle screen repaint commands
01183 
01184   size_t  viewers = manager_->viewers_.size();
01185   row_col vpsize  = vp->size();
01186   row_col vporigin= vp->origin();
01187 
01188   if(cmd == CursorWindow::viewport::repaint_handler::activate)
01189     active_=true;
01190   else
01191   if(cmd == CursorWindow::viewport::repaint_handler::deactivate)
01192     active_=false;
01193 
01194   int left = 0;
01195 
01196   if(vporigin.col_)  ++left;  // if not left most viewer, add a 1 char bias
01197 
01198   // erase the viewport -- and underline the bottom line and the left
01199   // if necessary
01200 
01201   vp->set_text_attribute(ViewerManager::normal_att);
01202 
01203   vp->set_curpos(0,0);
01204   vp->fill_to_eos();
01205 
01206   if(left)
01207   {
01208     for(int i = 0; i < vpsize.row_; ++i)
01209     {
01210       vp->set_curpos(i, 0);
01211 
01212       // vp->write('|');
01213 
01214       using namespace CursesInterface;
01215 
01216       vp->write(line_chars[VL_MIDDLE]);
01217     }
01218   }
01219 
01220   vp->set_curpos(vpsize.row_-1, left);
01221   vp->set_text_attribute(ViewerManager::bottom_att);
01222   vp->fill_to_eol();
01223 
01224   // display the title line highlighted based on active' flag
01225   // for this paint request
01226 
01227   vp->set_curpos(0,left);
01228   if(active_)
01229     vp->set_text_attribute(ViewerManager::active_title_att);
01230   else
01231     vp->set_text_attribute(ViewerManager::inactive_title_att);
01232 
01233   *vp << "Select one of " << viewers << " viewers";
01234   vp->fill_to_eol();
01235 
01236   // Draw the body of the window by representing each viewer
01237   // on one line of the display.  The viewer's address and shortname
01238   // and as much of the full name is presented as possible.
01239 
01240   // The display_top_ member indicates which row of the display is to
01241   // appear as the first entry in the vertical list of viewers
01242   // and the cur_row_ indicates which row the cursor is sitting on
01243 
01244 
01245   int row = first_row_;  // actual physical row where display occurs
01246 
01247   for(size_t  i = display_top_;
01248       row < vpsize.row_ && i < viewers;
01249       ++i, ++row
01250      )
01251   {
01252 
01253     vp->set_text_attribute(ViewerManager::normal_att); // set to normal atts
01254 
01255     if(row == vpsize.row_-1 && i != cur_row_)
01256     {
01257       vp->set_text_attribute(ViewerManager::bottom_att);
01258     }
01259     else
01260     if(i == cur_row_)
01261     {
01262       // highlight the current row by making it reversed video
01263 
01264       vp->set_curpos(row, left);
01265       vp->set_text_attribute(active_ ? ViewerManager::highlighted_att
01266                                      : ViewerManager::inactive_mark_att
01267                             );
01268       vp->fill_to_eol();
01269 
01270       // leave the text attributes as reversed
01271     }
01272 
01273     vp->set_curpos(row, 2+left);
01274 
01275     output_row_text(vp, i);
01276 
01277   }
01278 
01279   vp->set_text_attribute(ViewerManager::normal_att); // set to normal atts
01280 
01281   vp->set_curpos(first_row_ + cur_row_ - display_top_,left);
01282                           // leave cursor on current line of scrolling display
01283 
01284 }
01285 
01286 bool
01287 ViewerSelector::
01288 handle_event( CursorWindow::input_event const * e,
01289               CursorWindow::viewport          * vp
01290             )
01291 {
01292   //
01293   //  The ViewerSelector event handler lets you select a viewer
01294   //  and make the 'active'.
01295   //
01296 
01297    if(e->type_ == CursorWindow::input_event::ForceExitKey)
01298      return true; // terminate the window
01299 
01300 
01301    if(e->type_ != CursorWindow::input_event::DataKey &&
01302       e->type_ != CursorWindow::input_event::FunctionKey
01303      )
01304      return false;
01305 
01306    // unhighlight the current line to be ready for a line
01307    // change
01308 
01309    int     row      = first_row_ + (cur_row_ - display_top_); // screen row
01310    row_col size     = vp->size();
01311    row_col vporigin = vp->origin();
01312 
01313    int bottom_row   = size.row_ - first_row_ - 1;
01314 
01315    int left = 0;
01316 
01317    if(vporigin.col_)  ++left;  // if not left most viewer, add a 1 char bias
01318 
01319    vp->set_curpos(row,left);
01320    vp->set_text_attribute(row == bottom_row ? ViewerManager::bottom_att
01321                                             : ViewerManager::normal_att);
01322 
01323    *vp << "  ";
01324 
01325    output_row_text(vp, cur_row_);
01326 
01327    vp->fill_to_eol();
01328 
01329    int edit_func = vp->window()->func[e->value_];
01330 
01331    switch(edit_func)
01332    {
01333      case CursorWindow::func_top:
01334        row = first_row_;
01335        cur_row_ = 0;
01336        display_top_ = 0;
01337        vp->activate();
01338        break;
01339 
01340      case CursorWindow::func_bottom:
01341        row = first_row_;
01342        cur_row_ = manager_->viewers_.size()-1;
01343 
01344        if( (int) cur_row_ < 0)
01345          cur_row_ = 0;
01346         
01347        display_top_ = cur_row_;
01348        vp->activate();
01349        break;
01350 
01351      case CursorWindow::func_up:
01352 
01353        // move the cursor up one line and handle paging issues
01354 
01355        if(row == first_row_)
01356        {
01357          if(cur_row_ > 0)
01358          {
01359            // step up a row
01360         
01361            int page_length = size.row_ - first_row_;
01362         
01363            display_top_ -= page_length;
01364         
01365            if( (int) display_top_ < 0)
01366              display_top_ = 0;
01367         
01368            cur_row_ = display_top_ + page_length-1;
01369         
01370            if(cur_row_ >= manager_->viewers_.size())
01371            {
01372              cur_row_ = manager_->viewers_.size() -1;
01373            }
01374         
01375            if( (int)(cur_row_) < 0 )
01376              cur_row_ = 0;
01377         
01378            row = first_row_ + (cur_row_ - display_top_);
01379         
01380            repaint(vp);
01381          }
01382        }
01383        else
01384        {
01385          --row;
01386          --cur_row_;
01387        }
01388 
01389        break;
01390      case CursorWindow::func_down:
01391 
01392        // move the cursor down one line and handle paging issues
01393 
01394        if(row == size.row_ - 1)
01395        {
01396          // at bottom of current viewport
01397          // page forward
01398         
01399          row = first_row_;
01400 
01401          display_top_  += size.row_ - first_row_;
01402         
01403          if( (int)(display_top_) >= (int)(manager_->viewers_.size()))
01404          {
01405            display_top_ -= size.row_ - first_row_ -1;
01406         
01407            if( ((int)display_top_) < 0 )
01408              display_top_ = 0;
01409          }
01410         
01411          cur_row_ = display_top_;
01412         
01413         repaint(vp);
01414         
01415        }
01416        else
01417        {
01418          // not at bottom of viewport
01419         
01420          if(cur_row_ < manager_->viewers_.size()-1)
01421          {
01422            ++row;
01423            ++cur_row_;
01424          }
01425        }
01426        break;
01427      case CursorWindow::func_prior:
01428 
01429        // move the cursor back one page and handle paging issues
01430 
01431        display_top_ -= size.row_ - first_row_;
01432 
01433        if( (int)(display_top_) < 0)
01434          display_top_ = 0;
01435         
01436        cur_row_ = display_top_;
01437 
01438        row = first_row_;
01439 
01440        repaint(vp);
01441 
01442        break;
01443 
01444      case CursorWindow::func_next:
01445 
01446        // move the cursor forward one page and handle paging issues
01447 
01448        display_top_ += size.row_ - first_row_;
01449 
01450        if( (int)(display_top_) >= (int)manager_->viewers_.size() )
01451          display_top_ = manager_->viewers_.size()-1;
01452         
01453        if( (int)(display_top_) < 0 )
01454          display_top_ = 0;
01455         
01456        cur_row_ = display_top_;
01457 
01458        row = first_row_;
01459 
01460        repaint(vp);
01461 
01462        break;
01463 
01464      case CursorWindow::func_clreol:  // ^K
01465        goto undisplay_viewer_selector;
01466 
01467      case CursorWindow::func_enter:
01468 
01469        // Activate the viewer indicated by the current line onto
01470        // the screen.  If there is no viewport currently showing
01471        // that viewerr, replace the viewer in the current viewport
01472        // with the selected viewer (displacing the viewer selector).
01473        {
01474           Viewer* selectee = manager_->viewers_[cur_row_].first;
01475 
01476           manager_->order_.activate( manager_->viewers_[cur_row_].second );
01477         
01478           vector<viewport*> &viewports_ = manager_->viewports_;
01479         
01480           size_t i;
01481         
01482           bool found=false;
01483         
01484           for(i = 0; i < viewports_.size(); ++i)
01485           {
01486             repaint_handler *rh =  viewports_[i]->get_repaint_handler();
01487         
01488             Viewer* vp = dynamic_cast<Viewer*>(rh);
01489         
01490             if(vp == selectee)
01491             {
01492 
01493               viewports_[i]->activate();
01494               manager_->active_viewport_ = i;
01495               found = true;
01496               return false;
01497             }
01498           }
01499         
01500           if(!found)
01501           {
01502             // no viewport is currently showing the viewer --
01503             // give it the space used by this viewer selector
01504         
01505             viewports_[manager_->active_viewport_]->set_repaint_handler(selectee);
01506             viewports_[manager_->active_viewport_]->activate();
01507         
01508             return false;
01509         
01510           }
01511         
01512        }
01513        break;
01514 
01515      case CursorWindow::func_data:
01516        switch(e->value_)
01517        {
01518          case 'q':  // undisplay the viewer selector
01519            {
01520 undisplay_viewer_selector:
01521         
01522         
01523              size_t &active_viewport_ = manager_->active_viewport_;
01524         
01525              vector<CursorWindow::viewport*> &viewports_ = manager_->viewports_;
01526         
01527              delete viewports_[active_viewport_];
01528 
01529              viewports_.erase(viewports_.begin() + active_viewport_);
01530         
01531              if(active_viewport_ >= viewports_.size())
01532                active_viewport_ = viewports_.size() -1 ;
01533         
01534              if( ((int)active_viewport_) < 0 )
01535                active_viewport_ = 0;
01536         
01537              if( viewports_.size() )
01538              {
01539                viewports_[active_viewport_]->activate();
01540              }
01541              else
01542              {
01543                vector<ViewerManager::vpentry> &viewers_ =
01544                                                             manager_->viewers_;
01545         
01546                if( viewers_.size() == 0 ||
01547                     (
01548                       viewers_.size() == 1 &&
01549                       viewers_[0].first == this
01550                     )
01551                  )
01552                  manager_->exit();  // either no viewers left or only the viewer selector
01553                else
01554                  viewports_.push_back(manager_->
01555                                          cw_.new_viewport(viewers_[0].first).release());
01556                 
01557                viewports_[0]->activate();
01558                 
01559              }
01560         
01561              return false;
01562            }
01563            break;
01564        }
01565        break;
01566 
01567 
01568    }
01569 
01570    // now, highlight the appropriate line
01571 
01572    vp->set_curpos(row,left);
01573    vp->set_text_attribute(ViewerManager::highlighted_att);
01574 
01575    *vp << "  ";
01576 
01577    output_row_text(vp, cur_row_);
01578 
01579    vp->fill_to_eol();
01580 
01581    vp->set_curpos(row,left);
01582    vp->set_text_attribute(row == bottom_row ? ViewerManager::bottom_att
01583                                             : ViewerManager::normal_att);
01584 
01585    return false;
01586 }
01587 
01589 
01590 
01591 void
01592 appChooser::
01593 operator() ( CursorWindow::viewport * vp,int cmd)
01594 {
01595   // WARNING:  do not save vp -- it gets deleted regularly!
01596 
01597   // Handle screen repaint commands
01598 
01599   if(cmd == CursorWindow::viewport::repaint_handler::activate)
01600     active_ = true;
01601   else
01602   if(cmd == CursorWindow::viewport::repaint_handler::deactivate)
01603     active_ = false;
01604 
01605   size_t  apps = manager_->apps_.size();
01606   row_col vpsize  = vp->size();
01607   row_col vporigin= vp->origin();
01608 
01609   int left = 0;
01610 
01611   if(vporigin.col_)  ++left;  // if not left most viewer, add a 1 char bias
01612 
01613   // erase the viewport -- and underline the bottom line
01614   vp->set_text_attribute(ViewerManager::normal_att);
01615   vp->set_curpos(0,0);
01616   vp->fill_to_eos();
01617 
01618   if(left)
01619   {
01620     for(int i = 0; i < vpsize.row_; ++i)
01621     {
01622       vp->set_curpos(i, 0);
01623 
01624       using namespace CursesInterface;
01625 
01626       vp->write(line_chars[VL_MIDDLE]);
01627     }
01628   }
01629 
01630 
01631   vp->set_curpos(vpsize.row_-1, left);
01632   vp->set_text_attribute(ViewerManager::bottom_att);
01633   vp->fill_to_eol();
01634 
01635   // display the title line highlighted based on active' flag
01636   // for this paint request
01637 
01638   vp->set_curpos(0,left);
01639 
01640   if(active_)
01641     vp->set_text_attribute(ViewerManager::active_title_att);
01642   else
01643     vp->set_text_attribute(ViewerManager::inactive_title_att);
01644 
01645   *vp << "Select one of " << apps << " applications";
01646   vp->fill_to_eol();
01647 
01648   // Draw the body of the window by representing each application
01649   // on one line of the display.  The application's address and shortname
01650   // and as much of the full name is presented as possible.
01651 
01652   // The display_top_ member indicates which row of the display is to
01653   // appear as the first entry in the vertical list of apps
01654   // and the cur_row_ indicates which row the cursor is sitting on
01655 
01656 
01657   int row = first_row_;  // actual physical row where display occurs
01658 
01659   for(size_t  i = display_top_;
01660       row < vpsize.row_ && i < apps;
01661       ++i, ++row
01662      )
01663   {
01664 
01665     vp->set_text_attribute(ViewerManager::normal_att); // set to normal atts
01666 
01667     if(row == vpsize.row_-1 && i != cur_row_)
01668     {
01669       vp->set_text_attribute(ViewerManager::bottom_att);
01670     }
01671     else
01672     if(i == cur_row_)
01673     {
01674       // highlight the current row by making it reversed video
01675 
01676       vp->set_curpos(row, left);
01677       vp->set_text_attribute(ViewerManager::highlighted_att);
01678       vp->fill_to_eol();
01679 
01680       // leave the text attributes as reversed
01681     }
01682 
01683     vp->set_curpos(row, 2+left);
01684 
01685     output_row_text(vp, i);
01686 
01687   }
01688 
01689   vp->set_text_attribute(ViewerManager::normal_att); // set to normal atts
01690 
01691   vp->set_curpos(first_row_ + cur_row_ - display_top_,left);
01692                           // leave cursor on current line of scrolling display
01693 
01694 }
01695 
01696 bool
01697 appChooser::
01698 handle_event( CursorWindow::input_event const * e,
01699               CursorWindow::viewport          * vp
01700             )
01701 {
01702   //
01703   //  The appChooser event handler lets you select a application
01704   //  replace the chooser with that application in the same viewport.
01705   //
01706 
01707    if(e->type_ == CursorWindow::input_event::ForceExitKey)
01708      return true;
01709 
01710    if(e->type_ != CursorWindow::input_event::DataKey &&
01711       e->type_ != CursorWindow::input_event::FunctionKey
01712      )
01713      return false;
01714 
01715    if(manager_->apps_.size() == 0)
01716      return true;
01717 
01718    // unhighlight the current line to be ready for a line
01719    // change
01720 
01721    int     row  = first_row_ + (cur_row_ - display_top_); // screen row
01722    row_col size = vp->size();
01723    row_col vporigin= vp->origin();
01724 
01725    int left = 0;
01726 
01727    if(vporigin.col_)  ++left;  // if not left most viewer, add a 1 char bias
01728 
01729    vp->set_curpos(row,left);
01730    vp->set_text_attribute(ViewerManager::normal_att);
01731 
01732    *vp << "  ";
01733 
01734    output_row_text(vp, cur_row_);
01735 
01736    vp->fill_to_eol();
01737 
01738    int edit_func = vp->window()->func[e->value_];
01739 
01740    switch(edit_func)
01741    {
01742      case CursorWindow::func_top:
01743        row = first_row_;
01744        cur_row_ = 0;
01745        display_top_ = 0;
01746        vp->activate();
01747        break;
01748 
01749      case CursorWindow::func_bottom:
01750        row = first_row_;
01751        cur_row_ = manager_->viewers_.size()-1;
01752 
01753        if( (int) cur_row_ < 0)
01754          cur_row_ = 0;
01755         
01756        display_top_ = cur_row_;
01757        vp->activate();
01758        break;
01759      case CursorWindow::func_up:
01760 
01761        // move the cursor up one line and handle paging issues
01762 
01763        if(row == first_row_)
01764        {
01765          if(cur_row_ > 0)
01766          {
01767            // step up a row
01768         
01769            int page_length = size.row_ - first_row_;
01770         
01771            display_top_ -= page_length;
01772         
01773            if( (int) display_top_ < 0)
01774              display_top_ = 0;
01775         
01776            cur_row_ = display_top_ + page_length-1;
01777         
01778            if(cur_row_ >= manager_->apps_.size())
01779            {
01780              cur_row_ = manager_->apps_.size() -1;
01781            }
01782         
01783            if( (int)(cur_row_) < 0 )
01784              cur_row_ = 0;
01785         
01786            row = first_row_ + (cur_row_ - display_top_);
01787         
01788            repaint(vp);
01789         
01790          }
01791        }
01792        else
01793        {
01794          --row;
01795          --cur_row_;
01796        }
01797 
01798        break;
01799      case CursorWindow::func_down:
01800 
01801        // move the cursor down one line and handle paging issues
01802 
01803        if(row == size.row_ - 1)
01804        {
01805          // at bottom of current viewport
01806          // page forward
01807         
01808          row = first_row_;
01809 
01810          display_top_  += size.row_ - first_row_;
01811         
01812          if( (int)(display_top_) >= (int)(manager_->apps_.size()))
01813          {
01814            display_top_ -= size.row_ - first_row_ -1;
01815         
01816            if( ((int)display_top_) < 0 )
01817              display_top_ = 0;
01818          }
01819         
01820          cur_row_ = display_top_;
01821         
01822         repaint(vp);
01823         
01824        }
01825        else
01826        {
01827          // not at bottom of viewport
01828         
01829          if(cur_row_ < manager_->apps_.size()-1)
01830          {
01831            ++row;
01832            ++cur_row_;
01833          }
01834        }
01835        break;
01836      case CursorWindow::func_prior:
01837 
01838        // move the cursor back one page and handle paging issues
01839 
01840        display_top_ -= size.row_ - first_row_;
01841 
01842        if( (int)(display_top_) < 0)
01843          display_top_ = 0;
01844         
01845        cur_row_ = display_top_;
01846 
01847        row = first_row_;
01848 
01849        repaint(vp);
01850 
01851        break;
01852 
01853      case CursorWindow::func_next:
01854 
01855        // move the cursor forward one page and handle paging issues
01856 
01857        display_top_ += size.row_ - first_row_;
01858 
01859        if( (int)(display_top_) >= (int)manager_->apps_.size() )
01860          display_top_ = manager_->apps_.size()-1;
01861         
01862        if( (int)(display_top_) < 0 )
01863          display_top_ = 0;
01864         
01865        cur_row_ = display_top_;
01866 
01867        row = first_row_;
01868 
01869        repaint(vp);
01870 
01871        break;
01872 
01873 
01874      case CursorWindow::func_enter:
01875        {
01876           //
01877           // Invoke the current application to get a viewer, then replace
01878           // this appChooser instance with the viewer -- finally deleting
01879           // self.
01880           //
01881           ViewerManager::application app = manager_->apps_[cur_row_].first;
01882         
01883           string fullname;
01884         
01885           Viewer* rv = (*app)(manager_, fullname);
01886         
01887           if(rv)
01888           {
01889             // A viewer was returned -- ie the user didn't abort any
01890             // needed input.  So, replace this appChooser with the
01891             // new viewer.
01892         
01893             {
01894               // see if the returned viewer is a viewer that has already
01895               // found in the viewers list.  If so, kill this window and
01896               // activate tht one
01897         
01898               for(size_t i=0; i < manager_->viewers_.size(); ++i)
01899               {
01900                 if(manager_->viewers_[i].first == rv)
01901                 {
01902                   manager_->activate(rv);
01903                 
01904                   {
01905                       for(i = 0; i < manager_->viewports_.size(); ++i)
01906                       {
01907                         if(manager_->viewports_[i]->get_repaint_handler() == rv)
01908                         {
01909                           manager_->override_active_viewport_ = i;
01910                           break;
01911                         }
01912                       }
01913                   }
01914                 
01915                   return true;
01916                 }
01917               }
01918         
01919             }
01920         
01921         
01922             size_t i;
01923         
01924             typedef ViewerManager::vpentry  vpentry;
01925         
01926             vector<viewport*> &viewports_ = manager_->viewports_;
01927             vector<vpentry>   &viewers_   = manager_->viewers_;
01928         
01929             viewports_[manager_->active_viewport_]->set_repaint_handler(rv);
01930         
01931         
01932             for(i=0; i < viewers_.size(); ++i)
01933             {
01934                if(viewers_[i].first == this)
01935                {
01936                   viewers_[i].first = rv;
01937                   viewers_[i].second = fullname;
01938                 
01939                   viewports_[manager_->active_viewport_]->activate();
01940                 
01941                   return false;
01942                }
01943             }
01944           }
01945         
01946           return true;
01947         
01948        }
01949        break;
01950 
01951      case CursorWindow::func_data:
01952        switch(e->value_)
01953        {
01954          case 'q':  // undisplay the application chooser
01955            return true;
01956        }
01957        break;
01958 
01959 
01960    }
01961 
01962    // now, highlight the appropriate line
01963 
01964    vp->set_curpos(row,left);
01965    vp->set_text_attribute(ViewerManager::highlighted_att);
01966 
01967    *vp << "  ";
01968 
01969    output_row_text(vp, cur_row_);
01970 
01971    vp->fill_to_eol();
01972 
01973    vp->set_curpos(row,left);
01974    vp->set_text_attribute(ViewerManager::normal_att);
01975 
01976    return false;
01977 }
01978 
01979 Viewer*
01980 ViewerManager::
01981 find_viewer(string const &viewername)
01982 {
01983   for(size_t i=0; i < viewers_.size(); ++i)
01984   {
01985     if( viewers_[i].second == viewername)
01986       return viewers_[i].first;
01987   }
01988 
01989   return 0;
01990 }
01991 
01992 
01993 
01994 std::string
01995 ViewerManager::
01996 find_viewer_name(Viewer *vp)
01997 {
01998   for(size_t i=0; i < viewers_.size(); ++i)
01999   {
02000     if( viewers_[i].first == vp)
02001       return viewers_[i].second;
02002   }
02003 
02004   return std::string();
02005 }
02006 
02007 
02008 void
02009 ViewerManager::
02010 help()
02011 {
02012   Viewer* active = active_viewer();
02013 
02014   active->help();
02015 
02016 }
02017 
02018 
02019 
02020 void
02021 ViewerManager::
02022 help_helper( list<string>& help_info )
02023 {
02024   CursorWindow::Message m("Help");
02025 
02026   //
02027   // First, make sure the current viewer's help is first in the display
02028   //
02029 
02030   {
02031     list< string >::iterator first = help_info.begin(),
02032                                        last  = help_info.end();
02033                                 
02034     while(first != last)
02035     {
02036       string &t = *first++;
02037 
02038       m += t;
02039 
02040     }
02041   }
02042 
02043 
02044   // now attach the system command bindings help info (viewer manager specific
02045   // stuff
02046 
02047   m += "";
02048   m += string("Executable: ") + executable_name_ + ":" ;
02049   m += "    " + executable_version_;
02050   m += "";
02051   m += "System command bindings are as follows:";
02052   m += "";
02053 
02054   {
02055     list<string>::iterator first = key_bindings_doc.begin(),
02056                                      last  = key_bindings_doc.end();
02057                                 
02058     while(first != last)
02059     {
02060       string &s = *first++;
02061 
02062       m += "  " + s;
02063 
02064     }
02065   }
02066 
02067   m += "";
02068   m += "Standard edit function key bindings";
02069   m += "  (some may not apply):";
02070   m += "";
02071 
02072   {
02073     CursorWindow* window = this->window();
02074 
02075     map<int,int>::iterator first = window->func.begin(),
02076                                 last  = window->func.end();
02077     while(first != last)
02078     {
02079       map<int,int>::value_type& cur = *first++;
02080 
02081       int key = cur.first;
02082       int func= cur.second;
02083 
02084       if(func != CursorWindow::func_data)
02085       {
02086 
02087         string key_name  = CursorWindow::key_name(key);
02088         string func_name = CursorWindow::func_name(func);
02089         
02090         while(key_name.size() < 8)
02091           key_name += ' ';
02092         
02093         m += string("  ") + key_name + string(" -- ") + func_name;
02094       }
02095 
02096     }
02097 
02098 
02099   }
02100 
02101 
02102 
02103   m.popup(window());
02104 
02105 }
02106 
02107 
02108 Viewer*
02109 ViewerManager::
02110 open(string const &_fullname)
02111 {
02112   FileName fullname(_fullname);
02113 
02114   if(fullname.is_dir())
02115   {
02116     if(!dir_opener_)
02117       return 0;
02118 
02119     return (*dir_opener_)(this, fullname);
02120 
02121   }
02122   else
02123   {
02124     // see if the specified name's basename contains '*' or '?'
02125 
02126     string basepart = fullname.basename();
02127 
02128     string::iterator first = basepart.begin(),
02129                           last  = basepart.end();
02130                         
02131     while(first != last)
02132     {
02133       char c = *first++;
02134 
02135       if(c == '*' || c == '?')
02136       {
02137         if(!dir_opener_)
02138           return 0;
02139 
02140         return (*dir_opener_)(this, fullname);
02141       }
02142     }
02143 
02144   }
02145 
02146   // ok, its not a directory or a directory search pattern
02147 
02148 
02149   string ext = fullname.extension();
02150 
02151   if(ext.size())
02152   {
02153     list<opener_map_entry>::iterator first = openers_.begin(),
02154                                      last  = openers_.end();
02155                                         
02156     while(first != last)
02157     {
02158       opener_map_entry & cur = *first++;
02159 
02160       std::string const &supported = cur.second;
02161 
02162 
02163       if(supported == ext)
02164         return (*cur.first)(this, fullname);
02165     }
02166 
02167     // no file extension specific match occurred
02168 
02169   }
02170 
02171   if(openers_.begin() != openers_.end())
02172   {
02173     application app= openers_.back().first;
02174 
02175     return (*app)(this, fullname);
02176 
02177   }
02178 
02179 
02180   return 0;
02181 
02182 
02183 }
02184 
02185 void
02186 ViewerManager::
02187 set_directory_app(application a)
02188 {
02189   dir_opener_ = a;
02190 }
02191 
02192 void
02193 ViewerManager::
02194 add_viewer_app(application a, string filename_extension)
02195 {
02196   openers_.push_front( opener_map_entry(a,filename_extension) );
02197 }
02198 
02199 void
02200 ViewerManager::
02201 add_editor_app(application a, string filename_extension)
02202 {
02203   editors_.push_front( opener_map_entry(a,filename_extension) );
02204 }
02205 
02206 Viewer*
02207 ViewerManager::
02208 edit(string const &_fullname)
02209 {
02210   FileName fullname(_fullname);
02211 
02212   if(fullname.is_dir())
02213   {
02214     if(!dir_opener_)
02215       return 0;
02216 
02217     string name = fullname + "/*";
02218 
02219     return (*dir_opener_)(this, name);
02220 
02221   }
02222   else
02223   {
02224     // see if the specified name's basename contains '*' or '?'
02225 
02226     string basepart = fullname.basename();
02227 
02228     string::iterator first = basepart.begin(),
02229                           last  = basepart.end();
02230                         
02231     while(first != last)
02232     {
02233       char c = *first++;
02234 
02235       if(c == '*' || c == '?')
02236       {
02237         if(!dir_opener_)
02238           return 0;
02239 
02240         return (*dir_opener_)(this, fullname);
02241       }
02242     }
02243 
02244   }
02245 
02246   // ok, its not a directory or a directory search pattern
02247 
02248 
02249   string ext = fullname.extension();
02250 
02251   if(ext.size())
02252   {
02253     list<opener_map_entry>::iterator first = editors_.begin(),
02254                                           last  = editors_.end();
02255                                         
02256     while(first != last)
02257     {
02258       opener_map_entry & cur = *first++;
02259 
02260       std::string const &supported = cur.second;
02261 
02262       if(supported == ext)
02263         return (*cur.first)(this, fullname);
02264     }
02265 
02266     // no file extension specific match occurred
02267 
02268   }
02269 
02270   if(editors_.begin() != editors_.end())
02271   {
02272     // look for the editor with an empty string as its extension
02273     // and if that is not found, look for the last one .
02274 
02275     application app= 0;
02276 
02277     list<opener_map_entry>::iterator first = editors_.begin(),
02278                                           last  = editors_.end();
02279                                         
02280     while(first != last)
02281     {
02282       opener_map_entry & cur = *first++;
02283 
02284       if(cur.second == "")
02285       {
02286         app = cur.first;
02287         break;
02288       }
02289     }
02290     
02291     if(app == 0)
02292         app= editors_.back().first;
02293 
02294     return (*app)(this, fullname);
02295 
02296   }
02297 
02298 
02299   return 0;
02300 
02301 
02302 }
02303 
02304 string
02305 ViewerManager::
02306 active_directory() const
02307 {
02308   ViewerManager* me = const_cast<ViewerManager*>(this);
02309 
02310   Viewer* av = me->active_viewer();
02311 
02312   FileName pattern;
02313 
02314   if(!av)
02315     pattern="/";
02316   else
02317   {
02318     vector<vpentry>::iterator first = me->viewers_.begin(),
02319                                    last  = me->viewers_.end();
02320                                 
02321     while(first != last)
02322     {
02323       vpentry& e = *first;
02324 
02325       if(e.first == av)
02326       {
02327         pattern=e.second;
02328         pattern = pattern.dirname();
02329         
02330         break;
02331       }
02332 
02333       ++first;
02334 
02335     }
02336 
02337     if(first == last)
02338     {
02339       pattern="/";
02340     }
02341 
02342   }
02343 
02344   return pattern;
02345 
02346 }
02347 
02348 
02349 void
02350 ViewerManager::
02351 popup_new_viewer(bool use_edit)
02352 {
02353   FileName pattern = active_directory();
02354 
02355   // NOTE:  do NOT use the CursorWindow::FileSelector here because it can't
02356   // repaint the screen from this context and it needs to.
02357 
02358   CursorWindow::Dialog d( use_edit ? "Edit file or directory"
02359                                    : "View file or directory"
02360                         );
02361 
02362   d.set_completion_directory(pattern);
02363         
02364    d += new CursorWindow::Dialog::String("name",
02365                                          "Pathname",
02366                                          "",
02367                                          40
02368                                         );
02369                                 
02370    if(d.popup(window()))
02371      return ;
02372         
02373   string file = d.element_value("name");
02374 
02375 
02376   if(file.size())
02377   {
02378      FileName f(file);
02379 
02380      f = f.expand_tildes();  // expand ~lboggs
02381 
02382      if(!f.is_absolute_path())
02383        f = pattern + f;
02384 
02385      f.convert_to_absolute_path();
02386 
02387      if(f.is_dir())
02388      {
02389        char lastChar = f[f.size()-1];
02390 
02391        if(lastChar != '/' && lastChar != '\\')
02392          f += '/';
02393 
02394        f += '*';
02395      }
02396 
02397      Viewer* extant_viewer = find_viewer(f);
02398 
02399      if(extant_viewer)
02400      {
02401        activate(extant_viewer);
02402 
02403        if(override_active_viewport_ < viewports_.size())
02404        {
02405          active_viewport_ = override_active_viewport_;
02406          override_active_viewport_ = 10000;
02407        }
02408 
02409        return;
02410      }
02411 
02412      Viewer* newbie;
02413 
02414      if(use_edit)
02415        newbie = edit(f);
02416      else
02417        newbie = open(f);
02418 
02419      if(newbie)
02420        add(newbie, f);
02421 
02422   }
02423 
02424 }
02425 
02426 bool
02427 ViewerManager::
02428 is_visible(Viewer* v)
02429 {
02430 
02431   vector<viewport*>::iterator vp_next = viewports_.begin(),
02432                                    vp_last = viewports_.end();
02433 
02434   while(vp_next != vp_last)
02435   {
02436     viewport* entry = *vp_next++;
02437 
02438     repaint_handler *rh = entry->get_repaint_handler();
02439 
02440     Viewer* vp = dynamic_cast<Viewer*>(rh);
02441 
02442     if(vp == v)
02443     {
02444       // found it -- there is a viewport with this viewer in it.
02445       // make it the current viewport.
02446 
02447       return true;
02448 
02449     }
02450 
02451   }
02452 
02453   return false;
02454 }
02455 
02456 
02457 void
02458 ViewerManager::
02459 splitscreen_new_editor(bool horizontal)
02460 {
02461   FileName pattern = active_directory();
02462 
02463   string title;
02464 
02465   if(horizontal)
02466     title = "Horizontally ";
02467   else
02468     title = "Vertically ";
02469 
02470   title += "Split window and edit (leave name blank for buffer list)";
02471 
02472   CursorWindow::Dialog d(title);
02473 
02474   d.set_completion_directory(pattern);
02475         
02476    d += new CursorWindow::Dialog::String("name",
02477                                          "Pathname",
02478                                          "",
02479                                          40
02480                                         );
02481                                 
02482    if(d.popup(window()))
02483      return ;
02484         
02485   string file = d.element_value("name");
02486 
02487   // remove leading spaces from the file name
02488 
02489   while( file.size() && file[0] == ' ')
02490     file.erase( file.begin() );
02491 
02492   // if the file name is empty, bring up the viewer
02493   // selector, otherwise bring up an edit session
02494 
02495   if(file.size() == 0)
02496   {
02497     //
02498     // make sure the viewer selector is not already up -- if it is,
02499     // make it the active viewport
02500     //
02501     size_t i;
02502 
02503     for(i=0; i < viewports_.size(); ++i)
02504     {
02505       repaint_handler* rh = viewports_[i]->get_repaint_handler();
02506       Viewer*          vp = dynamic_cast<Viewer*>(rh);
02507 
02508       if(vp == vs_.get())
02509       {
02510         active_viewport_ = i;
02511         viewports_[i]->activate();
02512         return;
02513       }
02514     }
02515 
02516     // ok, if we get here it means the the user enter an empty
02517     // file name and the viewer selector is not currently
02518     // displayed.
02519 
02520     if(horizontal)
02521       hsplit(vs_.get(), "Viewer Selector");
02522     else
02523       vsplit(vs_.get(), "Viewer Selector");
02524 
02525 
02526   }
02527   else
02528   {
02529      FileName f(file);
02530 
02531      if(!f.is_absolute_path())
02532        f = pattern + f;
02533 
02534      f.convert_to_absolute_path();
02535 
02536      if(f.is_dir())
02537        f += "/*";
02538 
02539      Viewer* extant_viewer = find_viewer(f);
02540 
02541      if(extant_viewer)
02542      {
02543        if(is_visible(extant_viewer))
02544        {
02545          activate(extant_viewer);
02546         
02547          if(override_active_viewport_ < viewports_.size())
02548          {
02549            active_viewport_ = override_active_viewport_;
02550            override_active_viewport_ = 10000;
02551          }
02552        }
02553        else
02554        {
02555          if(horizontal)
02556            hsplit(extant_viewer, f);
02557          else
02558            vsplit(extant_viewer, f);
02559        }
02560        return;
02561      }
02562 
02563      Viewer* newbie;
02564 
02565      newbie = edit(f);
02566 
02567      if(newbie)
02568      {
02569        if(horizontal)
02570          hsplit(newbie, f);
02571        else
02572          vsplit(newbie, f);
02573      }
02574 
02575   }
02576 
02577 }
02578 
02579 void
02580 ViewerManager::
02581 handle_die_request()
02582 {
02583    // close all windows that can be closed
02584 
02585    string curdir=active_directory();
02586 
02587    if(exit_dir_.size() == 0)
02588    {
02589      exit_dir_ = curdir;
02590    }
02591 
02592    bool clean_viewer_found=true;
02593 
02594    while(clean_viewer_found)
02595    {
02596      size_t viewers = viewers_.size();
02597 
02598      clean_viewer_found = false;
02599 
02600      for(size_t i=0; i < viewers; ++i)
02601      {
02602        if(!viewers_[i].first->is_dirty())
02603        {
02604          CursorWindow::input_event e;  
02605                                    
02606          e.type_ = CursorWindow::input_event::ForceExitKey;
02607      
02608          activate(viewers_[i].first);
02609 
02610          dispatch_event(e);
02611 
02612 
02613          clean_viewer_found = true;
02614 
02615          break; // leave the loop so that each time a 'kill' is sent to a viewer
02616                 // we restart with viewerport 0 while searching
02617        }
02618      }
02619 
02620    }
02621 
02622    if(viewers_.size() == 0)
02623    {
02624      recordExitDir();  // won't do it if jump2dir is false
02625 
02626      exit();
02627 
02628    }
02629 
02630    unify();  
02631 
02632    {
02633        active_viewport()->beep();
02634 
02635        CursorWindow::Message m("Unsaved edit changes exist");
02636 
02637        m += "  You must manually close all edit sessions";
02638        m += "  with unsaved changes";
02639 
02640        m.popup(window());
02641    }
02642 
02643 
02644 
02645 }
02646 
02647 string 
02648 ViewerManager::
02649 default_etags_path(string &default_etags_path, char const *tagfileName)
02650 {
02651    //
02652    //  Return a pathname for the TAGS file
02653    //
02654 
02655    string etagspath = ProgramOptions::global_options_->getenv("ETAGSPATH");
02656    string home      = ProgramOptions::global_options_->getenv("HOME");
02657    string cdpath    = ProgramOptions::global_options_->getenv("CDPATH");
02658 
02659    if(cdpath.size())
02660     {
02661       default_etags_path += cdpath;
02662       default_etags_path += FileName::PATH_separator;
02663     }
02664 
02665    default_etags_path += ".";
02666    default_etags_path += FileName::PATH_separator;
02667    default_etags_path += "..";
02668    default_etags_path += FileName::PATH_separator;
02669    default_etags_path += home;
02670 
02671    if(etagspath.size())
02672    {
02673      default_etags_path = etagspath;
02674    }
02675 
02676    FileName tagsfile = FileName::find_file_in_path(tagfileName, default_etags_path);
02677 
02678    return tagsfile;
02679 
02680 }
02681 
02682 EtagsDB*
02683 ViewerManager::default_etags_db()
02686 {
02687   static EtagsDB* rv = 0;
02688 
02689   if(rv == 0)
02690   {
02691     rv = new EtagsDB;
02692 
02693     string tagsfile;
02694 
02695     string default_etags_path;
02696 
02697     tagsfile = ViewerManager::default_etags_path(default_etags_path);
02698 
02699     rv->set_tags_file(tagsfile);
02700 
02701     if(!rv->ok())
02702     {
02703       string sp("  ");
02704     
02705       CursorWindow::Message  m("Error opening 'TAGS' file");
02706     
02707       m += "Couldn't find the TAGS file in any directory defined by $ETAGSPATH:";
02708     
02709       StrTool::stringlist_t l;
02710     
02711       string default_etags_path;
02712     
02713       ViewerManager::default_etags_path(default_etags_path);
02714     
02715       StrTool::parse_words(default_etags_path, &l, 10000, FileName::is_separator());
02716     
02717       StrTool::stringlist_t::iterator first = l.begin(),
02718                                       last  = l.end();
02719                                   
02720       while(first != last)
02721       {
02722         m += *first++;
02723       }
02724     
02725       active_viewport()->beep();
02726     
02727       m.popup(active_viewport()->window());
02728     
02729       return 0;
02730     }
02731 
02732 
02733   }
02734 
02735   return rv;
02736 }
02737 
02738 CppTagDB::Info*
02739 ViewerManager::default_cpptags_db()
02742 {
02743   static CppTagDB::Info* rv = 0;
02744 
02745   if(rv == 0)
02746   {
02747     rv = new CppTagDB::Info;
02748 
02749     string path;
02750 
02751     string tagppFile = default_etags_path(path,"TAGPP.tagpp");
02752 
02753     int failedLine=-1;
02754 
02755     int err = rv->populate(tagppFile, failedLine);
02756 
02757     if(err)
02758     {
02759       string sp("  ");
02760     
02761       CursorWindow::Message  m("Error opening TAGPP.tagpp file");
02762     
02763       m += "Couldn't find the TAGPP.tagpp file in any directory defined by $ETAGSPATH:";
02764     
02765       StrTool::stringlist_t l;
02766     
02767       string default_etags_path;
02768     
02769       StrTool::parse_words(path, &l, 10000, FileName::is_separator());
02770     
02771       StrTool::stringlist_t::iterator first = l.begin(),
02772                                       last  = l.end();
02773                                   
02774       while(first != last)
02775       {
02776         m += *first++;
02777       }
02778     
02779       active_viewport()->beep();
02780     
02781       m.popup(active_viewport()->window());
02782     
02783       return 0;
02784     }
02785 
02786 
02787   }
02788 
02789   return rv;
02790 }
02791 
02792 
02793 struct is_pathsep
02794 {
02795   bool operator() (char c) const { return c == '/' || c == '\\'; }
02796 };
02797 
02798 
02799 int
02800 ViewerManager::
02801 find_files(string operand,
02802            list<string> *results
02803           )
02804 {
02805   FileName tmp(operand);
02806 
02807   if(tmp.is_absolute_path())
02808   {
02809     results->push_back(tmp);
02810     return 1;
02811   }
02812 
02813   int count = 0;
02814 
02815   // first, find all matching files from the CDPATH
02816   {
02817     StrTool::stringlist_t dirs;
02818     int count = StrTool::parse_words(ProgramOptions::global_options_->getenv("CDPATH"),
02819                                      &dirs,
02820                                      1000000,
02821                                      StrTool::Is_Colon()
02822                                     );
02823    
02824     StrTool::stringlist_t::iterator f, l;
02825     
02826     for(f = dirs.begin(), l = dirs.end(); f != l; ++f)
02827     {
02828       string const& cur = *f;
02829 
02830       FileName tmp(cur);  
02831       
02832       tmp += string("/") + operand;
02833 
02834       if(tmp.exists())
02835       {
02836         results->push_back(tmp);
02837         ++count;
02838       }
02839 
02840     }
02841   }  
02842 
02843   // next include all references from the etags database
02844 
02845   {
02846      CppTagDB::Info* db = default_cpptags_db();
02847 
02848      if(db)
02849      {
02850         vector<string> tmp;
02851 
02852         db->findMatchingFiles(operand, tmp);
02853 
02854         for(size_t i = 0; i < tmp.size(); ++i)
02855         {
02856            results->push_back(tmp[i]);
02857            ++count;
02858         }
02859 
02860 
02861      }
02862 
02863   }
02864 
02865   {
02866     EtagsDB* db = default_etags_db();
02867 
02868     if(db && db->ok())
02869     {
02870       count += db->matching_files(operand, results);
02871     }
02872   }
02873 
02874 
02875   return count;
02876 
02877 }
02878 
02879 struct Is_Path_Separator
02880 {
02881   bool operator() (char c) const
02882   {
02883     return c == FileName::PATH_separator ;
02884   }
02885 
02886 };
02887 
02888 
02889 FileName
02890 ViewerManager::
02891 find_file_in_standard_locations(FileName const &fragment, FileName const &directory)
02892 {
02893   FileName name;  // return value
02894 
02895   if(fragment.is_absolute_path())
02896   {
02897     // no need to search for it.
02898 
02899      return fragment;
02900   }
02901 
02902   // the directory should include a trailing /
02903 
02904   // search for a given filename fragment in all the standard locations.
02905   // the standard locations are defined by the algorithm below, but they include
02906   //
02907   //    directory + fragment  -- there is a presumed directory but it may not in fact
02908   //                             be the correct one.
02909   //
02910   //    SOURCEPATH as defined by environment variable -- a colon (or semicolon) separated list
02911   //               (depending on the os) of directories to look for files.
02912   //
02913   //    CDPATH     similar to SOURCEPATH but this is obsolete -- please do not use.
02914   //
02915   //    TAGPP.tagpp  This is a database of source files generated by cpptagdb.exe.
02916   //                 The viewermanager keeps track of it and this function will search
02917   //                 it for files matching the specified fragment.
02918   //
02919   //    TAGS         The etags generated source file database.  The viewer manager keeps
02920   //                 track of it and we will search it here.
02921 
02922 
02923 
02924   FileName specified_name(fragment);
02925   FileName local_dir_reference = directory + specified_name;
02926 
02927   local_dir_reference.convert_to_absolute_path();
02928 
02929   if( ! local_dir_reference.exists() )
02930   {
02931 
02932     std::string cdpath = ProgramOptions::global_options_->getenv("SOURCEPATH");
02933 
02934     if(cdpath.empty())
02935       cdpath = std::string(ProgramOptions::global_options_->getenv("CDPATH"));
02936 
02937     bool found=false;
02938 
02939     if(!cdpath.empty())
02940     {
02941       // re-architect the cdpath variable such that path elements beginning with ./ and ..
02942       // are prefixed with the name of the directory in which file being edited lies.
02943 
02944       if(directory.size())
02945       {
02946         
02947         StrTool::stringlist_t splitpath;
02948       
02949         Is_Path_Separator functor;
02950       
02951         StrTool::parse_words(cdpath,
02952                              &splitpath,
02953                              2000000000U,
02954                              functor
02955                             );
02956       
02957         StrTool::stringlist_t::iterator f = splitpath.begin();
02958         StrTool::stringlist_t::iterator l = splitpath.end();
02959       
02960         while(f != l)
02961         {
02962           std::string &s = *f++;
02963 
02964           if(s.size() > 2 && s[0] == '.' && ( s[1] == '.' || s[1] == '/' || s[1] == '\\' ))
02965           {
02966             s = directory + s;  // assumes trailing slash is found on dirname
02967           }
02968         }
02969 
02970         cdpath.resize(0);
02971 
02972         f = splitpath.begin();
02973 
02974         while(f != l)
02975         {
02976           if(f != splitpath.begin())
02977             cdpath += ':';
02978 
02979           cdpath += *f++;
02980         }
02981 
02982       }
02983 
02984 
02985     }
02986 
02987     if(!cdpath.empty())
02988     {
02989       FileName cd_path_location( FileName::find_file_in_path(specified_name, cdpath ) );
02990 
02991       if(cd_path_location.size())
02992       {
02993         name = cd_path_location;
02994         specified_name = name;
02995         found=true;
02996       }
02997 
02998     }
02999 
03000     if(!found)
03001     {
03002       CppTagDB::Info * cpptags=(default_cpptags_db());  // pts to static object
03003 
03004       if(cpptags)
03005       {
03006         std::vector<std::string> matches;
03007 
03008         std::string search_name;
03009 
03010         size_t first_good_char = static_cast<std::string const &>(specified_name).find_first_not_of("..\\/");
03011 
03012         if(first_good_char < specified_name.size())
03013           search_name = specified_name.substr(first_good_char, specified_name.size() - first_good_char);
03014         else
03015           search_name = specified_name;
03016         
03017         cpptags->findRelativeFiles(search_name, matches);
03018         
03019         if(!matches.empty())
03020         {
03021           std::string const & s = *matches.begin();
03022         
03023           name = s;
03024           found=true;
03025           specified_name=name;
03026         }
03027       }
03028     }
03029 
03030     if(!found)
03031     {
03032       EtagsDB* etags=(default_etags_db());  // pts to static object
03033 
03034       if(etags && etags->ok())
03035       {
03036         std::list<std::string> matches;
03037 
03038         std::string search_name;
03039 
03040         size_t first_good_char = static_cast<std::string const &>(specified_name).find_first_not_of("..\\/");
03041 
03042         if(first_good_char < specified_name.size())
03043           search_name = specified_name.substr(first_good_char, specified_name.size() - first_good_char);
03044         else
03045           search_name = specified_name;
03046         
03047         int count = etags->matching_files(search_name, &matches);
03048         
03049         if(count)
03050         {
03051           std::string const & s = *matches.begin();
03052         
03053           name = s;
03054           found=true;
03055           specified_name=name;
03056         }
03057       }
03058     }
03059   }
03060   else
03061   {
03062     specified_name=local_dir_reference;
03063 
03064     name = specified_name;
03065 
03066   }
03067 
03068   return name;
03069 
03070 }
03071 
03072 void ViewerManager::findMatchingViewers(FileName namePattern, std::list<std::pair<Viewer*, FileName> > &viewers)
03073 {
03074     CXXTLS_FOREACH(vpentry &cur, viewers_)
03075     {
03076         FileName curFile(cur.second);
03077 
03078         if( curFile.matches(namePattern) )
03079         {
03080            viewers.push_back(std::pair<Viewer*,FileName>(cur.first, cur.second) );
03081         }
03082     }
03083 }
03084 
03085 
03086 
03087 Viewer* ViewerManager::most_recent_viewer()
03088 {
03089     if(order_.empty())
03090     {
03091        if(viewers_.empty())
03092            return 0;
03093 
03094        return viewers_.back().first;
03095     }
03096 
03097     // if we get here, there is at least one previously activated viewer.
03098 
03099     MRU<std::string>::iterator mruPtr = order_.mostRecent();
03100 
03101     if(mruPtr != order_.end())
03102     {
03103         std::string mru = *mruPtr;
03104         
03105         return find_viewer(mru);  // may return null!
03106     }
03107 
03108     return viewers_.back().first; 
03109 
03110 
03111 }
03112 
03113 
03114 
03115 } // namespace cxxtls
Generated on Wed Feb 29 22:50:05 2012 for CXXUtilities by  doxygen 1.6.3