1 /* fileviewerbg.cc
2 * This file belongs to Worker, a file manager for UN*X/X11.
3 * Copyright (C) 2010-2017 Ralf Hoffmann.
4 * You can contact me at: ralf@boomerangsworld.de
5 * or http://www.boomerangsworld.de/worker
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "fileviewerbg.hh"
23 #include "fileviewer.hh"
24 #include "worker.h"
25 #include "aguix/textview.h"
26 #include "textstoragefile.h"
27 #include "nwc_fsentry.hh"
28 #include "aguix/util.h"
29 #include "aguix/refcount.hh"
30 #include "filenameshrinker.hh"
31 #include "aguix/searchtextstorage.hh"
32 #include "aguix/backgroundmessagehandler.hh"
33 #include "aguix/choosebutton.h"
34 #include "aguix/button.h"
35 #include "aguix/stringgadget.h"
36 #include "worker_locale.h"
37 #include "wconfig.h"
38 #include "listermode.h"
39 #include "virtualdirmode.hh"
40 #include "pdatei.h"
41
FileViewerBG(Worker * worker)42 FileViewerBG::FileViewerBG( Worker *worker ) : win( NULL ),
43 m_wrap_mode( false ),
44 m_showlinenumbers_mode( false ),
45 ts( NULL ),
46 tv( NULL ),
47 search_sg( NULL ),
48 okb( NULL ),
49 wcb( NULL ),
50 slncb( NULL ),
51 jumplineb( NULL ),
52 readmoreb( NULL ),
53 reloadb( NULL ),
54 m_next_match_b( NULL ),
55 m_prev_match_b( NULL ),
56 m_restart_search_b( NULL ),
57 m_showintab_b( NULL ),
58 m_find_pos_text( NULL ),
59 m_worker( worker )
60 {
61 }
62
~FileViewerBG()63 FileViewerBG::~FileViewerBG()
64 {
65 m_destroy_callback = NULL;
66 if ( win != NULL ) delete win;
67 if ( ts != NULL ) delete ts;
68 }
69
view(const std::list<std::string> & filelist,int initial_line_number,bool highlight_initial_line,RefCount<FileViewerDestroyCallback> destroy_callback)70 void FileViewerBG::view( const std::list<std::string> &filelist,
71 int initial_line_number,
72 bool highlight_initial_line,
73 RefCount< FileViewerDestroyCallback > destroy_callback )
74 {
75 AGUIX *aguix = Worker::getAGUIX();
76 const int cfix = AContainer::ACONT_MINH +
77 AContainer::ACONT_MINW +
78 AContainer::ACONT_MAXH +
79 AContainer::ACONT_MAXW;
80 const int cincw = AContainer::ACONT_MINH +
81 AContainer::ACONT_MINW +
82 AContainer::ACONT_MAXH;
83 const int cincwnr = cincw +
84 AContainer::ACONT_NORESIZE;
85
86 m_filelist = filelist;
87 m_destroy_callback = destroy_callback;
88
89 ts = NULL;
90 tv = NULL;
91 std::list<std::string>::const_iterator it1;
92 int w, h, sw, sh;
93
94 win = new AWindow( aguix, 10, 10, 10, 10, catalog.getLocale( 1290 ) );
95 win->create();
96 /* if ( aguix->getTransientWindow() != NULL ) {
97 win->setTransientForAWindow( aguix->getTransientWindow() );
98 }*/
99
100 AContainer *ac1 = win->setContainer( new AContainer( win, 1, 4 ), true );
101 ac1->setMinSpace( 5 );
102 ac1->setMaxSpace( 5 );
103
104 AContainer *ac1_1 = ac1->add( new AContainer( win, 4, 1 ), 0, 0 );
105 ac1_1->setMinSpace( 5 );
106 ac1_1->setMaxSpace( 5 );
107 ac1_1->setBorderWidth( 0 );
108 ac1_1->add( new Text( aguix, 0, 0, catalog.getLocale( 404 ) ), 0, 0, AContainer::CO_FIXNR );
109 Text *fnt = (Text*)ac1_1->add( new Text( aguix, 0, 0, "" ), 1, 0, AContainer::ACONT_MINH + AContainer::ACONT_MAXH );
110 readmoreb = (Button*)ac1_1->add( new Button( aguix, 0, 0, catalog.getLocale( 763 ), 0 ),
111 2, 0, cfix );
112 readmoreb->setBubbleHelpText( catalog.getLocale( 1146 ) );
113
114 reloadb = ac1_1->addWidget( new Button( aguix, 0, 0, catalog.getLocale( 511 ), 0 ),
115 3, 0, cfix );
116 reloadb->setBubbleHelpText( catalog.getLocale( 1175 ) );
117
118 fnt->setTextShrinker( RefCount<TextShrinker>( new FileNameShrinker() ) );
119
120 it1 = filelist.begin();
121
122 RefCount<AFontWidth> lencalc( new AFontWidth( aguix, aguix->getFont( wconfig->getFont( 4 ).c_str() ) ) );
123
124 if ( buildTextView( *it1, ac1, fnt, lencalc ) != 0 ) {
125 delete win;
126 win = NULL;
127 if ( ts != NULL ) delete ts;
128 ts = NULL;
129 return;
130 }
131
132 ac1->readLimits();
133 ac1_1->readLimits();
134
135 AContainer *ac1_3 = ac1->add( new AContainer( win, 6, 1 ), 0, 3 );
136 ac1_3->setMinSpace( 5 );
137 ac1_3->setMaxSpace( -1 );
138 ac1_3->setBorderWidth( 0 );
139
140 /*nextb = (Button*)ac1_3->add( new Button( aguix, 0, 0, "Next", 1, 0, 2 ),
141 0, 0, cfix );
142 prevb = (Button*)ac1_3->add( new Button( aguix, 0, 0, "Prev", 1, 0, 2 ),
143 1, 0, cfix );*/
144 wcb = (ChooseButton*)ac1_3->add( new ChooseButton( aguix, 0, 0,
145 m_wrap_mode, catalog.getLocale( 637 ),
146 LABEL_RIGHT, 0 ),
147 0, 0, cincwnr );
148 wcb->setBubbleHelpText( catalog.getLocale( 1147 ) );
149 slncb = (ChooseButton*)ac1_3->add( new ChooseButton( aguix, 0, 0,
150 m_showlinenumbers_mode, catalog.getLocale( 715 ),
151 LABEL_RIGHT, 0 ),
152 1, 0, cincwnr );
153 slncb->setBubbleHelpText( catalog.getLocale( 1148 ) );
154
155 snp_cb = ac1_3->addWidget( new ChooseButton( aguix, 0, 0,
156 false, catalog.getLocale( 1176 ),
157 LABEL_RIGHT, 0 ),
158 2, 0, cincwnr );
159 snp_cb->setBubbleHelpText( catalog.getLocale( 1177 ) );
160
161 jumplineb = (Button*)ac1_3->add( new Button( aguix, 0, 0, catalog.getLocale( 716 ), 2 ),
162 3, 0, cfix );
163 jumplineb->setBubbleHelpText( catalog.getLocale( 1142 ) );
164
165 m_showintab_b = ac1_3->addWidget( new Button( aguix, 0, 0, catalog.getLocale( 1178 ), 2 ),
166 4, 0, cfix );
167 m_showintab_b->setBubbleHelpText( catalog.getLocale( 1179 ) );
168
169 okb = (Button*)ac1_3->add( new Button( aguix, 0, 0, catalog.getLocale( 633 ), 2 ),
170 5, 0, cfix );
171 okb->setBubbleHelpText( catalog.getLocale( 1143 ) );
172
173 AContainer *ac1_4 = ac1->add( new AContainer( win, 5, 1 ), 0, 2 );
174 ac1_4->setMinSpace( 5 );
175 ac1_4->setMaxSpace( 10 );
176 ac1_4->setBorderWidth( 0 );
177
178 AContainer *ac1_4_1 = ac1_4->add( new AContainer( win, 2, 1 ), 0, 0 );
179 ac1_4_1->setMinSpace( 5 );
180 ac1_4_1->setMaxSpace( 5 );
181 ac1_4_1->setBorderWidth( 0 );
182
183 ac1_4_1->add( new Text( aguix, 0, 0, catalog.getLocale( 790 ) ), 0, 0, AContainer::CO_FIXNR + AContainer::ACONT_CENTER );
184 search_sg = (StringGadget*)ac1_4_1->add( new StringGadget( aguix, 0, 0, 60, "", 1 ),
185 1, 0, cincw );
186 search_sg->setBubbleHelpText( catalog.getLocale( 1149 ) );
187
188 m_next_match_b = ac1_4->addWidget( new Button( aguix, 0, 0, catalog.getLocale( 1136 ), 2 ),
189 1, 0, cfix );
190 m_next_match_b->setBubbleHelpText( catalog.getLocale( 1144 ) );
191 m_prev_match_b = ac1_4->addWidget( new Button( aguix, 0, 0, catalog.getLocale( 1137 ), 2 ),
192 2, 0, cfix );
193 m_prev_match_b->setBubbleHelpText( catalog.getLocale( 1145 ) );
194 m_restart_search_b = ac1_4->addWidget( new Button( aguix, 0, 0, catalog.getLocale( 1138 ), 2 ),
195 3, 0, cfix );
196
197 AContainer *ac1_4_2 = ac1_4->add( new AContainer( win, 2, 1 ), 4, 0 );
198 ac1_4_2->setMinSpace( 5 );
199 ac1_4_2->setMaxSpace( 5 );
200 ac1_4_2->setBorderWidth( 0 );
201
202 ac1_4_2->addWidget( new Text( aguix, 0, 0, catalog.getLocale( 1139 ) ), 0, 0, AContainer::CO_FIX );
203 m_find_pos_text = ac1_4_2->addWidget( new Text( aguix, 0, 0, catalog.getLocale( 1140 ) ),
204 1, 0, AContainer::CO_INCW );
205 {
206 std::string info = AGUIXUtils::formatStringToString( catalog.getLocale( 1141 ), 1000000000 );
207 int tw = aguix->getTextWidth( info.c_str() );
208
209 if ( tw > m_find_pos_text->getWidth() ) {
210 m_find_pos_text->resize( tw, m_find_pos_text->getHeight() );
211 ac1_4_2->readLimits();
212 }
213 }
214
215 win->setDoTabCycling( true );
216 win->contMaximize( true );
217
218 w = win->getWidth();
219 h = win->getHeight();
220
221 int rx, ry, rw, rh;
222
223 aguix->getLargestDimensionOfCurrentScreen( &rx, &ry,
224 &rw, &rh );
225
226 sw = rw;
227 sh = rh;
228 sw = (int)( (double)sw * 0.8 );
229 sh = (int)( (double)sh * 0.8 );
230 if ( sw < 200 ) sw = 200;
231 if ( sh < 100 ) sh = 100;
232 if ( w < sw ) w = sw;
233 if ( h < sh ) h = sh;
234 win->resize( w, h );
235
236 tv->setLineWrap( wcb->getState() );
237 tv->setShowLineNumbers( slncb->getState() );
238 tv->jumpToLine( initial_line_number, highlight_initial_line );
239
240 if ( ts->incompleteFile() == false ) {
241 readmoreb->hide();
242 }
243
244 m_find_pos_text->setText( "" );
245
246 win->useStippleBackground();
247 win->centerScreen();
248 win->show();
249
250 win->applyFocus( tv );
251 }
252
handleAGUIXMessage(AGMessage & msg)253 void FileViewerBG::handleAGUIXMessage( AGMessage &msg )
254 {
255 AGUIX *aguix = Worker::getAGUIX();
256 int endmode = -1;
257 // bool ignore_key_release = true;
258
259 switch ( msg.type ) {
260 case AG_CLOSEWINDOW:
261 if ( msg.closewindow.window == win->getWindow() ) {
262 endmode = 0;
263 }
264 break;
265 case AG_CHOOSECLICKED:
266 if ( msg.choose.button == wcb ) {
267 tv->setLineWrap( msg.choose.state );
268 } else if ( msg.choose.button == slncb ) {
269 tv->setShowLineNumbers( msg.choose.state );
270 } else if ( msg.choose.button == snp_cb ) {
271 if ( msg.choose.state ) {
272 ts->setConvertMode( TextStorageString::CONVERT_NON_PRINTABLE_HEX );
273 } else {
274 ts->setConvertMode( TextStorageString::CONVERT_NON_PRINTABLE_SIMPLE );
275 }
276 tv->textStorageChanged();
277 }
278 break;
279 case AG_BUTTONCLICKED:
280 if ( msg.button.button == okb ) {
281 endmode = 0;
282 /* } else if ( msg.button.button == nextb ) {
283 it1++;
284 if ( it1 == filelist.end() ) it1 = filelist.begin();
285 buildTextView( *it1, &ts, &tv, ac1 );
286 } else if ( msg.button.button == prevb ) {
287 if ( it1 == filelist.begin() )
288 it1 = filelist.end();
289 it1--;
290 buildTextView( *it1, &ts, &tv, ac1 );*/
291 } else if ( msg.button.button == jumplineb ) {
292 jumpToLine();
293 } else if ( msg.button.button == readmoreb ) {
294 ts->readMore();
295 tv->textStorageChanged();
296 if ( ts->incompleteFile() == false ) {
297 readmoreb->hide();
298 }
299 } else if ( msg.button.button == reloadb ) {
300 ts->reloadFile();
301 tv->textStorageChanged();
302 if ( ts->incompleteFile() == false ) {
303 readmoreb->hide();
304 }
305 } else if ( msg.button.button == m_next_match_b ) {
306 nextMatch();
307 } else if ( msg.button.button == m_prev_match_b ) {
308 nextMatch( true );
309 } else if ( msg.button.button == m_restart_search_b ) {
310 restartSearchFromTop();
311 } else if ( msg.button.button == m_showintab_b ) {
312 showInWorkerTab();
313 }
314 break;
315 /* case AG_KEYPRESSED:
316 ignore_key_release = false;
317 break;*/
318 case AG_KEYPRESSED:
319 if ( /*ignore_key_release == false && */win->isParent( msg.key.window, false ) == true ) {
320 switch ( msg.key.key ) {
321 case XK_q:
322 case XK_F3:
323 case XK_F10:
324 endmode = 0;
325 break;
326 case XK_l:
327 if ( ( msg.key.keystate & ( ControlMask | Mod1Mask ) ) != 0 ) {
328 jumpToLine();
329 } else if ( KEYSTATEMASK( msg.key.keystate ) == 0 &&
330 ! tv->getHasFocus() ) {
331 tv->setShowLineNumbers( ( tv->getShowLineNumbers() == true ) ? false : true );
332 }
333 break;
334 case XK_w:
335 if ( KEYSTATEMASK( msg.key.keystate ) == 0 &&
336 ! tv->getHasFocus() ) {
337 tv->setLineWrap( ( tv->getLineWrap() == true ) ? false : true );
338 }
339 break;
340 case XK_r:
341 if ( ( msg.key.keystate & ( ControlMask | Mod1Mask ) ) != 0 ) {
342 ts->reloadFile();
343 tv->textStorageChanged();
344 if ( ts->incompleteFile() == false ) {
345 readmoreb->hide();
346 }
347 } else {
348 if ( ts->incompleteFile() == true ) {
349 ts->readMore();
350 tv->textStorageChanged();
351 if ( ts->incompleteFile() == false ) {
352 readmoreb->hide();
353 }
354 }
355 }
356 break;
357 case XK_slash:
358 if ( search_sg->isActive() == true ) {
359 nextMatch();
360 } else {
361 std::pair<int, int> rl = ts->getRealLinePair( tv->getYOffset() );
362 ts_search->setSearchStartLine( rl.first );
363 search_sg->setText( "" );
364 search_sg->activate();
365 }
366 break;
367 case XK_s:
368 case XK_f:
369 case XK_i:
370 if ( ( msg.key.keystate & ( ControlMask | Mod1Mask ) ) != 0 ) {
371 if ( search_sg->isActive() == true ) {
372 nextMatch();
373 } else {
374 std::pair<int, int> rl = ts->getRealLinePair( tv->getYOffset() );
375 ts_search->setSearchStartLine( rl.first );
376 search_sg->setText( "" );
377 search_sg->activate();
378 }
379 }
380 break;
381 case XK_n:
382 if ( KEYSTATEMASK( msg.key.keystate ) == 0 ) {
383 nextMatch();
384 }
385 break;
386 case XK_p:
387 if ( KEYSTATEMASK( msg.key.keystate ) == 0 ) {
388 nextMatch( true );
389 }
390 break;
391 case XK_Return:
392 nextMatch();
393 break;
394 }
395 wcb->setState( tv->getLineWrap() );
396 slncb->setState( tv->getShowLineNumbers() );
397 }
398 break;
399 case AG_STRINGGADGET_OK:
400 if ( msg.stringgadget.sg == search_sg ) {
401 search_sg->activate();
402 }
403 case AG_STRINGGADGET_CONTENTCHANGE:
404 if ( msg.stringgadget.sg == search_sg ) {
405 nextMatch();
406 }
407 break;
408 case AG_TEXTVIEW_END_REACHED:
409 if ( msg.textview.textview == tv &&
410 ts->incompleteFile() ) {
411 ts->readMore();
412 tv->textStorageChanged();
413 if ( ts->incompleteFile() == false ) {
414 readmoreb->hide();
415 }
416 }
417 break;
418 }
419
420 if ( endmode == 0 ) {
421 aguix->unregisterBGHandler( win );
422 FileViewer::setGlobalLineWrap( tv->getLineWrap() );
423 FileViewer::setGlobalShowLineNumbers( tv->getShowLineNumbers() );
424 }
425 }
426
getAWindow()427 AWindow *FileViewerBG::getAWindow()
428 {
429 return win;
430 }
431
buildTextView(const std::string & filename,AContainer * ac1,class Text * fnt,const RefCount<AWidth> & lencalc)432 int FileViewerBG::buildTextView( const std::string &filename,
433 AContainer *ac1,
434 class Text *fnt,
435 const RefCount<AWidth> &lencalc )
436 {
437 AGUIX *aguix = Worker::getAGUIX();
438 const int cmin = AContainer::ACONT_MINH +
439 AContainer::ACONT_MINW;
440
441 if ( ac1 == NULL ) return 1;
442
443 NWC::FSEntry fse( filename );
444 loff_t file_length = 0;
445 int initial_size = ( m_wrap_mode == true ) ? ( 512 * 1024 ) : ( 2 * 1024 * 1024 );
446 bool continue_viewing = true;
447
448 file_length = PDatei::getFileSize( filename );
449
450 if ( file_length > initial_size ) {
451 std::string l1, l2;
452 int cancel_button;
453
454 l1 = AGUIXUtils::bytes_to_human_readable_f( file_length );
455 l2 = AGUIXUtils::bytes_to_human_readable_f( (double)initial_size );
456
457 char *textstr = (char*)_allocsafe( strlen( catalog.getLocale( 764 ) ) +
458 l1.length() + l2.length() + 1 );
459 sprintf( textstr, catalog.getLocale( 764 ), l1.c_str(), l2.c_str() );
460
461 std::string buttontext = catalog.getLocale( 765 );
462 buttontext += "|";
463 buttontext += catalog.getLocale( 766 );
464
465 if ( m_wrap_mode == true ) {
466 buttontext += "|";
467 buttontext += catalog.getLocale( 767 );
468
469 cancel_button = 3;
470 } else {
471 cancel_button = 2;
472 }
473
474 buttontext += "|";
475 buttontext += catalog.getLocale( 8 );
476
477 int erg = Worker::getRequester()->request( catalog.getLocale( 123 ),
478 textstr,
479 buttontext.c_str(),
480 win,
481 Requester::REQUEST_NONE );
482 if ( erg == 1 ) {
483 if ( file_length > 1 * 1024 * 1024 * 1024 ) {
484 initial_size = 1 * 1024 * 1024 * 1024;
485 } else {
486 initial_size = file_length;
487 }
488 } else if ( erg == cancel_button ) {
489 continue_viewing = false;
490 } else if ( erg == 2 ) {
491 if ( file_length > 1 * 1024 * 1024 * 1024 ) {
492 initial_size = 1 * 1024 * 1024 * 1024;
493 } else {
494 initial_size = file_length;
495 }
496 m_wrap_mode = false;
497 }
498 _freesafe( textstr );
499 }
500
501 if ( continue_viewing == false ) {
502 return 2;
503 }
504
505 if ( tv != NULL ) {
506 delete tv;
507 }
508 if ( ts != NULL ) {
509 delete ts;
510 }
511 ts = new TextStorageFile( filename, lencalc, initial_size, TextStorageString::CONVERT_NON_PRINTABLE_SIMPLE );
512 tv = new TextView( aguix, 0, 0, 100, 100, "", *ts );
513
514 ts_search = new SearchTextStorage( *ts );
515
516 tv->setDisplayFocus( true );
517 tv->setFont( wconfig->getFont( 4 ).c_str() );
518 ac1->add( tv, 0, 1, cmin );
519 tv->create();
520 if ( fnt != NULL ) fnt->setText( filename.c_str() );
521 ac1->rearrange();
522 tv->show();
523
524 std::string title = AGUIXUtils::formatStringToString( catalog.getLocale( 1079 ), filename.c_str() );
525
526 win->setTitle( title.c_str() );
527
528 return 0;
529 }
530
jumpToLine()531 void FileViewerBG::jumpToLine()
532 {
533 int erg;
534 std::string buttons;
535 char *return_str = NULL;
536
537 buttons = catalog.getLocale( 716 );
538 buttons += "|";
539 buttons += catalog.getLocale( 8 );
540
541 //TODO use current line number as default but I need the interface in tv for this first
542 erg = win->string_request( catalog.getLocale( 123 ),
543 catalog.getLocale( 717 ),
544 "",
545 buttons.c_str(),
546 &return_str );
547 if ( erg == 0 && return_str != NULL ) {
548 int line_nr = 0;
549 line_nr = atoi( return_str ) - 1;
550 tv->jumpToLine( line_nr, true );
551 }
552 if ( return_str != NULL )
553 _freesafe( return_str );
554 }
555
nextMatch(bool backwards)556 void FileViewerBG::nextMatch( bool backwards )
557 {
558 if ( backwards ) {
559 ts_search->searchBackwards( search_sg->getText() );
560 } else {
561 ts_search->search( search_sg->getText() );
562 }
563 ts_search->highlightCurMatch( *tv );
564 tv->makeSelectionVisible();
565
566 if ( strlen( search_sg->getText() ) < 1 ) {
567 m_find_pos_text->setText( "" );
568 } else {
569 int match_line = ts_search->getCurMatchLine();
570
571 if ( match_line < 0 ) {
572 m_find_pos_text->setText( catalog.getLocale( 1140 ) );
573 } else {
574 std::string info = AGUIXUtils::formatStringToString( catalog.getLocale( 1141 ), match_line + 1 );
575
576 m_find_pos_text->setText( info.c_str() );
577 }
578 }
579 }
580
setLineWrap(bool nv)581 void FileViewerBG::setLineWrap( bool nv )
582 {
583 m_wrap_mode = nv;
584 }
585
getLineWrap() const586 bool FileViewerBG::getLineWrap() const
587 {
588 return m_wrap_mode;
589 }
590
setShowLineNumbers(bool nv)591 void FileViewerBG::setShowLineNumbers( bool nv )
592 {
593 m_showlinenumbers_mode = nv;
594 }
595
getShowLineNumbers() const596 bool FileViewerBG::getShowLineNumbers() const
597 {
598 return m_showlinenumbers_mode;
599 }
600
restartSearchFromTop()601 void FileViewerBG::restartSearchFromTop()
602 {
603 ts_search->setSearchStartLine( 0 );
604 nextMatch();
605 }
606
showInWorkerTab()607 void FileViewerBG::showInWorkerTab()
608 {
609 if ( ! m_worker ) return;
610
611 auto it1 = m_filelist.begin();
612
613 if ( it1 == m_filelist.end() ) return;
614
615 Lister *l1;
616
617 l1 = m_worker->getActiveLister();
618 if ( l1 != NULL ) {
619 l1->switch2Mode( 0 );
620
621 VirtualDirMode *vdm = dynamic_cast< VirtualDirMode* >( l1->getActiveMode() );
622 if ( vdm != NULL ) {
623 vdm->newTab();
624
625 vdm->showDir( *it1 );
626 }
627 }
628 }
629