libyui-ncurses  2.44.1
/usr/src/RPM/BUILD/libyui-ncurses-2.44.1/src/NCFileSelection.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019    File:       NCFileSelection.cc
00020 
00021    Author:     Gabriele Strattner <gs@suse.de>
00022 
00023 /-*/
00024 
00025 #define  YUILogComponent "ncurses"
00026 #include <yui/YUILog.h>
00027 #include "NCFileSelection.h"
00028 #include "NCTable.h"
00029 #include "NCi18n.h"
00030 
00031 #include <fnmatch.h>
00032 #include <grp.h>
00033 #include <pwd.h>
00034 #include <string.h> // strerror()
00035 #include <sys/types.h>
00036 
00037 /*
00038   Textdomain "ncurses"
00039 */
00040 
00041 
00042 
00043 NCFileInfo::NCFileInfo( std::string     fileName,
00044                         struct stat64 * statInfo,
00045                         bool    link )
00046 {
00047     _name   = fileName;
00048     _mode   = statInfo->st_mode;
00049     _device = statInfo->st_dev;
00050     _links  = statInfo->st_nlink;
00051     _size   = statInfo->st_size;
00052     _mtime  = statInfo->st_mtime;
00053 
00054     if ( link )
00055     {
00056         char tmpName[PATH_MAX+1];
00057         // get actual file name
00058         int len = readlink( fileName.c_str(), tmpName, PATH_MAX );
00059 
00060         if ( len >= 0 )
00061         {
00062             tmpName[len] = '\0';
00063             _realName = tmpName;
00064         }
00065 
00066         _tag = " @";    // set tag
00067     }
00068     else if ( S_ISREG( _mode )
00069               && ( _mode & S_IXUSR ) )
00070         _tag = " *";    // user executable files
00071     else
00072         _tag = "  ";
00073 
00074     // get user and group name
00075 
00076     struct passwd * pwdInfo  = getpwuid( statInfo->st_uid );
00077 
00078     if ( pwdInfo )
00079         _user = pwdInfo->pw_name;
00080 
00081     struct group * groupInfo = getgrgid( statInfo->st_gid );
00082 
00083     if ( groupInfo )
00084         _group = groupInfo->gr_name;
00085 
00086     if ( _mode & S_IRUSR )
00087         _perm += "r";
00088     else
00089         _perm += "-";
00090 
00091     if ( _mode & S_IWUSR )
00092         _perm += "w";
00093     else
00094         _perm += "-";
00095 
00096     if ( _mode & S_IXUSR )
00097         _perm += "x";
00098     else
00099         _perm += "-";
00100 
00101     if ( _mode & S_IRGRP )
00102         _perm += "r";
00103     else
00104         _perm += "-";
00105 
00106     if ( _mode & S_IWGRP )
00107         _perm += "w";
00108     else
00109         _perm += "-";
00110 
00111     if ( _mode & S_IXGRP )
00112         _perm += "x";
00113     else
00114         _perm += "-";
00115 
00116     if ( _mode & S_IROTH )
00117         _perm += "r";
00118     else
00119         _perm += "-";
00120 
00121     if ( _mode & S_IWOTH )
00122         _perm += "w";
00123     else
00124         _perm += "-";
00125 
00126     if ( _mode & S_IXOTH )
00127         _perm += "x";
00128     else
00129         _perm += "-";
00130 }
00131 
00132 
00133 NCFileInfo::NCFileInfo( )
00134 {
00135     _name   = "";
00136     _realName = "";
00137     _tag    = "";
00138     _perm   = "";
00139     _user   = "";
00140     _group  = "";
00141     _mode   = ( mode_t )0;
00142     _device = ( dev_t )0;
00143     _links  = ( nlink_t )0;
00144     _size   = ( off64_t )0;
00145     _mtime  = ( time_t )0;
00146 }
00147 
00148 
00149 NCFileSelectionTag::NCFileSelectionTag( NCFileInfo * info )
00150         : YTableCell( "  " )
00151         , fileInfo( info )
00152 {
00153     setLabel( fileInfo->_tag );
00154 }
00155 
00156 NCFileSelectionTag::~NCFileSelectionTag()
00157 {
00158     if ( fileInfo )
00159     {
00160         delete fileInfo;
00161     }
00162 }
00163 
00164 NCFileSelection::NCFileSelection( YWidget * parent,
00165                                   YTableHeader * tableHeader,
00166                                   NCFileSelectionType type,
00167                                   const std::string & iniDir )
00168     : NCTable( parent, tableHeader )
00169     , startDir( iniDir )
00170     , currentDir( iniDir )
00171     , tableType( type )
00172 {
00173     SetSepChar( ' ' );
00174     //setTextdomain( "ncurses" );
00175 
00176     struct stat64 statInfo;
00177 
00178     if ( !iniDir.empty() )
00179     {
00180         stat64( iniDir.c_str(), &statInfo );
00181     }
00182 
00183     if ( iniDir.empty()
00184          || !S_ISDIR( statInfo.st_mode ) )
00185     {
00186         char wDir[PATH_MAX+1];          // <limits.h>
00187 
00188         // start with working directory
00189 
00190         if ( getcwd( wDir, PATH_MAX ) )
00191         {
00192             startDir = wDir;
00193             currentDir = wDir;
00194         }
00195         else
00196         {
00197             startDir = "/";
00198             currentDir = "/";
00199         }
00200     }
00201 
00202     yuiDebug() << std::endl;
00203 }
00204 
00205 
00206 NCFileSelection::~NCFileSelection()
00207 {
00208     yuiDebug() << std::endl;
00209 }
00210 
00211 
00212 std::string     NCFileSelection::getCurrentLine( )
00213 {
00214     int index = getCurrentItem();
00215 
00216     if ( index != -1 )
00217     {
00218         NCFileInfo * info = getFileInfo( index );
00219         return info->_name;
00220     }
00221     else
00222     {
00223         return "";
00224     }
00225 }
00226 
00227 
00228 void NCFileSelection::setCurrentDir()
00229 {
00230     std::string selected = getCurrentLine();
00231     yuiMilestone() << "Current directory: " << selected << std::endl;
00232 
00233     if ( selected != ".." )
00234     {
00235         if ( startDir != "/" )
00236         {
00237             currentDir = startDir + "/" + selected;
00238         }
00239         else
00240         {
00241             currentDir = startDir + selected;
00242         }
00243     }
00244     else
00245     {
00246         size_t pos;
00247 
00248         if (( pos = currentDir.find_last_of( "/" ) ) != 0 )
00249         {
00250             currentDir = currentDir.substr( 0, pos );
00251         }
00252         else
00253         {
00254             currentDir = "/";
00255         }
00256     }
00257 }
00258 
00259 
00260 void NCFileSelection::addLine( const std::vector<std::string> & elements,
00261                                NCFileInfo * info )
00262 {
00263      YTableItem *tabItem = new YTableItem();
00264 
00265      tabItem->addCell( new NCFileSelectionTag( info ) );
00266 
00267      for ( unsigned i = 1; i < elements.size()+1; ++i ) {
00268         tabItem->addCell( elements[i-1] );
00269     }
00270 
00271     // use all-at-once insertion mode - DrawPad() is called only after the loop
00272     addItem(tabItem, true);
00273 }
00274 
00275 
00276 void NCFileSelection::deleteAllItems()
00277 {
00278     return NCTable::deleteAllItems();
00279 }
00280 
00281 
00282 bool NCFileTable::createListEntry( NCFileInfo * fileInfo )
00283 {
00284     std::vector<std::string> data;
00285 
00286     switch ( tableType )
00287     {
00288         case T_Overview:
00289             {
00290                 data.reserve( 2 );
00291                 data.push_back( fileInfo->_name );
00292                 break;
00293             }
00294         case T_Detailed:
00295             {
00296                 data.reserve( 6 );
00297                 data.push_back( fileInfo->_name );
00298                 char size_buf[50];
00299                 sprintf( size_buf, "%lld", ( long long int ) fileInfo->_size );
00300                 data.push_back( size_buf );
00301                 data.push_back( fileInfo->_perm );
00302                 data.push_back( fileInfo->_user );
00303                 data.push_back( fileInfo->_group );
00304                 break;
00305             }
00306         default:
00307             {
00308                 data.reserve( 2 );
00309                 data.push_back( " " );
00310                 data.push_back( " " );
00311                 break;
00312             }
00313     }
00314 
00315     addLine( data, fileInfo );
00316 
00317     return true;
00318 }
00319 
00320 
00321 bool NCDirectoryTable::createListEntry( NCFileInfo * fileInfo )
00322 {
00323     std::vector<std::string> data;
00324 
00325     switch ( tableType )
00326     {
00327         case T_Overview:
00328             {
00329                 data.reserve( 2 );
00330                 data.push_back( fileInfo->_name );
00331                 break;
00332             }
00333         case T_Detailed:
00334             {
00335                 data.reserve( 4 );
00336                 data.push_back( fileInfo->_name );
00337                 data.push_back( fileInfo->_perm );
00338                 data.push_back( fileInfo->_user );
00339                 data.push_back( fileInfo->_group );
00340                 break;
00341             }
00342         default:
00343             {
00344                 data.reserve( 2 );
00345                 data.push_back( " " );
00346                 data.push_back( " " );
00347                 break;
00348             }
00349     }
00350 
00351     addLine( data, fileInfo );
00352 
00353     return true;
00354 }
00355 
00356 
00357 NCFileInfo * NCFileSelection::getFileInfo( int index )
00358 {
00359     // get the tag
00360     NCFileSelectionTag *cc = getTag( index );
00361 
00362     if ( !cc )
00363         return 0;
00364 
00365     return cc->getFileInfo();
00366 }
00367 
00368 
00369 NCFileSelectionTag * NCFileSelection::getTag( const int & index )
00370 {
00371     // get the table line
00372     NCTableLine * cl = myPad()->ModifyLine( index );
00373 
00374     if ( !cl )
00375         return 0;
00376 
00377     // get first column (the column containing the status info)
00378     YTableItem *it = dynamic_cast<YTableItem*> (cl->origItem() );
00379     YTableCell *tcell = it->cell(0);
00380     NCFileSelectionTag * cc = static_cast<NCFileSelectionTag *>( tcell );
00381 
00382     return cc;
00383 }
00384 
00385 
00386 
00387 
00388 
00389 
00390 NCFileTable::NCFileTable( YWidget * parent,
00391                           YTableHeader * tableHeader,
00392                           NCFileSelectionType type,
00393                           const std::string & filter,
00394                           const std::string & iniDir )
00395     : NCFileSelection( parent, tableHeader, type, iniDir )
00396     , currentFile("")
00397 {
00398     //fillHeader();
00399 
00400     std::string filterStr = filter;
00401     const std::string delims( " \t" );
00402     std::string::size_type begin, end;
00403 
00404     begin = filterStr.find_first_not_of( delims );
00405 
00406     while ( begin != std::string::npos )
00407     {
00408         end = filterStr.find_first_of( delims, begin );
00409 
00410         if ( end == std::string::npos )
00411             end = filterStr.length();
00412 
00413         pattern.push_back( filterStr.substr( begin, end - begin ) );
00414         begin = filterStr.find_first_not_of( delims, end );
00415     }
00416 }
00417 
00418 
00419 /**
00420  * Fill the column headers of the file table
00421  **/
00422 void NCFileTable::fillHeader( )
00423 {
00424     std::vector<std::string> header;
00425     std::string old_textdomain = textdomain(NULL);
00426     setTextdomain( "ncurses" );
00427 
00428     switch ( tableType )
00429     {
00430         case T_Overview:
00431             {
00432                 header.reserve( 2 );
00433                 header.push_back( "L" + std::string( "  " ) );
00434                 // column header name of the file
00435                 header.push_back( "L" + std::string( _( "File name" ) ) );
00436                 break;
00437             }
00438 
00439         case T_Detailed:
00440             {
00441                 header.reserve( 6 );
00442                 header.push_back( "L" + std::string( "  " ) );
00443                 // column header name of the file
00444                 header.push_back( "L" + std::string( _( "File name" ) ) );
00445                 // column header size of the file
00446                 header.push_back( "L" + std::string( _( "Size" ) ) );
00447                 // column header file permissions
00448                 header.push_back( "L" + std::string( _( "Permissions" ) ) );
00449                 // column header user
00450                 header.push_back( "L" + std::string( _( "User" ) ) );
00451                 // column header group
00452                 header.push_back( "L" + std::string( _( "Group" ) ) );
00453                 break;
00454             }
00455 
00456         default:
00457             {
00458                 header.reserve( 2 );
00459                 header.push_back( "L" + std::string( "   " ) );
00460                 header.push_back( "L" + std::string( _( "File name" ) ) );
00461                 break;
00462             }
00463     }
00464 
00465     setHeader( header );
00466     // restore former text domain
00467     setTextdomain( old_textdomain.c_str() );
00468 }
00469 
00470 
00471 bool NCFileTable::filterMatch( const std::string & fileEntry )
00472 {
00473     if ( pattern.empty() )
00474         return true;
00475 
00476     bool match = false;
00477 
00478     std::list<std::string>::iterator it = pattern.begin();
00479 
00480     while ( it != pattern.end() )
00481     {
00482         if ( fnmatch(( *it ).c_str(), fileEntry.c_str(), FNM_PATHNAME ) == 0 )
00483             match = true;
00484 
00485         ++it;
00486     }
00487 
00488     return match;
00489 }
00490 
00491 
00492 NCursesEvent NCFileSelection::handleKeyEvents( wint_t key )
00493 {
00494     NCursesEvent ret = NCursesEvent::none;
00495 
00496     if ( sendKeyEvents() &&
00497          ( key == KEY_LEFT || key == KEY_RIGHT ) )
00498     {
00499         ret = NCursesEvent::key;
00500 
00501         switch ( key )
00502         {
00503             case KEY_LEFT:
00504                 ret.keySymbol = "CursorLeft";
00505                 break;
00506 
00507             case KEY_RIGHT:
00508                 ret.keySymbol = "CursorRight";
00509                 break;
00510         }
00511     }
00512 
00513     return ret;
00514 }
00515 
00516 
00517 NCursesEvent NCFileTable::wHandleInput( wint_t key )
00518 {
00519     NCursesEvent ret = handleKeyEvents( key );
00520 
00521     // return key event
00522 
00523     if ( ret == NCursesEvent::key )
00524         return ret;
00525 
00526     // call handleInput of NCPad
00527     handleInput( key );
00528 
00529     currentFile = getCurrentLine();
00530 
00531     switch ( key )
00532     {
00533         case KEY_UP:
00534         case KEY_PPAGE:
00535         case KEY_HOME:
00536         case KEY_DOWN:
00537         case KEY_NPAGE:
00538         case KEY_END:
00539             {
00540                 ret = NCursesEvent::SelectionChanged;
00541                 ret.result = currentFile;
00542                 break;
00543             }
00544 
00545         default:
00546             ret = NCursesEvent::none;
00547     }
00548 
00549     yuiDebug() << "CURRENT_FILE: " << currentFile << std::endl;
00550 
00551     return ret;
00552 }
00553 
00554 
00555 bool NCFileTable::fillList()
00556 {
00557 
00558     struct stat64       statInfo;
00559     struct stat64       linkInfo;
00560     struct dirent *     entry;
00561     std::list<std::string>      tmpList;
00562     std::list<std::string>::iterator   it;
00563 
00564     fillHeader();       // create the column headers
00565 
00566     DIR * diskDir = opendir( currentDir.c_str() );
00567 
00568     if ( diskDir )
00569     {
00570         deleteAllItems();
00571 
00572         while (( entry = readdir( diskDir ) ) )
00573         {
00574             std::string entryName = entry->d_name;
00575 
00576             if ( entryName != "."
00577                  && filterMatch( entryName ) )
00578             {
00579                 tmpList.push_back( entryName );
00580             }
00581         }
00582 
00583         // sort the list and fill the table widget with file entries
00584         tmpList.sort( );
00585         it = tmpList.begin();
00586 
00587         while ( it != tmpList.end() )
00588         {
00589             std::string fullName = currentDir + "/" + ( *it );
00590 
00591             if ( lstat64( fullName.c_str(), &statInfo ) == 0 )
00592             {
00593                 if ( S_ISREG( statInfo.st_mode ) || S_ISBLK( statInfo.st_mode ) )
00594                 {
00595                     if ((( *it ) == ".." && currentDir != "/" )
00596                         || ( *it ) != ".." )
00597                     {
00598                         createListEntry( new NCFileInfo(( *it ), &statInfo ) );
00599                     }
00600                 }
00601                 else if ( S_ISLNK( statInfo.st_mode ) )
00602                 {
00603                     if ( stat64( fullName.c_str(), &linkInfo ) == 0 )
00604                     {
00605                         if ( S_ISREG( linkInfo.st_mode ) || S_ISBLK( linkInfo.st_mode ) )
00606                         {
00607                             createListEntry( new NCFileInfo(( *it ), &linkInfo, true ) );
00608                         }
00609                     }
00610                 }
00611             }
00612 
00613             ++it;
00614         }
00615 
00616         drawList();             // draw the list
00617 
00618         if ( getNumLines() > 0 )
00619         {
00620             setCurrentItem( 0 );        // set focus to the first list entry
00621             currentFile = getCurrentLine();
00622         }
00623         else
00624         {
00625             currentFile = "";
00626         }
00627 
00628         closedir( diskDir );
00629     }
00630     else
00631     {
00632         yuiError() << "ERROR opening directory: " << currentDir << " errno: "
00633                    << strerror( errno ) << std::endl;
00634         return false;
00635     }
00636 
00637     return true;
00638 }
00639 
00640 
00641 NCDirectoryTable::NCDirectoryTable( YWidget * parent,
00642                                     YTableHeader * tableHeader,
00643                                     NCFileSelectionType type,
00644                                     const std::string & iniDir )
00645     : NCFileSelection( parent, tableHeader, type, iniDir )
00646 {
00647     //fillHeader();
00648 }
00649 
00650 
00651 /**
00652  * Fill the column headers of the table
00653  **/
00654 void NCDirectoryTable::fillHeader()
00655 {
00656     std::vector<std::string> header;
00657     std::string old_textdomain = textdomain(NULL);
00658     setTextdomain( "ncurses" );
00659 
00660     switch ( tableType )
00661     {
00662         case T_Overview:
00663             {
00664                 header.reserve( 2 );
00665                 header.push_back( "L" + std::string( "  " ) );
00666                 // column header name of diretcory
00667                 header.push_back( "L" + std::string( _( "Directory Name" ) ) );
00668                 break;
00669             }
00670 
00671         case T_Detailed:
00672             {
00673                 header.reserve( 5 );
00674                 header.push_back( "L" + std::string( "  " ) );
00675                 // column header name of diretcory
00676                 header.push_back( "L" + std::string( _( "Directory Name" ) ) );
00677                 header.push_back( "L" + std::string( _( "Permissions" ) ) );
00678                 header.push_back( "L" + std::string( _( "User" ) ) );
00679                 header.push_back( "L" + std::string( _( "Group" ) ) );
00680                 break;
00681             }
00682 
00683         default:
00684             {
00685                 header.reserve( 2 );
00686                 header.push_back( "L" + std::string( "   " ) );
00687                 header.push_back( "L" + std::string( _( "Directory Name" ) ) );
00688                 break;
00689             }
00690     }
00691 
00692     setHeader( header );
00693     // restore former text domain
00694     setTextdomain( old_textdomain.c_str() );
00695 }
00696 
00697 
00698 bool NCDirectoryTable::fillList()
00699 {
00700     struct stat64       statInfo;
00701     struct stat64       linkInfo;
00702     struct dirent *     entry;
00703     std::list<std::string>      tmpList;
00704     std::list<std::string>::iterator   it;
00705 
00706     fillHeader();       // create the column headers
00707 
00708     DIR * diskDir = opendir( currentDir.c_str() );
00709 
00710     if ( diskDir )
00711     {
00712         deleteAllItems();
00713 
00714         while (( entry = readdir( diskDir ) ) )
00715         {
00716             std::string entryName = entry->d_name;
00717 
00718             if ( entryName != "." )
00719             {
00720                 tmpList.push_back( entryName );
00721             }
00722         }
00723 
00724         // sort the list and fill the table widget with directory entries
00725         tmpList.sort( );
00726 
00727         it = tmpList.begin();
00728 
00729         while ( it != tmpList.end() )
00730         {
00731             std::string fullName = currentDir + "/" + ( *it );
00732 
00733             if ( lstat64( fullName.c_str(), &statInfo ) == 0 )
00734             {
00735                 if ( S_ISDIR( statInfo.st_mode ) )
00736                 {
00737                     if ((( *it ) == ".." && currentDir != "/" )
00738                         || ( *it ) != ".." )
00739                     {
00740                         createListEntry( new NCFileInfo(( *it ), &statInfo ) );
00741                     }
00742                 }
00743                 else if ( S_ISLNK( statInfo.st_mode ) )
00744                 {
00745                     if ( stat64( fullName.c_str(), &linkInfo ) == 0 )
00746                     {
00747                         if ( S_ISDIR( linkInfo.st_mode ) )
00748                         {
00749                             createListEntry( new NCFileInfo(( *it ), &linkInfo, true ) );
00750                         }
00751                     }
00752                 }
00753             }
00754 
00755             ++it;
00756         }
00757 
00758         drawList();             // draw the list
00759         startDir = currentDir;  // set start directory
00760 
00761         if ( getNumLines() > 0 )
00762             setCurrentItem( 0 );        // set focus to the first list entry
00763 
00764         closedir( diskDir );
00765     }
00766     else
00767     {
00768         yuiError() << "ERROR opening directory: " << currentDir << " errno: "
00769         << strerror( errno ) << std::endl;
00770 
00771         return false;
00772     }
00773 
00774     return true;
00775 }
00776 
00777 
00778 NCursesEvent NCDirectoryTable::wHandleInput( wint_t key )
00779 {
00780     NCursesEvent ret = handleKeyEvents( key );
00781 
00782     // return key event
00783 
00784     if ( ret == NCursesEvent::key )
00785         return ret;
00786 
00787     unsigned int old_pos = getCurrentItem();
00788 
00789     // call handleInput of NCPad
00790     handleInput( key );
00791 
00792     switch ( key )
00793     {
00794         case KEY_UP:
00795         case KEY_PPAGE:
00796         case KEY_HOME:
00797             {
00798                 if ( old_pos != 0 )
00799                 {
00800                     setCurrentDir();
00801                     ret = NCursesEvent::SelectionChanged;
00802                     ret.result = currentDir;
00803                 }
00804 
00805                 break;
00806             }
00807 
00808         case KEY_DOWN:
00809         case KEY_NPAGE:
00810         case KEY_END:
00811             {
00812                 setCurrentDir();
00813                 ret = NCursesEvent::SelectionChanged;
00814                 ret.result = currentDir;
00815                 break;
00816             }
00817 
00818         case KEY_RETURN:
00819         case KEY_SPACE:
00820             {
00821                 setCurrentDir();
00822                 ret = NCursesEvent::Activated;
00823                 ret.result = currentDir;
00824                 break;
00825             }
00826 
00827         default:
00828             ret = NCursesEvent::none;
00829     }
00830 
00831     yuiDebug() << "CURRENT: " << currentDir << " START DIR: " << startDir << std::endl;
00832 
00833     return ret;
00834 }
00835 
00836 
00837 
 All Classes Functions Variables