tableeditor.cxx

Go to the documentation of this file.
00001 //
00002 // Copyright 2010, Lowell Boggs Jr.
00003 //
00004 // This file or directory, containing source code for a computer program,
00005 // is Copyrighted by Lowell Boggs, Jr.  987 Regency Drive, Lewisville
00006 // TX (USA), 75067.  You may use, copy, modify, and distribute this
00007 // source file without charge or obligation so long as you agree to
00008 // the following:
00009 //
00010 //  1.  You must indemnify Lowell Boggs against any and all financial
00011 //      obligations caused by its use, misuse, function, or malfunction.
00012 //      Further, you acknowledge that there is no warranty of any kind,
00013 //      whatsoever.
00014 //
00015 //  2.  You agree not to attempt to patent any portion of this original
00016 //      work -- though you may attempt to patent your own extensions to
00017 //      it if you so choose.
00018 //
00019 //  3.  You keep this copyright notice with the file and all copies
00020 //      of the file and do not change it anyway except language translation.
00021 //
00022 // You are responsible for enforcing your own compliance with these
00023 // conditions and may not use this source file if you cannot agree to the
00024 // above terms and conditions.
00025 //
00026 // Warning:  not all files in this directory structure are covered by the
00027 // same copyright.  Some of them are part of the GNU source distribution
00028 // and you must obey the GPL copyright for those files.
00029 
00030 #include <cxxtls/tableeditor.h>
00031 #include <cxxtls/viewermanager.h>
00032 #include <iostream>
00033 #include <fstream>
00034 #include <cxxtls/strtool.h>
00035 #include <cxxtls/file.h>
00036 
00037 using namespace std;
00038 
00039 namespace cxxtls
00040 {
00041 
00044 TableEditor::~TableEditor()
00045 {
00046 }
00049 TableEditor::TableEditor(ViewerManager *vm, int delimiter)
00050 : TableViewer(vm)
00051 , fieldEditColumn_(0)
00052 , delimiter_(delimiter)
00053 , keyKludge_(0)
00054 {
00055   set_data_dirty(false);
00056 }
00059 TableViewer::CellInfo *TableEditor::editCell()
00060 {
00061    if(rows() && cols())
00062    {
00063        CursorInfo cursor = cursorInfo();
00064 
00065        return cellInfo(cursor.row_, cursor.col_);
00066 
00067    }
00068 
00069    return 0;
00070 }
00075 bool TableEditor::handle_event( CursorWindow::input_event const * e,
00076                               CursorWindow::viewport          * vp
00077                             )
00078 {
00079     if(    e->type_ == CursorWindow::input_event::DataKey
00080        ||  e->type_ == CursorWindow::input_event::FunctionKey 
00081       )
00082     {
00083         // first, check to see if this is part 2 of a two part
00084         // command key sequence.  Part 1 is always ^X,
00085 
00086         if(keyKludge_)
00087         {
00088             keyKludge_ = false;
00089 
00090             switch(e->value_)
00091             {
00092                 case 0x03: // ^C quit editing
00093                    return true;
00094 
00095 
00096                 default: vp->beep(); break;
00097             }
00098 
00099             return false;
00100         }
00101 
00102         // ok, this is not part two a two part key sequence
00103 
00104         if(isTableEditKey(e) && !fieldEditable(cursorInfo()))
00105         {
00106            vp->beep();
00107            return false;
00108         }
00109 
00110 
00111         switch(e->value_)
00112         {
00113            case 0x18:  // ^X
00114            {
00115               keyKludge_ = true;
00116            }
00117            return false;
00118 
00119            case 0x10: // ^P
00120            {
00121                pageRight(vp);
00122            }
00123            return false;
00124 
00125            case 0x11: // ^Q
00126            {
00127                pageLeft(vp);
00128            }
00129            return false;
00130 
00131            case 0x09: // TAB
00132            {
00133                moveRight(vp);
00134            }
00135            return false;
00136 
00137            case CursorWindow::key_btab: // shift tab
00138            {
00139                moveLeft(vp);
00140            }
00141            return false;
00142 
00143 
00144 
00145            case 0x01: // ^A -- got to beginning of cell line
00146            {
00147                CellInfo  *cell = editCell();
00148            
00149                if(cell)
00150                {
00151                   if(cell->text_.size())
00152                   {
00153                      // assume we only edit row 0 for the moment
00154            
00155                      fieldEditColumn_ = 0;
00156                      paintCursor(vp);
00157                   }
00158                }
00159            
00160            }
00161            return false;
00162 
00163            case 0x05: // control e -- go to end of cell
00164            {
00165                CellInfo  *cell = editCell();
00166            
00167                if(cell)
00168                {
00169                   if(cell->text_.size())
00170                   {
00171                      // assume we only edit row 0 for the moment
00172            
00173                      fieldEditColumn_ = cell->text_[0].size();
00174                      paintCursor(vp);
00175                   }
00176                }
00177            
00178            }
00179            return false;
00180 
00181 
00182            case CursorWindow::key_dc:  
00183            {
00184 
00185                CellInfo  *cell = editCell();
00186            
00187                if(cell)
00188                {
00189                   if(cell->text_.size())
00190                   {
00191                      // assume we only edit row 0 for the moment
00192            
00193                      string &text = cell->text_[0];
00194            
00195                      if(fieldEditColumn_ < text.size())
00196                      {
00197                         set_data_dirty(true);
00198 
00199                         text.erase(fieldEditColumn_, 1);
00200                         
00201                         checkLayoutRecompute();
00202 
00203                         paintCursor(vp);
00204                      }
00205            
00206                   }
00207                }
00208            
00209            }
00210            return false;
00211 
00212            case CursorWindow::key_bs:  
00213            {
00214                
00215                CellInfo  *cell = editCell();
00216            
00217                if(cell)
00218                {
00219                   if(cell->text_.size())
00220                   {
00221                      // assume we only edit row 0 for the moment
00222            
00223                      string &text = cell->text_[0];
00224            
00225                      if(fieldEditColumn_ <= text.size() && fieldEditColumn_ > 0)
00226                      {
00227                         set_data_dirty(true);
00228 
00229                         --fieldEditColumn_;
00230 
00231                         text.erase(fieldEditColumn_, 1);
00232            
00233                         checkLayoutRecompute();
00234 
00235                         paintCursor(vp);
00236                      }
00237            
00238                   }
00239                }
00240            
00241            }
00242            return false;
00243 
00244            case CursorWindow::key_left:  
00245            {
00246                // Key left works like this:
00247                // If you are sitting in the left most column of an
00248                // cell, it will jump you to the previous cell.
00249                // On the other hand, if you are in the middle or at
00250                // the end of a cell, it will merely move the cursor
00251                // back one column.
00252 
00253                CellInfo  *cell = editCell();
00254            
00255                if(cell)
00256                {
00257                      // assume we only edit row 0 for the moment
00258            
00259                      if(fieldEditColumn_)
00260                      {
00261                          --fieldEditColumn_;
00262                          paintCursor(vp);
00263                          return false;
00264                      }
00265                }
00266            
00267            }
00268            break; // not return false!
00269 
00270            case CursorWindow::key_right:  
00271            {
00272                // Key right works like this:
00273                // If you are sitting at the end of the text in a cell
00274                // cell, it will jump you to the next cell.
00275                // On the other hand, if you are in the middle or at
00276                // the beginning of a cell, it will merely move the cursor
00277                // to the right one column.
00278 
00279                CellInfo  *cell = editCell();
00280            
00281                if(cell)
00282                {
00283                   
00284                   if(cell->text_.size())
00285                   {
00286                      // assume we only edit row 0 for the moment
00287            
00288                      string &text = cell->text_[0];
00289            
00290                      if(fieldEditColumn_ < text.size())
00291                      {
00292                         ++fieldEditColumn_;
00293            
00294                         paintCursor(vp);
00295 
00296                         return false;
00297                      }
00298            
00299                   }
00300                }
00301            
00302            }
00303            break; // not return false!
00304 
00305 
00306            case CursorWindow::key_f9: // insert row above
00307            {
00308                RowInfo ri;
00309 
00310                TableViewer::CursorInfo info = cursorInfo();
00311 
00312                ri.setRowTitleNumber(info.row_+1);
00313 
00314 
00315                TableViewer::insertRowAbove(vp, ri);
00316 
00317                for(size_t i = 0; i < rows(); ++i)
00318                {
00319                    ri = rowInfo(i);
00320 
00321                    ri.setRowTitleNumber(i+1);
00322 
00323                    setRowInfo(i, ri);
00324 
00325                }
00326 
00327 
00328                (*this)(vp, CursorWindow::viewport::repaint_handler::activate);
00329 
00330                TableViewer::setCursorInfo(vp, info);
00331 
00332 
00333            }
00334            return false;
00335 
00336 
00337            case 0x0d: // carriage return ^M
00338            case 0x0a: // (line feed ^J) insert row below
00339            {
00340 
00341                RowInfo ri;
00342 
00343                TableViewer::CursorInfo info = cursorInfo();
00344 
00345                ri.setRowTitleNumber(info.row_+2);
00346 
00347 
00348                TableViewer::insertRowBelow(vp, ri);
00349 
00350                for(size_t i = 0; i < rows(); ++i)
00351                {
00352                    ri = rowInfo(i);
00353 
00354                    ri.setRowTitleNumber(i+1);
00355                    
00356 
00357                    setRowInfo(i, ri);
00358 
00359                }
00360 
00361                (*this)(vp, CursorWindow::viewport::repaint_handler::activate);
00362 
00363                TableViewer::setCursorInfo(vp, info);
00364            }
00365            return false;
00366 
00367            case CursorWindow::key_f8: // delete row
00368            {
00369                TableViewer::CursorInfo info = cursorInfo();
00370 
00371                if(info.row_ < rows_.size())
00372                {
00373 
00374                    RowInfo ri;
00375                    
00376                    
00377                    TableViewer::deleteRow(vp);
00378                    
00379                    for(size_t i = 0; i < rows(); ++i)
00380                    {
00381                        ri = rowInfo(i);
00382                    
00383                        ri.setRowTitleNumber(i+1);
00384                    
00385                        setRowInfo(i, ri);
00386                    
00387                    }
00388                    
00389                    (*this)(vp, CursorWindow::viewport::repaint_handler::activate);
00390                    
00391                    TableViewer::setCursorInfo(vp, info);
00392                }
00393            }
00394            return false;
00395 
00396 
00397            default:
00398 
00399                if(e->type_ == CursorWindow::input_event::DataKey)
00400                {
00401                    set_data_dirty(true);
00402 
00403                    if(e->value_ >= ' ' && e->value_ < 0x7f)
00404                    {
00405                       char data = e->value_;
00406 
00407                       if(data == delimiter_)
00408                       {
00409                         vp->beep();
00410                         data = ' ';
00411                       }
00412 
00413                       CellInfo *cell = editCell();
00414 
00415                       if(cell)
00416                       {
00417                         
00418                          if(cell->text_.empty())
00419                          {
00420                            cell->text_.push_back("");
00421                          }
00422 
00423                          {
00424                             // assume we only edit row 0 for the moment
00425                       
00426                             string &text = cell->text_[0];
00427                       
00428                             if(fieldEditColumn_ > text.size())
00429                             {
00430                                fieldEditColumn_ = text.size();
00431                             }
00432 
00433                             text.insert(fieldEditColumn_, 1, data);
00434 
00435                             ++fieldEditColumn_;
00436 
00437                             checkLayoutRecompute();
00438 
00439                             paintCursor(vp);
00440 
00441                             return false; 
00442                          }
00443                       }
00444                    }
00445                }
00446 
00447                break;
00448 
00449         }
00450     }
00451 
00452    // by default, act like a table viewer -- which has different arrow key behavior
00453    // than is inforced here
00454 
00455    bool quitNow = TableViewer::handle_event(e,vp);
00456 
00457    return quitNow;
00458 }
00459 
00462 void TableEditor::snatchEdit(CursorWindow::viewport *vp, FileName const &directory)
00463 {
00464   
00465     // note:  directory MUST include the trailing /
00466 
00467 
00468     CellInfo *cell = editCell();
00469     
00470     if(cell)
00471     {
00472       
00473         string &text = cell->text_[0];
00474         
00475         if(fieldEditColumn_ < text.size())
00476         {
00477             string operand(  text.begin() + fieldEditColumn_, text.end() );
00478 
00479             FileName filename;
00480             int    lineNo = 0;
00481 
00482             string tmp;
00483 
00484             bool success = StrTool::snatch_file_info(operand, tmp, lineNo);
00485 
00486             if(success)
00487             {
00488                 filename = manager_->find_file_in_standard_locations(tmp, directory);
00489 
00490                 if(!filename.empty())
00491                 {
00492 
00493                     Viewer* oldie = manager_->find_viewer(filename);
00494                     
00495                     if(oldie)
00496                     {
00497                       if(lineNo > 0)
00498                           oldie->set_row_col_hint(lineNo-1,0);
00499 
00500                       manager_->activate(oldie);
00501                     }
00502                     else
00503                     {
00504                       if(!filename.exists())
00505                       {
00506                          CursorWindow::Message m(filename + " does not exist");
00507                     
00508                          m += "Sorry, can't find it";
00509                          m += "";
00510                          m += "Press Enter to continue";
00511                     
00512                          m.popup(manager_->window());
00513                     
00514                          return;
00515                       }
00516                     
00517                       Viewer *newbie = manager_->edit(filename);
00518                     
00519                       if(!newbie)
00520                         manager_->window()->beep();
00521                       else
00522                       {
00523                         if(lineNo > 0)
00524                             newbie->set_row_col_hint(lineNo-1, 0);  // 0 based line numbers!
00525 
00526                         manager_->vsplit(newbie, filename);
00527                       }
00528                     
00529                     }
00530 
00531                    
00532                 }
00533                 else
00534                 {
00535                    CursorWindow::Message m(string("Error:  ") + tmp);
00536                   
00537                    m += "File cannot be found";
00538                    m += "";
00539                    m += "Press Enter to continue";
00540                   
00541                    m.popup(manager_->window());
00542                 }
00543 
00544             }
00545             else
00546             {
00547                CursorWindow::Message m("Error");
00548               
00549                m += "The cell you are in does not contain a file name";
00550                m += "at the current cursor position.";
00551                m += "";
00552                m += "Press Enter to continue";
00553               
00554                m.popup(manager_->window());
00555             }
00556         }
00557     }
00558 
00559 
00560     // we get here only some kind of error
00561 
00562     vp->beep();
00563 }
00564 
00565 
00566 
00569 void TableEditor::setCursorInfo(CursorWindow::viewport *vp,
00570                               size_t worldRow, 
00571                               size_t worldCol, 
00572                               bool displayed
00573                              )
00574 {
00575     terminateInput();
00576 
00577     TableViewer::setCursorInfo(vp, worldRow, worldCol, displayed);
00578 }
00579 
00582 void TableEditor::terminateInput()
00583 {
00584    fieldEditColumn_ = 0;
00585 }
00586 
00589 void TableEditor::paintField(CursorWindow::viewport *vp,
00590                            size_t                       vpRow,
00591                            size_t                       vpCol,
00592                            TableViewer::CellInfo const *cell,
00593                            size_t                       cellRow,
00594                            size_t                       vpColumns,
00595                            bool                         editCursor
00596                           )
00597 {
00598    // the cursor is already positioned to vpRow, vpCol+1 when we get here!
00599 
00600    CursorWindow::row_col vpSize = vp->size();
00601 
00602    size_t vpRemainingColumns = vpSize.col_ - vpCol;  
00603 
00604    if(vpColumns > vpRemainingColumns)
00605    {
00606       vpColumns = vpRemainingColumns;
00607    }
00608 
00609 
00610    if(cell == 0 )
00611       return;
00612 
00613    if(    cell->text_.size() <= cellRow
00614       ||  cell->text_[cellRow].size() < vpColumns
00615      )
00616    {
00617        TableViewer::paintField(vp, vpRow, vpCol, cell, cellRow, vpColumns, editCursor);
00618 
00619        setTextInputPointer(vpRow, vpCol + 1 + fieldEditColumn_);
00620    }
00621    else
00622    {
00623        // the text is too big to fit in the cell.
00624     
00625        string const &text = cell->text_[cellRow];
00626     
00627        if(fieldEditColumn_ == text.size())
00628        {
00629           // paint the tail of the string and put the cursor 1 character past the
00630           // end of the string.
00631     
00632           char const *p = text.data() + text.size() - vpColumns + 2;
00633     
00634           vp->write(p, vpColumns-2);
00635 
00636           *vp << "  ";
00637 
00638           setTextInputPointer(vpRow, vpCol + vpColumns-1);
00639     
00640        }
00641        else
00642        {
00643           // the cursor is in the middle of the string 
00644 
00645           char const *p = text.data(); 
00646 
00647           size_t charOffset = 0;
00648 
00649           if(fieldEditColumn_ > text.size())
00650           {
00651             fieldEditColumn_ = text.size();
00652           }
00653 
00654           if(fieldEditColumn_+1 >= vpColumns)
00655           {
00656             charOffset = (fieldEditColumn_+2) - vpColumns;
00657           }
00658 
00659           size_t remainingLength = text.size() - charOffset;
00660 
00661           if(remainingLength > vpColumns)
00662              remainingLength = vpColumns;
00663 
00664           vp->write(p + charOffset, remainingLength);
00665 
00666           CursorWindow::row_col curpos;
00667 
00668           if(remainingLength < vpColumns)
00669           {
00670              
00671              curpos = vp->curpos();
00672 
00673              vp->write(' ', vpColumns - remainingLength);
00674 
00675              curpos = vp->curpos();
00676 
00677           }
00678 
00679           CursorWindow::row_col cp= vp->curpos();
00680 
00681 
00682           setTextInputPointer(vpRow, vpCol + 1 + fieldEditColumn_ - charOffset);
00683 
00684           if(editCursor)
00685           {
00686               if(size_t(cp.row_) != vpRow || cp.col_ >= vpSize.col_)
00687               {
00688                 // page too wide for screen, wrap around occurred on write
00689     
00690                 vp->set_curpos(vpRow, vpCol + vpColumns-1);
00691     
00692               }
00693               else
00694               {
00695                 vp->set_curpos(vpRow, vpCol + 1 + fieldEditColumn_ - charOffset);
00696               }
00697           }
00698 
00699        }
00700    }
00701 
00702 }
00703 
00704 bool TableEditor::isTableEditKey(CursorWindow::input_event const * e)
00705 {
00706   if(e->value_ >= ' ' && e->value_ <= '~')
00707     return true;
00708 
00709   switch(e->value_)
00710   {
00711      case                 0x08:  return true;
00712      case CursorWindow::key_dc:  return true;
00713      case CursorWindow::key_bs:  return true;
00714 
00715   }
00716 
00717 
00718    return false;
00719 }
00720 
00721 } // namespace cxxtls
Generated on Wed Feb 29 22:50:05 2012 for CXXUtilities by  doxygen 1.6.3