libyui-ncurses  2.46.7
NCFileSelection.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: NCFileSelection.cc
20 
21  Author: Gabriele Strattner <gs@suse.de>
22 
23 /-*/
24 
25 #define YUILogComponent "ncurses"
26 #include <yui/YUILog.h>
27 #include "NCFileSelection.h"
28 #include "NCTable.h"
29 #include "NCi18n.h"
30 
31 #include <fnmatch.h>
32 #include <grp.h>
33 #include <pwd.h>
34 #include <string.h> // strerror()
35 #include <sys/types.h>
36 
37 /*
38  Textdomain "ncurses"
39 */
40 
41 
42 
43 NCFileInfo::NCFileInfo( std::string fileName,
44  struct stat64 * statInfo,
45  bool link )
46 {
47  _name = fileName;
48  _mode = statInfo->st_mode;
49  _device = statInfo->st_dev;
50  _links = statInfo->st_nlink;
51  _size = statInfo->st_size;
52  _mtime = statInfo->st_mtime;
53 
54  if ( link )
55  {
56  char tmpName[PATH_MAX+1];
57  // get actual file name
58  int len = readlink( fileName.c_str(), tmpName, PATH_MAX );
59 
60  if ( len >= 0 )
61  {
62  tmpName[len] = '\0';
63  _realName = tmpName;
64  }
65 
66  _tag = " @"; // set tag
67  }
68  else if ( S_ISREG( _mode )
69  && ( _mode & S_IXUSR ) )
70  _tag = " *"; // user executable files
71  else
72  _tag = " ";
73 
74  // get user and group name
75 
76  struct passwd * pwdInfo = getpwuid( statInfo->st_uid );
77 
78  if ( pwdInfo )
79  _user = pwdInfo->pw_name;
80 
81  struct group * groupInfo = getgrgid( statInfo->st_gid );
82 
83  if ( groupInfo )
84  _group = groupInfo->gr_name;
85 
86  if ( _mode & S_IRUSR )
87  _perm += "r";
88  else
89  _perm += "-";
90 
91  if ( _mode & S_IWUSR )
92  _perm += "w";
93  else
94  _perm += "-";
95 
96  if ( _mode & S_IXUSR )
97  _perm += "x";
98  else
99  _perm += "-";
100 
101  if ( _mode & S_IRGRP )
102  _perm += "r";
103  else
104  _perm += "-";
105 
106  if ( _mode & S_IWGRP )
107  _perm += "w";
108  else
109  _perm += "-";
110 
111  if ( _mode & S_IXGRP )
112  _perm += "x";
113  else
114  _perm += "-";
115 
116  if ( _mode & S_IROTH )
117  _perm += "r";
118  else
119  _perm += "-";
120 
121  if ( _mode & S_IWOTH )
122  _perm += "w";
123  else
124  _perm += "-";
125 
126  if ( _mode & S_IXOTH )
127  _perm += "x";
128  else
129  _perm += "-";
130 }
131 
132 
133 NCFileInfo::NCFileInfo( )
134 {
135  _name = "";
136  _realName = "";
137  _tag = "";
138  _perm = "";
139  _user = "";
140  _group = "";
141  _mode = ( mode_t )0;
142  _device = ( dev_t )0;
143  _links = ( nlink_t )0;
144  _size = ( off64_t )0;
145  _mtime = ( time_t )0;
146 }
147 
148 
149 NCFileSelectionTag::NCFileSelectionTag( NCFileInfo * info )
150  : YTableCell( " " )
151  , fileInfo( info )
152 {
153  setLabel( fileInfo->_tag );
154 }
155 
156 NCFileSelectionTag::~NCFileSelectionTag()
157 {
158  if ( fileInfo )
159  {
160  delete fileInfo;
161  }
162 }
163 
164 NCFileSelection::NCFileSelection( YWidget * parent,
165  YTableHeader * tableHeader,
166  NCFileSelectionType type,
167  const std::string & iniDir )
168  : NCTable( parent, tableHeader )
169  , startDir( iniDir )
170  , currentDir( iniDir )
171  , tableType( type )
172 {
173  SetSepChar( ' ' );
174 
175  struct stat64 statInfo;
176 
177  if ( !iniDir.empty() )
178  {
179  stat64( iniDir.c_str(), &statInfo );
180  }
181 
182  if ( iniDir.empty()
183  || !S_ISDIR( statInfo.st_mode ) )
184  {
185  char wDir[PATH_MAX+1]; // <limits.h>
186 
187  // start with working directory
188 
189  if ( getcwd( wDir, PATH_MAX ) )
190  {
191  startDir = wDir;
192  currentDir = wDir;
193  }
194  else
195  {
196  startDir = "/";
197  currentDir = "/";
198  }
199  }
200 
201  yuiDebug() << std::endl;
202 }
203 
204 
205 NCFileSelection::~NCFileSelection()
206 {
207  yuiDebug() << std::endl;
208 }
209 
210 
211 std::string NCFileSelection::getCurrentLine( )
212 {
213  int index = getCurrentItem();
214 
215  if ( index != -1 )
216  {
217  NCFileInfo * info = getFileInfo( index );
218  return info->_name;
219  }
220  else
221  {
222  return "";
223  }
224 }
225 
226 
227 void NCFileSelection::setCurrentDir()
228 {
229  std::string selected = getCurrentLine();
230  yuiMilestone() << "Current directory: " << selected << std::endl;
231 
232  if ( selected != ".." )
233  {
234  if ( startDir != "/" )
235  {
236  currentDir = startDir + "/" + selected;
237  }
238  else
239  {
240  currentDir = startDir + selected;
241  }
242  }
243  else
244  {
245  size_t pos;
246 
247  if (( pos = currentDir.find_last_of( "/" ) ) != 0 )
248  {
249  currentDir = currentDir.substr( 0, pos );
250  }
251  else
252  {
253  currentDir = "/";
254  }
255  }
256 }
257 
258 
259 void NCFileSelection::addLine( const std::vector<std::string> & elements,
260  NCFileInfo * info )
261 {
262  YTableItem *tabItem = new YTableItem();
263 
264  tabItem->addCell( new NCFileSelectionTag( info ) );
265 
266  for ( unsigned i = 1; i < elements.size()+1; ++i ) {
267  tabItem->addCell( elements[i-1] );
268  }
269 
270  // use all-at-once insertion mode - DrawPad() is called only after the loop
271  addItem(tabItem, true);
272 }
273 
274 
276 {
277  return NCTable::deleteAllItems();
278 }
279 
280 
282 {
283  std::vector<std::string> data;
284 
285  switch ( tableType )
286  {
287  case T_Overview:
288  {
289  data.reserve( 2 );
290  data.push_back( fileInfo->_name );
291  break;
292  }
293  case T_Detailed:
294  {
295  data.reserve( 6 );
296  data.push_back( fileInfo->_name );
297  char size_buf[50];
298  sprintf( size_buf, "%lld", ( long long int ) fileInfo->_size );
299  data.push_back( size_buf );
300  data.push_back( fileInfo->_perm );
301  data.push_back( fileInfo->_user );
302  data.push_back( fileInfo->_group );
303  break;
304  }
305  default:
306  {
307  data.reserve( 2 );
308  data.push_back( " " );
309  data.push_back( " " );
310  break;
311  }
312  }
313 
314  addLine( data, fileInfo );
315 
316  return true;
317 }
318 
319 
321 {
322  std::vector<std::string> data;
323 
324  switch ( tableType )
325  {
326  case T_Overview:
327  {
328  data.reserve( 2 );
329  data.push_back( fileInfo->_name );
330  break;
331  }
332  case T_Detailed:
333  {
334  data.reserve( 4 );
335  data.push_back( fileInfo->_name );
336  data.push_back( fileInfo->_perm );
337  data.push_back( fileInfo->_user );
338  data.push_back( fileInfo->_group );
339  break;
340  }
341  default:
342  {
343  data.reserve( 2 );
344  data.push_back( " " );
345  data.push_back( " " );
346  break;
347  }
348  }
349 
350  addLine( data, fileInfo );
351 
352  return true;
353 }
354 
355 
357 {
358  // get the tag
359  NCFileSelectionTag *cc = getTag( index );
360 
361  if ( !cc )
362  return 0;
363 
364  return cc->getFileInfo();
365 }
366 
367 
368 NCFileSelectionTag * NCFileSelection::getTag( const int & index )
369 {
370  // get the table line
371  NCTableLine * cl = myPad()->ModifyLine( index );
372 
373  if ( !cl )
374  return 0;
375 
376  // get first column (the column containing the status info)
377  YTableItem *it = dynamic_cast<YTableItem*> (cl->origItem() );
378  YTableCell *tcell = it->cell(0);
379  NCFileSelectionTag * cc = static_cast<NCFileSelectionTag *>( tcell );
380 
381  return cc;
382 }
383 
384 
385 
386 
387 
388 
389 NCFileTable::NCFileTable( YWidget * parent,
390  YTableHeader * tableHeader,
391  NCFileSelectionType type,
392  const std::string & filter,
393  const std::string & iniDir )
394  : NCFileSelection( parent, tableHeader, type, iniDir )
395  , currentFile("")
396 {
397  //fillHeader();
398 
399  std::string filterStr = filter;
400  const std::string delims( " \t" );
401  std::string::size_type begin, end;
402 
403  begin = filterStr.find_first_not_of( delims );
404 
405  while ( begin != std::string::npos )
406  {
407  end = filterStr.find_first_of( delims, begin );
408 
409  if ( end == std::string::npos )
410  end = filterStr.length();
411 
412  pattern.push_back( filterStr.substr( begin, end - begin ) );
413  begin = filterStr.find_first_not_of( delims, end );
414  }
415 }
416 
417 
418 /**
419  * Fill the column headers of the file table
420  **/
422 {
423  std::vector<std::string> header;
424  std::string old_textdomain = textdomain(NULL);
425  setTextdomain( "ncurses" );
426 
427  switch ( tableType )
428  {
429  case T_Overview:
430  {
431  header.reserve( 2 );
432  header.push_back( "L" + std::string( " " ) );
433  // column header name of the file
434  header.push_back( "L" + std::string( _( "File name" ) ) );
435  break;
436  }
437 
438  case T_Detailed:
439  {
440  header.reserve( 6 );
441  header.push_back( "L" + std::string( " " ) );
442  // column header name of the file
443  header.push_back( "L" + std::string( _( "File name" ) ) );
444  // column header size of the file
445  header.push_back( "L" + std::string( _( "Size" ) ) );
446  // column header file permissions
447  header.push_back( "L" + std::string( _( "Permissions" ) ) );
448  // column header user
449  header.push_back( "L" + std::string( _( "User" ) ) );
450  // column header group
451  header.push_back( "L" + std::string( _( "Group" ) ) );
452  break;
453  }
454 
455  default:
456  {
457  header.reserve( 2 );
458  header.push_back( "L" + std::string( " " ) );
459  header.push_back( "L" + std::string( _( "File name" ) ) );
460  break;
461  }
462  }
463 
464  setHeader( header );
465  // restore former text domain
466  setTextdomain( old_textdomain.c_str() );
467 }
468 
469 
470 bool NCFileTable::filterMatch( const std::string & fileEntry )
471 {
472  if ( pattern.empty() )
473  return true;
474 
475  bool match = false;
476 
477  std::list<std::string>::iterator it = pattern.begin();
478 
479  while ( it != pattern.end() )
480  {
481  if ( fnmatch(( *it ).c_str(), fileEntry.c_str(), FNM_PATHNAME ) == 0 )
482  match = true;
483 
484  ++it;
485  }
486 
487  return match;
488 }
489 
490 
491 NCursesEvent NCFileSelection::handleKeyEvents( wint_t key )
492 {
493  NCursesEvent ret = NCursesEvent::none;
494 
495  if ( sendKeyEvents() &&
496  ( key == KEY_LEFT || key == KEY_RIGHT ) )
497  {
498  ret = NCursesEvent::key;
499 
500  switch ( key )
501  {
502  case KEY_LEFT:
503  ret.keySymbol = "CursorLeft";
504  break;
505 
506  case KEY_RIGHT:
507  ret.keySymbol = "CursorRight";
508  break;
509  }
510  }
511 
512  return ret;
513 }
514 
515 
516 NCursesEvent NCFileTable::wHandleInput( wint_t key )
517 {
518  NCursesEvent ret = handleKeyEvents( key );
519 
520  // return key event
521 
522  if ( ret == NCursesEvent::key )
523  return ret;
524 
525  // call handleInput of NCPad
526  handleInput( key );
527 
528  currentFile = getCurrentLine();
529 
530  switch ( key )
531  {
532  case KEY_UP:
533  case KEY_PPAGE:
534  case KEY_HOME:
535  case KEY_DOWN:
536  case KEY_NPAGE:
537  case KEY_END:
538  {
539  ret = NCursesEvent::SelectionChanged;
540  ret.result = currentFile;
541  break;
542  }
543 
544  default:
545  ret = NCursesEvent::none;
546  }
547 
548  yuiDebug() << "CURRENT_FILE: " << currentFile << std::endl;
549 
550  return ret;
551 }
552 
553 
555 {
556 
557  struct stat64 statInfo;
558  struct stat64 linkInfo;
559  struct dirent * entry;
560  std::list<std::string> tmpList;
561  std::list<std::string>::iterator it;
562 
563  fillHeader(); // create the column headers
564 
565  DIR * diskDir = opendir( currentDir.c_str() );
566 
567  if ( diskDir )
568  {
569  deleteAllItems();
570 
571  while (( entry = readdir( diskDir ) ) )
572  {
573  std::string entryName = entry->d_name;
574 
575  if ( entryName != "."
576  && filterMatch( entryName ) )
577  {
578  tmpList.push_back( entryName );
579  }
580  }
581 
582  // sort the list and fill the table widget with file entries
583  tmpList.sort( );
584  it = tmpList.begin();
585 
586  while ( it != tmpList.end() )
587  {
588  std::string fullName = currentDir + "/" + ( *it );
589 
590  if ( lstat64( fullName.c_str(), &statInfo ) == 0 )
591  {
592  if ( S_ISREG( statInfo.st_mode ) || S_ISBLK( statInfo.st_mode ) )
593  {
594  if ((( *it ) == ".." && currentDir != "/" )
595  || ( *it ) != ".." )
596  {
597  createListEntry( new NCFileInfo(( *it ), &statInfo ) );
598  }
599  }
600  else if ( S_ISLNK( statInfo.st_mode ) )
601  {
602  if ( stat64( fullName.c_str(), &linkInfo ) == 0 )
603  {
604  if ( S_ISREG( linkInfo.st_mode ) || S_ISBLK( linkInfo.st_mode ) )
605  {
606  createListEntry( new NCFileInfo(( *it ), &linkInfo, true ) );
607  }
608  }
609  }
610  }
611 
612  ++it;
613  }
614 
615  drawList(); // draw the list
616 
617  if ( getNumLines() > 0 )
618  {
619  setCurrentItem( 0 ); // set focus to the first list entry
620  currentFile = getCurrentLine();
621  }
622  else
623  {
624  currentFile = "";
625  }
626 
627  closedir( diskDir );
628  }
629  else
630  {
631  yuiError() << "ERROR opening directory: " << currentDir << " errno: "
632  << strerror( errno ) << std::endl;
633  return false;
634  }
635 
636  return true;
637 }
638 
639 
640 NCDirectoryTable::NCDirectoryTable( YWidget * parent,
641  YTableHeader * tableHeader,
642  NCFileSelectionType type,
643  const std::string & iniDir )
644  : NCFileSelection( parent, tableHeader, type, iniDir )
645 {
646  //fillHeader();
647 }
648 
649 
650 /**
651  * Fill the column headers of the table
652  **/
654 {
655  std::vector<std::string> header;
656  std::string old_textdomain = textdomain(NULL);
657  setTextdomain( "ncurses" );
658 
659  switch ( tableType )
660  {
661  case T_Overview:
662  {
663  header.reserve( 2 );
664  header.push_back( "L" + std::string( " " ) );
665  // column header name of diretcory
666  header.push_back( "L" + std::string( _( "Directory Name" ) ) );
667  break;
668  }
669 
670  case T_Detailed:
671  {
672  header.reserve( 5 );
673  header.push_back( "L" + std::string( " " ) );
674  // column header name of diretcory
675  header.push_back( "L" + std::string( _( "Directory Name" ) ) );
676  header.push_back( "L" + std::string( _( "Permissions" ) ) );
677  header.push_back( "L" + std::string( _( "User" ) ) );
678  header.push_back( "L" + std::string( _( "Group" ) ) );
679  break;
680  }
681 
682  default:
683  {
684  header.reserve( 2 );
685  header.push_back( "L" + std::string( " " ) );
686  header.push_back( "L" + std::string( _( "Directory Name" ) ) );
687  break;
688  }
689  }
690 
691  setHeader( header );
692  // restore former text domain
693  setTextdomain( old_textdomain.c_str() );
694 }
695 
696 
698 {
699  struct stat64 statInfo;
700  struct stat64 linkInfo;
701  struct dirent * entry;
702  std::list<std::string> tmpList;
703  std::list<std::string>::iterator it;
704 
705  fillHeader(); // create the column headers
706 
707  DIR * diskDir = opendir( currentDir.c_str() );
708 
709  if ( diskDir )
710  {
711  deleteAllItems();
712 
713  while (( entry = readdir( diskDir ) ) )
714  {
715  std::string entryName = entry->d_name;
716 
717  if ( entryName != "." )
718  {
719  tmpList.push_back( entryName );
720  }
721  }
722 
723  // sort the list and fill the table widget with directory entries
724  tmpList.sort( );
725 
726  it = tmpList.begin();
727 
728  while ( it != tmpList.end() )
729  {
730  std::string fullName = currentDir + "/" + ( *it );
731 
732  if ( lstat64( fullName.c_str(), &statInfo ) == 0 )
733  {
734  if ( S_ISDIR( statInfo.st_mode ) )
735  {
736  if ((( *it ) == ".." && currentDir != "/" )
737  || ( *it ) != ".." )
738  {
739  createListEntry( new NCFileInfo(( *it ), &statInfo ) );
740  }
741  }
742  else if ( S_ISLNK( statInfo.st_mode ) )
743  {
744  if ( stat64( fullName.c_str(), &linkInfo ) == 0 )
745  {
746  if ( S_ISDIR( linkInfo.st_mode ) )
747  {
748  createListEntry( new NCFileInfo(( *it ), &linkInfo, true ) );
749  }
750  }
751  }
752  }
753 
754  ++it;
755  }
756 
757  drawList(); // draw the list
758  startDir = currentDir; // set start directory
759 
760  if ( getNumLines() > 0 )
761  setCurrentItem( 0 ); // set focus to the first list entry
762 
763  closedir( diskDir );
764  }
765  else
766  {
767  yuiError() << "ERROR opening directory: " << currentDir << " errno: "
768  << strerror( errno ) << std::endl;
769 
770  return false;
771  }
772 
773  return true;
774 }
775 
776 
777 NCursesEvent NCDirectoryTable::wHandleInput( wint_t key )
778 {
779  NCursesEvent ret = handleKeyEvents( key );
780 
781  // return key event
782 
783  if ( ret == NCursesEvent::key )
784  return ret;
785 
786  unsigned int old_pos = getCurrentItem();
787 
788  // call handleInput of NCPad
789  handleInput( key );
790 
791  switch ( key )
792  {
793  case KEY_UP:
794  case KEY_PPAGE:
795  case KEY_HOME:
796  {
797  if ( old_pos != 0 )
798  {
799  setCurrentDir();
800  ret = NCursesEvent::SelectionChanged;
801  ret.result = currentDir;
802  }
803 
804  break;
805  }
806 
807  case KEY_DOWN:
808  case KEY_NPAGE:
809  case KEY_END:
810  {
811  setCurrentDir();
812  ret = NCursesEvent::SelectionChanged;
813  ret.result = currentDir;
814  break;
815  }
816 
817  case KEY_RETURN:
818  case KEY_SPACE:
819  {
820  setCurrentDir();
821  ret = NCursesEvent::Activated;
822  ret.result = currentDir;
823  break;
824  }
825 
826  default:
827  ret = NCursesEvent::none;
828  }
829 
830  yuiDebug() << "CURRENT: " << currentDir << " START DIR: " << startDir << std::endl;
831 
832  return ret;
833 }
834 
835 
836 
This class is used for the first column of the file table.
NCFileInfo * getFileInfo(int index)
Get the file info.
virtual NCTablePad * myPad() const
Overload myPad to narrow the type.
Definition: NCTable.h:102
virtual bool fillList()
Fill the std::list of files Returns 'true' on success.
virtual void fillHeader()
Fill the column headers of the file table.
NCFileTable(YWidget *parent, YTableHeader *tableHeader, NCFileSelectionType type, const std::string &filter, const std::string &iniDir)
Constructor.
NCFileInfo(std::string fileName, struct stat64 *statInfo, bool link=false)
Constructor from a stat buffer (i.e.
void drawList()
Draws the file std::list (has to be called after the loop with addLine() calls)
virtual bool createListEntry(NCFileInfo *fileInfo)
Creates a line in the package table.
The class which provides methods to handle a std::list of files or directories.
virtual void fillHeader()
Fill the column headers of the table.
virtual bool createListEntry(NCFileInfo *fileInfo)
Creates a line in the package table.
virtual bool fillList()
Fill the std::list of directories.
virtual void deleteAllItems()
Clears the package std::list.
unsigned int getNumLines()
Get number of lines ( std::list entries )