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