libyui-ncurses  2.44.1
 All Classes Functions Variables
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  //setTextdomain( "ncurses" );
175 
176  struct stat64 statInfo;
177 
178  if ( !iniDir.empty() )
179  {
180  stat64( iniDir.c_str(), &statInfo );
181  }
182 
183  if ( iniDir.empty()
184  || !S_ISDIR( statInfo.st_mode ) )
185  {
186  char wDir[PATH_MAX+1]; // <limits.h>
187 
188  // start with working directory
189 
190  if ( getcwd( wDir, PATH_MAX ) )
191  {
192  startDir = wDir;
193  currentDir = wDir;
194  }
195  else
196  {
197  startDir = "/";
198  currentDir = "/";
199  }
200  }
201 
202  yuiDebug() << std::endl;
203 }
204 
205 
206 NCFileSelection::~NCFileSelection()
207 {
208  yuiDebug() << std::endl;
209 }
210 
211 
212 std::string NCFileSelection::getCurrentLine( )
213 {
214  int index = getCurrentItem();
215 
216  if ( index != -1 )
217  {
218  NCFileInfo * info = getFileInfo( index );
219  return info->_name;
220  }
221  else
222  {
223  return "";
224  }
225 }
226 
227 
228 void NCFileSelection::setCurrentDir()
229 {
230  std::string selected = getCurrentLine();
231  yuiMilestone() << "Current directory: " << selected << std::endl;
232 
233  if ( selected != ".." )
234  {
235  if ( startDir != "/" )
236  {
237  currentDir = startDir + "/" + selected;
238  }
239  else
240  {
241  currentDir = startDir + selected;
242  }
243  }
244  else
245  {
246  size_t pos;
247 
248  if (( pos = currentDir.find_last_of( "/" ) ) != 0 )
249  {
250  currentDir = currentDir.substr( 0, pos );
251  }
252  else
253  {
254  currentDir = "/";
255  }
256  }
257 }
258 
259 
260 void NCFileSelection::addLine( const std::vector<std::string> & elements,
261  NCFileInfo * info )
262 {
263  YTableItem *tabItem = new YTableItem();
264 
265  tabItem->addCell( new NCFileSelectionTag( info ) );
266 
267  for ( unsigned i = 1; i < elements.size()+1; ++i ) {
268  tabItem->addCell( elements[i-1] );
269  }
270 
271  // use all-at-once insertion mode - DrawPad() is called only after the loop
272  addItem(tabItem, true);
273 }
274 
275 
277 {
278  return NCTable::deleteAllItems();
279 }
280 
281 
283 {
284  std::vector<std::string> data;
285 
286  switch ( tableType )
287  {
288  case T_Overview:
289  {
290  data.reserve( 2 );
291  data.push_back( fileInfo->_name );
292  break;
293  }
294  case T_Detailed:
295  {
296  data.reserve( 6 );
297  data.push_back( fileInfo->_name );
298  char size_buf[50];
299  sprintf( size_buf, "%lld", ( long long int ) fileInfo->_size );
300  data.push_back( size_buf );
301  data.push_back( fileInfo->_perm );
302  data.push_back( fileInfo->_user );
303  data.push_back( fileInfo->_group );
304  break;
305  }
306  default:
307  {
308  data.reserve( 2 );
309  data.push_back( " " );
310  data.push_back( " " );
311  break;
312  }
313  }
314 
315  addLine( data, fileInfo );
316 
317  return true;
318 }
319 
320 
322 {
323  std::vector<std::string> data;
324 
325  switch ( tableType )
326  {
327  case T_Overview:
328  {
329  data.reserve( 2 );
330  data.push_back( fileInfo->_name );
331  break;
332  }
333  case T_Detailed:
334  {
335  data.reserve( 4 );
336  data.push_back( fileInfo->_name );
337  data.push_back( fileInfo->_perm );
338  data.push_back( fileInfo->_user );
339  data.push_back( fileInfo->_group );
340  break;
341  }
342  default:
343  {
344  data.reserve( 2 );
345  data.push_back( " " );
346  data.push_back( " " );
347  break;
348  }
349  }
350 
351  addLine( data, fileInfo );
352 
353  return true;
354 }
355 
356 
358 {
359  // get the tag
360  NCFileSelectionTag *cc = getTag( index );
361 
362  if ( !cc )
363  return 0;
364 
365  return cc->getFileInfo();
366 }
367 
368 
369 NCFileSelectionTag * NCFileSelection::getTag( const int & index )
370 {
371  // get the table line
372  NCTableLine * cl = myPad()->ModifyLine( index );
373 
374  if ( !cl )
375  return 0;
376 
377  // get first column (the column containing the status info)
378  YTableItem *it = dynamic_cast<YTableItem*> (cl->origItem() );
379  YTableCell *tcell = it->cell(0);
380  NCFileSelectionTag * cc = static_cast<NCFileSelectionTag *>( tcell );
381 
382  return cc;
383 }
384 
385 
386 
387 
388 
389 
390 NCFileTable::NCFileTable( YWidget * parent,
391  YTableHeader * tableHeader,
392  NCFileSelectionType type,
393  const std::string & filter,
394  const std::string & iniDir )
395  : NCFileSelection( parent, tableHeader, type, iniDir )
396  , currentFile("")
397 {
398  //fillHeader();
399 
400  std::string filterStr = filter;
401  const std::string delims( " \t" );
402  std::string::size_type begin, end;
403 
404  begin = filterStr.find_first_not_of( delims );
405 
406  while ( begin != std::string::npos )
407  {
408  end = filterStr.find_first_of( delims, begin );
409 
410  if ( end == std::string::npos )
411  end = filterStr.length();
412 
413  pattern.push_back( filterStr.substr( begin, end - begin ) );
414  begin = filterStr.find_first_not_of( delims, end );
415  }
416 }
417 
418 
419 /**
420  * Fill the column headers of the file table
421  **/
423 {
424  std::vector<std::string> header;
425  std::string old_textdomain = textdomain(NULL);
426  setTextdomain( "ncurses" );
427 
428  switch ( tableType )
429  {
430  case T_Overview:
431  {
432  header.reserve( 2 );
433  header.push_back( "L" + std::string( " " ) );
434  // column header name of the file
435  header.push_back( "L" + std::string( _( "File name" ) ) );
436  break;
437  }
438 
439  case T_Detailed:
440  {
441  header.reserve( 6 );
442  header.push_back( "L" + std::string( " " ) );
443  // column header name of the file
444  header.push_back( "L" + std::string( _( "File name" ) ) );
445  // column header size of the file
446  header.push_back( "L" + std::string( _( "Size" ) ) );
447  // column header file permissions
448  header.push_back( "L" + std::string( _( "Permissions" ) ) );
449  // column header user
450  header.push_back( "L" + std::string( _( "User" ) ) );
451  // column header group
452  header.push_back( "L" + std::string( _( "Group" ) ) );
453  break;
454  }
455 
456  default:
457  {
458  header.reserve( 2 );
459  header.push_back( "L" + std::string( " " ) );
460  header.push_back( "L" + std::string( _( "File name" ) ) );
461  break;
462  }
463  }
464 
465  setHeader( header );
466  // restore former text domain
467  setTextdomain( old_textdomain.c_str() );
468 }
469 
470 
471 bool NCFileTable::filterMatch( const std::string & fileEntry )
472 {
473  if ( pattern.empty() )
474  return true;
475 
476  bool match = false;
477 
478  std::list<std::string>::iterator it = pattern.begin();
479 
480  while ( it != pattern.end() )
481  {
482  if ( fnmatch(( *it ).c_str(), fileEntry.c_str(), FNM_PATHNAME ) == 0 )
483  match = true;
484 
485  ++it;
486  }
487 
488  return match;
489 }
490 
491 
492 NCursesEvent NCFileSelection::handleKeyEvents( wint_t key )
493 {
494  NCursesEvent ret = NCursesEvent::none;
495 
496  if ( sendKeyEvents() &&
497  ( key == KEY_LEFT || key == KEY_RIGHT ) )
498  {
499  ret = NCursesEvent::key;
500 
501  switch ( key )
502  {
503  case KEY_LEFT:
504  ret.keySymbol = "CursorLeft";
505  break;
506 
507  case KEY_RIGHT:
508  ret.keySymbol = "CursorRight";
509  break;
510  }
511  }
512 
513  return ret;
514 }
515 
516 
517 NCursesEvent NCFileTable::wHandleInput( wint_t key )
518 {
519  NCursesEvent ret = handleKeyEvents( key );
520 
521  // return key event
522 
523  if ( ret == NCursesEvent::key )
524  return ret;
525 
526  // call handleInput of NCPad
527  handleInput( key );
528 
529  currentFile = getCurrentLine();
530 
531  switch ( key )
532  {
533  case KEY_UP:
534  case KEY_PPAGE:
535  case KEY_HOME:
536  case KEY_DOWN:
537  case KEY_NPAGE:
538  case KEY_END:
539  {
540  ret = NCursesEvent::SelectionChanged;
541  ret.result = currentFile;
542  break;
543  }
544 
545  default:
546  ret = NCursesEvent::none;
547  }
548 
549  yuiDebug() << "CURRENT_FILE: " << currentFile << std::endl;
550 
551  return ret;
552 }
553 
554 
556 {
557 
558  struct stat64 statInfo;
559  struct stat64 linkInfo;
560  struct dirent * entry;
561  std::list<std::string> tmpList;
562  std::list<std::string>::iterator it;
563 
564  fillHeader(); // create the column headers
565 
566  DIR * diskDir = opendir( currentDir.c_str() );
567 
568  if ( diskDir )
569  {
570  deleteAllItems();
571 
572  while (( entry = readdir( diskDir ) ) )
573  {
574  std::string entryName = entry->d_name;
575 
576  if ( entryName != "."
577  && filterMatch( entryName ) )
578  {
579  tmpList.push_back( entryName );
580  }
581  }
582 
583  // sort the list and fill the table widget with file entries
584  tmpList.sort( );
585  it = tmpList.begin();
586 
587  while ( it != tmpList.end() )
588  {
589  std::string fullName = currentDir + "/" + ( *it );
590 
591  if ( lstat64( fullName.c_str(), &statInfo ) == 0 )
592  {
593  if ( S_ISREG( statInfo.st_mode ) || S_ISBLK( statInfo.st_mode ) )
594  {
595  if ((( *it ) == ".." && currentDir != "/" )
596  || ( *it ) != ".." )
597  {
598  createListEntry( new NCFileInfo(( *it ), &statInfo ) );
599  }
600  }
601  else if ( S_ISLNK( statInfo.st_mode ) )
602  {
603  if ( stat64( fullName.c_str(), &linkInfo ) == 0 )
604  {
605  if ( S_ISREG( linkInfo.st_mode ) || S_ISBLK( linkInfo.st_mode ) )
606  {
607  createListEntry( new NCFileInfo(( *it ), &linkInfo, true ) );
608  }
609  }
610  }
611  }
612 
613  ++it;
614  }
615 
616  drawList(); // draw the list
617 
618  if ( getNumLines() > 0 )
619  {
620  setCurrentItem( 0 ); // set focus to the first list entry
621  currentFile = getCurrentLine();
622  }
623  else
624  {
625  currentFile = "";
626  }
627 
628  closedir( diskDir );
629  }
630  else
631  {
632  yuiError() << "ERROR opening directory: " << currentDir << " errno: "
633  << strerror( errno ) << std::endl;
634  return false;
635  }
636 
637  return true;
638 }
639 
640 
641 NCDirectoryTable::NCDirectoryTable( YWidget * parent,
642  YTableHeader * tableHeader,
643  NCFileSelectionType type,
644  const std::string & iniDir )
645  : NCFileSelection( parent, tableHeader, type, iniDir )
646 {
647  //fillHeader();
648 }
649 
650 
651 /**
652  * Fill the column headers of the table
653  **/
655 {
656  std::vector<std::string> header;
657  std::string old_textdomain = textdomain(NULL);
658  setTextdomain( "ncurses" );
659 
660  switch ( tableType )
661  {
662  case T_Overview:
663  {
664  header.reserve( 2 );
665  header.push_back( "L" + std::string( " " ) );
666  // column header name of diretcory
667  header.push_back( "L" + std::string( _( "Directory Name" ) ) );
668  break;
669  }
670 
671  case T_Detailed:
672  {
673  header.reserve( 5 );
674  header.push_back( "L" + std::string( " " ) );
675  // column header name of diretcory
676  header.push_back( "L" + std::string( _( "Directory Name" ) ) );
677  header.push_back( "L" + std::string( _( "Permissions" ) ) );
678  header.push_back( "L" + std::string( _( "User" ) ) );
679  header.push_back( "L" + std::string( _( "Group" ) ) );
680  break;
681  }
682 
683  default:
684  {
685  header.reserve( 2 );
686  header.push_back( "L" + std::string( " " ) );
687  header.push_back( "L" + std::string( _( "Directory Name" ) ) );
688  break;
689  }
690  }
691 
692  setHeader( header );
693  // restore former text domain
694  setTextdomain( old_textdomain.c_str() );
695 }
696 
697 
699 {
700  struct stat64 statInfo;
701  struct stat64 linkInfo;
702  struct dirent * entry;
703  std::list<std::string> tmpList;
704  std::list<std::string>::iterator it;
705 
706  fillHeader(); // create the column headers
707 
708  DIR * diskDir = opendir( currentDir.c_str() );
709 
710  if ( diskDir )
711  {
712  deleteAllItems();
713 
714  while (( entry = readdir( diskDir ) ) )
715  {
716  std::string entryName = entry->d_name;
717 
718  if ( entryName != "." )
719  {
720  tmpList.push_back( entryName );
721  }
722  }
723 
724  // sort the list and fill the table widget with directory entries
725  tmpList.sort( );
726 
727  it = tmpList.begin();
728 
729  while ( it != tmpList.end() )
730  {
731  std::string fullName = currentDir + "/" + ( *it );
732 
733  if ( lstat64( fullName.c_str(), &statInfo ) == 0 )
734  {
735  if ( S_ISDIR( statInfo.st_mode ) )
736  {
737  if ((( *it ) == ".." && currentDir != "/" )
738  || ( *it ) != ".." )
739  {
740  createListEntry( new NCFileInfo(( *it ), &statInfo ) );
741  }
742  }
743  else if ( S_ISLNK( statInfo.st_mode ) )
744  {
745  if ( stat64( fullName.c_str(), &linkInfo ) == 0 )
746  {
747  if ( S_ISDIR( linkInfo.st_mode ) )
748  {
749  createListEntry( new NCFileInfo(( *it ), &linkInfo, true ) );
750  }
751  }
752  }
753  }
754 
755  ++it;
756  }
757 
758  drawList(); // draw the list
759  startDir = currentDir; // set start directory
760 
761  if ( getNumLines() > 0 )
762  setCurrentItem( 0 ); // set focus to the first list entry
763 
764  closedir( diskDir );
765  }
766  else
767  {
768  yuiError() << "ERROR opening directory: " << currentDir << " errno: "
769  << strerror( errno ) << std::endl;
770 
771  return false;
772  }
773 
774  return true;
775 }
776 
777 
778 NCursesEvent NCDirectoryTable::wHandleInput( wint_t key )
779 {
780  NCursesEvent ret = handleKeyEvents( key );
781 
782  // return key event
783 
784  if ( ret == NCursesEvent::key )
785  return ret;
786 
787  unsigned int old_pos = getCurrentItem();
788 
789  // call handleInput of NCPad
790  handleInput( key );
791 
792  switch ( key )
793  {
794  case KEY_UP:
795  case KEY_PPAGE:
796  case KEY_HOME:
797  {
798  if ( old_pos != 0 )
799  {
800  setCurrentDir();
801  ret = NCursesEvent::SelectionChanged;
802  ret.result = currentDir;
803  }
804 
805  break;
806  }
807 
808  case KEY_DOWN:
809  case KEY_NPAGE:
810  case KEY_END:
811  {
812  setCurrentDir();
813  ret = NCursesEvent::SelectionChanged;
814  ret.result = currentDir;
815  break;
816  }
817 
818  case KEY_RETURN:
819  case KEY_SPACE:
820  {
821  setCurrentDir();
822  ret = NCursesEvent::Activated;
823  ret.result = currentDir;
824  break;
825  }
826 
827  default:
828  ret = NCursesEvent::none;
829  }
830 
831  yuiDebug() << "CURRENT: " << currentDir << " START DIR: " << startDir << std::endl;
832 
833  return ret;
834 }
835 
836 
837 
NCFileInfo * getFileInfo(int index)
virtual NCTablePad * myPad() const
Definition: NCTable.h:102
virtual bool fillList()
virtual void fillHeader()
NCFileTable(YWidget *parent, YTableHeader *tableHeader, NCFileSelectionType type, const std::string &filter, const std::string &iniDir)
NCFileInfo(std::string fileName, struct stat64 *statInfo, bool link=false)
virtual bool createListEntry(NCFileInfo *fileInfo)
virtual void fillHeader()
virtual bool createListEntry(NCFileInfo *fileInfo)
virtual bool fillList()
virtual void deleteAllItems()
unsigned int getNumLines()