libyui-ncurses
2.44.1
|
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