1 /* dirbookmarkui.cc
2 * This file belongs to Worker, a file manager for UN*X/X11.
3 * Copyright (C) 2007-2021 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 "dirbookmarkui.hh"
23 #include "aguix/aguix.h"
24 #include "aguix/awindow.h"
25 #include "aguix/text.h"
26 #include "aguix/fieldlistview.h"
27 #include "aguix/button.h"
28 #include "aguix/solidbutton.h"
29 #include "worker_locale.h"
30 #include "bookmarkdbentry.hh"
31 #include "bookmarkdbfilter.hh"
32 #include "dirbookmarkaddui.hh"
33 #include "dirbookmarkeditui.hh"
34 #include "bookmarkdbproxy.hh"
35 #include "nwc_path.hh"
36 #include <algorithm>
37 #include "prefixdb.hh"
38 #include "worker.h"
39 #include "stringmatcher_flexibleregex.hh"
40 #include "async_job_limiter.hh"
41 #include "wconfig.h"
42 #include <iostream>
43
DirBookmarkUI(Worker & worker,AGUIX & aguix,BookmarkDBProxy & data)44 DirBookmarkUI::DirBookmarkUI( Worker &worker,
45 AGUIX &aguix,
46 BookmarkDBProxy &data ) : m_worker( worker ),
47 m_aguix( aguix ),
48 m_data( data )
49 {
50 m_filtered_data = std::unique_ptr<BookmarkDBFilter>( new BookmarkDBFilter( data ) );
51
52 m_win = std::unique_ptr<AWindow>( new AWindow( &m_aguix,
53 0, 0,
54 400, 400,
55 catalog.getLocale( 1292 ) ) );
56 m_win->create();
57
58 m_co1 = m_win->setContainer( new AContainer( m_win.get(), 1, 5 ), true );
59 m_co1->setMaxSpace( 5 );
60
61 AContainer *co1_2 = m_co1->add( new AContainer( m_win.get(), 2, 1 ), 0, 0 );
62 co1_2->setMaxSpace( 5 );
63 co1_2->setBorderWidth( 0 );
64 co1_2->add( new Text( &m_aguix, 0, 0, catalog.getLocale( 758 ) ),
65 0, 0, AContainer::CO_FIX );
66 m_infixtext = static_cast<Text*>( co1_2->add( new Text( &m_aguix, 0, 0, "" ),
67 1, 0, AContainer::CO_INCW ) );
68
69 AContainer *co1_5 = m_co1->add( new AContainer( m_win.get(), 3, 1 ), 0, 1 );
70 co1_5->setMaxSpace( 5 );
71 co1_5->setBorderWidth( 0 );
72 co1_5->add( new Text( &m_aguix, 0, 0, catalog.getLocale( 822 ) ),
73 0, 0, AContainer::CO_FIX );
74
75 AContainer *co1_5_1 = co1_5->add( new AContainer( m_win.get(), 3, 1 ), 1, 0 );
76 co1_5_1->setMaxSpace( 0 );
77 co1_5_1->setMinSpace( 0 );
78 co1_5_1->setBorderWidth( 0 );
79 m_prev_cat_b = (Button*)co1_5_1->add( new Button( &m_aguix, 0, 0,
80 "<", 0 ), 0, 0, AContainer::CO_FIX );
81 m_cat_sb = dynamic_cast<SolidButton*>( co1_5_1->add( new SolidButton( &m_aguix, 0, 0,
82 "", true ), 1, 0, AContainer::CO_INCW ) );
83 m_next_cat_b = (Button*)co1_5_1->add( new Button( &m_aguix, 0, 0,
84 ">", 0 ), 2, 0, AContainer::CO_FIX );
85
86 m_lv = static_cast<FieldListView*>( m_co1->add( new FieldListView( &m_aguix,
87 0, 0,
88 400, 300, 0 ),
89 0, 2, AContainer::CO_MIN ) );
90 m_lv->setNrOfFields( 4 );
91 m_lv->setGlobalFieldSpace( 5 );
92 m_lv->setShowHeader( true );
93 m_lv->setFieldText( 0, catalog.getLocale( 809 ) );
94 m_lv->setFieldSpace( 0, 0 );
95 m_lv->setFieldSpace( 1, 0 );
96 m_lv->setFieldTextMerged( 0, true );
97 m_lv->setFieldWidth( 0, m_aguix.getTextWidth( "?" ) );
98 m_lv->setFieldText( 2, catalog.getLocale( 810 ) );
99 m_lv->setFieldText( 3, catalog.getLocale( 823 ) );
100 m_lv->setHBarState( 2 );
101 m_lv->setVBarState( 2 );
102 m_lv->setAcceptFocus( true );
103 m_lv->setDisplayFocus( true );
104 m_lv->setOnDemandCallback( [this]( FieldListView *lv,
105 int row,
106 int field,
107 struct FieldListView::on_demand_data &data )
108 {
109 updateLVData( row, field, data );
110 } );
111
112
113 AContainer *co1_4 = m_co1->add( new AContainer( m_win.get(), 3, 1 ), 0, 3 );
114 co1_4->setMinSpace( 5 );
115 co1_4->setMaxSpace( -1 );
116 co1_4->setBorderWidth( 0 );
117
118 m_addb = (Button*)co1_4->add( new Button( &m_aguix,
119 0,
120 0,
121 catalog.getLocale( 759 ),
122 0 ), 0, 0, AContainer::CO_FIX );
123
124 m_editb = (Button*)co1_4->add( new Button( &m_aguix,
125 0,
126 0,
127 catalog.getLocale( 805 ),
128 0 ), 1, 0, AContainer::CO_FIX );
129
130 m_delb = (Button*)co1_4->add( new Button( &m_aguix,
131 0,
132 0,
133 catalog.getLocale( 760 ),
134 0 ), 2, 0, AContainer::CO_FIX );
135
136 AContainer *co1_3 = m_co1->add( new AContainer( m_win.get(), 2, 1 ), 0, 4 );
137 co1_3->setMinSpace( 5 );
138 co1_3->setMaxSpace( -1 );
139 co1_3->setBorderWidth( 0 );
140 m_okb = (Button*)co1_3->add( new Button( &m_aguix,
141 0,
142 0,
143 catalog.getLocale( 761 ),
144 0 ), 0, 0, AContainer::CO_FIX );
145 m_cancelb = (Button*)co1_3->add( new Button( &m_aguix,
146 0,
147 0,
148 catalog.getLocale( 633 ),
149 0 ), 1, 0, AContainer::CO_FIX );
150
151 m_win->contMaximize( true );
152 m_win->setDoTabCycling( true );
153 }
154
~DirBookmarkUI()155 DirBookmarkUI::~DirBookmarkUI()
156 {
157 }
158
mainLoop()159 int DirBookmarkUI::mainLoop()
160 {
161 showData( "" );
162
163 maximizeWin();
164 m_win->show();
165
166 m_lv->takeFocus();
167
168 std::string current_cat = "";
169 AGMessage *msg;
170 int endmode = 0;
171
172 std::string cfgfile = Worker::getWorkerConfigDir();
173 #ifdef USEOWNCONFIGFILES
174 cfgfile = NWC::Path::join( cfgfile, "prefix.db2" );
175 #else
176 cfgfile = NWC::Path::join( cfgfile, "prefix.db" );
177 #endif
178
179 PrefixDB pdb( cfgfile );
180
181 updateCategoryText( current_cat );
182
183 {
184 std::string start_entry = NWC::Path::join( m_dirname,
185 m_basename );
186 bool found = false;
187
188 for ( int row = 0;; row++ ) {
189 if ( m_lv->isValidRow( row ) == false ) break;
190 if ( m_lv->getText( row, 1 ) == start_entry ) {
191 m_lv->setActiveRow( row );
192 m_lv->showActive();
193 found = true;
194 break;
195 }
196 }
197
198 if ( ! found ) {
199 /* first try to find an entry for which the start_entry
200 is a prefix */
201
202 int best_hit = -1;
203 std::string::size_type best_hit_length = 0;
204
205 for ( int row = 0;; row++ ) {
206 if ( m_lv->isValidRow( row ) == false ) break;
207
208 const std::string &entry_text = m_lv->getText( row, 1 );
209
210 if ( entry_text.length() > start_entry.length() ) {
211 if ( entry_text.compare( 0,
212 start_entry.length(),
213 start_entry ) == 0 ) {
214 if ( best_hit < 0 ||
215 entry_text.length() < best_hit_length ) {
216 best_hit = row;
217 best_hit_length = entry_text.length();
218 }
219 }
220 }
221 }
222
223 if ( best_hit >= 0 ) {
224 m_lv->setActiveRow( best_hit );
225 m_lv->showActive();
226 found = true;
227 }
228 }
229
230 if ( ! found ) {
231 /* now try to find the largest prefix */
232
233 int best_hit = -1;
234 std::string::size_type best_hit_length = 0;
235
236 for ( int row = 0;; row++ ) {
237 if ( m_lv->isValidRow( row ) == false ) break;
238
239 const std::string &entry_text = m_lv->getText( row, 1 );
240
241 if ( entry_text.length() < start_entry.length() ) {
242 if ( start_entry.compare( 0,
243 entry_text.length(),
244 entry_text ) == 0 ) {
245 if ( best_hit < 0 ||
246 entry_text.length() > best_hit_length ) {
247 best_hit = row;
248 best_hit_length = entry_text.length();
249 }
250 }
251 }
252 }
253
254 if ( best_hit >= 0 ) {
255 m_lv->setActiveRow( best_hit );
256 m_lv->showActive();
257 found = true;
258 }
259 }
260 }
261
262 for ( ; endmode == 0; ) {
263 if ( m_existence_tests.empty() ) {
264 msg = m_aguix.WaitMessage( NULL );
265 } else {
266 msg = m_aguix.GetMessage( NULL );
267 }
268
269 checkExistResults();
270
271 if ( msg != NULL ) {
272 switch ( msg->type ) {
273 case AG_CLOSEWINDOW:
274 endmode = -1;
275 break;
276 case AG_BUTTONCLICKED:
277 if ( msg->button.button == m_okb ) {
278 endmode = 1;
279 } else if ( msg->button.button == m_cancelb ) {
280 endmode = -1;
281 } else if ( msg->button.button == m_addb ) {
282 DirBookmarkAddUI addui( m_aguix, m_data, m_dirname, m_basename );
283
284 if ( addui.mainLoop() > 0 ) {
285 m_data.write();
286 showData( current_cat );
287 }
288 } else if ( msg->button.button == m_editb ) {
289 BookmarkDBEntry active_entry = getActiveEntry( current_cat );
290 if ( active_entry.getName().length() > 0 ) {
291 DirBookmarkEditUI editui( m_aguix, m_data, active_entry );
292
293 if ( editui.mainLoop() > 0 ) {
294 m_data.write();
295 showData( current_cat );
296 }
297 }
298 } else if ( msg->button.button == m_delb ) {
299 BookmarkDBEntry active_entry = getActiveEntry( current_cat );
300 if ( active_entry.getName().length() > 0 ) {
301 std::string buttontext = catalog.getLocale( 11 );
302 buttontext += "|";
303 buttontext += catalog.getLocale( 8 );
304
305 int erg = m_win->request( catalog.getLocale( 123 ),
306 catalog.getLocale( 762 ),
307 buttontext.c_str() );
308 if ( erg == 0 ) {
309 m_data.delEntry( active_entry );
310 m_data.write();
311 showData( current_cat );
312 }
313 }
314 } else if ( msg->button.button == m_prev_cat_b ) {
315 current_cat = switchCat( current_cat, -1 );
316 showData( current_cat );
317 updateCategoryText( current_cat );
318 } else if ( msg->button.button == m_next_cat_b ) {
319 current_cat = switchCat( current_cat, 1 );
320 showData( current_cat );
321 updateCategoryText( current_cat );
322 }
323 break;
324 case AG_KEYPRESSED:
325 if ( msg->key.key == XK_BackSpace ) {
326 if ( KEYSTATEMASK( msg->key.keystate ) == ShiftMask ) {
327 m_filtered_data->setInfixFilter( "" );
328 showData( current_cat );
329 highlightBestHit( pdb );
330 } else {
331 std::string cur_infix = m_filtered_data->getInfixFilter();
332
333 if ( cur_infix.length() > 0 ) {
334 cur_infix.resize( cur_infix.length() - 1 );
335 m_filtered_data->setInfixFilter( cur_infix );
336 showData( current_cat );
337 highlightBestHit( pdb );
338 }
339 }
340 } else if ( msg->key.key == XK_Return ) {
341 endmode = 1;
342 } else if ( msg->key.key == XK_Escape ) {
343 endmode = -1;
344 } else if ( msg->key.key == XK_Left ) {
345 current_cat = switchCat( current_cat, -1 );
346 showData( current_cat );
347 highlightBestHit( pdb );
348 updateCategoryText( current_cat );
349 } else if ( msg->key.key == XK_Right ) {
350 current_cat = switchCat( current_cat, 1 );
351 showData( current_cat );
352 highlightBestHit( pdb );
353 updateCategoryText( current_cat );
354 } else if ( msg->key.key == XK_Up ) {
355 } else if ( msg->key.key == XK_Down ) {
356 } else if ( msg->key.key == XK_Next ) {
357 } else if ( msg->key.key == XK_Prior ) {
358 } else if ( msg->key.key == XK_Home ) {
359 } else if ( msg->key.key == XK_End ) {
360 } else if ( IsModifierKey( msg->key.key ) ||
361 IsCursorKey( msg->key.key ) ||
362 IsPFKey( msg->key.key ) ||
363 IsFunctionKey( msg->key.key ) ||
364 IsMiscFunctionKey( msg->key.key ) ||
365 ( ( msg->key.key >= XK_BackSpace ) && ( msg->key.key <= XK_Escape ) ) ) {
366 } else if ( strlen( msg->key.keybuf ) > 0 ) {
367 std::string cur_infix = m_filtered_data->getInfixFilter(), old_infix;
368 old_infix = cur_infix;
369 cur_infix += msg->key.keybuf;
370 m_filtered_data->setInfixFilter( cur_infix );
371 if ( m_filtered_data->getEntries( current_cat ).empty() == true ) {
372 m_filtered_data->setInfixFilter( old_infix );
373 }
374 showData( current_cat );
375 highlightBestHit( pdb );
376 }
377 break;
378 case AG_FIELDLV_DOUBLECLICK:
379 if ( msg->fieldlv.lv == m_lv ) {
380 // double click in lv, actual element is unimportant here
381 endmode = 1;
382 }
383 break;
384 case AG_FIELDLV_HEADERCLICKED:
385 if ( ( msg->fieldlv.lv == m_lv ) &&
386 ( msg->fieldlv.button == Button1 ) ) {
387 // store current active entry
388 BookmarkDBEntry active_entry = getActiveEntry( current_cat );
389
390 // switch sort mode
391 switch ( msg->fieldlv.row ) {
392 case 0:
393 m_filtered_data->toggleSortMode( BookmarkDBFilter::SORT_BY_NAME );
394 showData( current_cat );
395 break;
396 case 2:
397 m_filtered_data->toggleSortMode( BookmarkDBFilter::SORT_BY_ALIAS );
398 showData( current_cat );
399 break;
400 case 4:
401 m_filtered_data->toggleSortMode( BookmarkDBFilter::SORT_BY_CATEGORY );
402 showData( current_cat );
403 break;
404 default:
405 break;
406 }
407
408 // find previously stored entry and activate it
409 std::list<BookmarkDBEntry> e = m_filtered_data->getEntries( current_cat );
410 int row = 0;
411 for ( std::list<BookmarkDBEntry>::iterator it1 = e.begin();
412 it1 != e.end();
413 it1++, row++ ) {
414 if ( *it1 == active_entry ) {
415 m_lv->setActiveRow( row );
416 break;
417 }
418 }
419 }
420 break;
421 }
422 m_aguix.ReplyMessage( msg );
423
424 if ( endmode == 1 ) {
425 int row = m_lv->getActiveRow();
426 if ( m_lv->isValidRow( row ) ) {
427 std::string path = m_lv->getText( row, 1 );
428
429 if ( ! NWC::FSEntry( path ).entryExists() ) {
430 endmode = 0;
431 }
432 }
433 }
434 }
435 }
436
437 m_selected_entry.reset();
438
439 if ( endmode == 1 ) {
440 int row = m_lv->getActiveRow();
441 if ( m_lv->isValidRow( row ) == true ) {
442 std::list<BookmarkDBEntry> e = m_filtered_data->getEntries( current_cat );
443 for ( std::list<BookmarkDBEntry>::iterator it1 = e.begin();
444 it1 != e.end();
445 it1++, row-- ) {
446 if ( row == 0 ) {
447 m_selected_entry = std::unique_ptr<BookmarkDBEntry>( new BookmarkDBEntry( *it1 ) );
448 pdb.pushAccess( m_filtered_data->getInfixFilter(), it1->getName(), time( NULL ) );
449 }
450 }
451 }
452 }
453
454 m_win->hide();
455
456 moveTests();
457
458 return endmode;
459 }
460
showData(const std::string & cat)461 void DirBookmarkUI::showData( const std::string &cat )
462 {
463 StringMatcherFlexibleRegEx matcher;
464
465 matcher.setMatchFlexible( false );
466
467 matcher.setMatchString( m_filtered_data->getInfixFilter() );
468
469 m_infixtext->setText( m_filtered_data->getInfixFilter().c_str() );
470
471 int act_row = m_lv->getActiveRow();
472
473 m_lv->setSize( 0 );
474
475 // invalidate running futures
476 for ( auto &e : m_existence_tests ) {
477 std::get<2>( e ) = false;
478 }
479
480 std::list<BookmarkDBEntry> e = m_filtered_data->getEntries( cat );
481 for ( std::list<BookmarkDBEntry>::iterator it1 = e.begin();
482 it1 != e.end();
483 it1++ ) {
484 int row = m_lv->addRow();
485 m_lv->setText( row, 1, it1->getName() );
486 m_lv->setText( row, 2, it1->getAlias() );
487 m_lv->setText( row, 3, it1->getCategory() );
488 m_lv->setPreColors( row, FieldListView::PRECOLOR_ONLYACTIVE );
489
490 if ( row == act_row )
491 m_lv->setActiveRow( row );
492
493 if ( ! m_filtered_data->getInfixFilter().empty() ) {
494 std::vector< size_t > segments = matcher.getMatchSegments( it1->getName() );
495
496 if ( segments.size() > 1 ) {
497 m_lv->setHighlightSegments( row, 1, segments );
498 }
499 }
500 }
501
502 if ( m_lv->isValidRow( m_lv->getActiveRow() ) == false ) {
503 if ( act_row < 0 ) {
504 m_lv->setActiveRow( 0 );
505 } else {
506 m_lv->setActiveRow( e.size() - 1 );
507 }
508 }
509
510 m_lv->redraw();
511 }
512
getSelectedEntry()513 BookmarkDBEntry DirBookmarkUI::getSelectedEntry()
514 {
515 if ( m_selected_entry.get() != NULL ) {
516 return *m_selected_entry;
517 }
518 throw 0;
519 }
520
getFilterString()521 std::string DirBookmarkUI::getFilterString()
522 {
523 return m_filtered_data->getInfixFilter();
524 }
525
setCurrentDirname(const std::string & dirname)526 void DirBookmarkUI::setCurrentDirname( const std::string &dirname )
527 {
528 m_dirname = dirname;
529 }
530
setCurrentBasename(const std::string & basename)531 void DirBookmarkUI::setCurrentBasename( const std::string &basename )
532 {
533 m_basename = basename;
534 }
535
getActiveEntry(const std::string & cat)536 BookmarkDBEntry DirBookmarkUI::getActiveEntry( const std::string &cat )
537 {
538 int row = m_lv->getActiveRow();
539 BookmarkDBEntry dbe( "", "" );
540
541 if ( m_lv->isValidRow( row ) == true ) {
542 std::list<BookmarkDBEntry> e = m_filtered_data->getEntries( cat );
543 for ( std::list<BookmarkDBEntry>::iterator it1 = e.begin();
544 it1 != e.end();
545 it1++, row-- ) {
546 if ( row == 0 ) {
547 dbe = *it1;
548 }
549 }
550 }
551 return dbe;
552 }
553
switchCat(const std::string & current_cat,int dir)554 std::string DirBookmarkUI::switchCat( const std::string ¤t_cat, int dir )
555 {
556 std::list<std::string> cats = m_data.getCats();
557 std::string new_cat = current_cat;
558
559 if ( dir == 0 || cats.empty() == true ) return "";
560
561 if ( current_cat == "" ) {
562 // "all"
563 if ( dir > 0 ) {
564 new_cat = cats.front();
565 } else {
566 new_cat = cats.back();
567 }
568 } else {
569 std::list<std::string>::iterator it1 = std::find( cats.begin(),
570 cats.end(),
571 current_cat );
572
573 if ( it1 != cats.end() ) {
574 if ( dir < 0 ) {
575 // to the left
576 if ( it1 == cats.begin() )
577 new_cat = "";
578 else {
579 it1--;
580 new_cat = *it1;;
581 }
582 } else {
583 it1++;
584 if ( it1 == cats.end() )
585 new_cat = "";
586 else
587 new_cat = *it1;
588 }
589 } else {
590 new_cat = "";
591 }
592 }
593 return new_cat;
594 }
595
updateCategoryText(const std::string & current_cat)596 void DirBookmarkUI::updateCategoryText( const std::string ¤t_cat )
597 {
598 if ( current_cat == "" ) {
599 m_cat_sb->setText( catalog.getLocale( 824 ) );
600 } else {
601 m_cat_sb->setText( current_cat.c_str() );
602 }
603 }
604
maximizeWin()605 void DirBookmarkUI::maximizeWin()
606 {
607 m_lv->maximizeX();
608 m_lv->maximizeY();
609 int my_w = m_lv->getWidth() + 10;
610 int my_h = m_lv->getHeight() + 10;
611
612 if ( my_w < 400 ) my_w = 400;
613 if ( my_h < 300 ) my_h = 300;
614
615 int rx, ry, rw, rh;
616
617 m_aguix.getLargestDimensionOfCurrentScreen( &rx, &ry,
618 &rw, &rh );
619
620 int mw = rw * 80 / 100;
621 int mh = rh * 80 / 100;
622 m_co1->resize( mw, mh );
623 m_co1->rearrange();
624
625 if ( my_w < m_lv->getWidth() ) {
626 m_co1->setMinWidth( my_w, 0, 2 );
627 } else {
628 m_co1->setMinWidth( m_lv->getWidth(), 0, 2 );
629 }
630 if ( my_h < m_lv->getHeight() ) {
631 m_co1->setMinHeight( my_h, 0, 2 );
632 } else {
633 m_co1->setMinHeight( m_lv->getHeight(), 0, 2 );
634 }
635 m_win->contMaximize( true );
636 }
637
highlightBestHit(class PrefixDB & pdb)638 void DirBookmarkUI::highlightBestHit( class PrefixDB &pdb )
639 {
640 if ( m_filtered_data->getInfixFilter().empty() ) return;
641
642 time_t t1;
643 std::string best_hit = pdb.getBestHit( m_filtered_data->getInfixFilter(), t1 );
644
645 if ( best_hit.empty() ) return;
646
647 // search for best_hit in visible entries
648
649 for ( int row = 0;; row++ ) {
650 if ( m_lv->isValidRow( row ) == false ) break;
651 if ( m_lv->getText( row, 1 ) == best_hit ) {
652 m_lv->setActiveRow( row );
653 m_lv->showActive();
654 break;
655 }
656 }
657 }
658
updateLVData(int row,int field,struct FieldListView::on_demand_data & data)659 void DirBookmarkUI::updateLVData( int row, int field,
660 struct FieldListView::on_demand_data &data )
661 {
662 if ( field == 0 ) {
663 std::string path = m_lv->getText( row, 1 );
664
665 if ( m_existence_results.count( path ) == 0 ) {
666 bool async_started = false;
667 bool do_check = true;
668
669 if ( ! wconfig->getDisableBGCheckPrefix().empty() &&
670 AGUIXUtils::starts_with( path, wconfig->getDisableBGCheckPrefix() ) ) {
671 do_check = false;
672 }
673
674 if ( do_check && ! AsyncJobLimiter::async_job_limit_reached() ) {
675 try {
676 auto f = std::async( std::launch::async,
677 [path] {
678 AsyncJobLimiter::inc_async_job();
679 auto res = ExistenceTest::checkPathExistence( path );
680 AsyncJobLimiter::dec_async_job();
681
682 return res;
683 } );
684 m_existence_tests.push_back( std::make_tuple( std::move( f ), row, true ) );
685
686 data.text = "?";
687 data.text_set = true;
688
689 async_started = true;
690 } catch ( std::system_error &e ) {
691 std::cout << e.what() << std::endl;
692 }
693 }
694
695 if ( ! async_started ) {
696 std::promise< ExistenceTest::existence_state_t > promise;
697 auto f = promise.get_future();
698
699 m_existence_tests.push_back( std::make_tuple( std::move( f ), row, true ) );
700
701 if ( do_check ) {
702 promise.set_value( ExistenceTest::checkPathExistence( path ) );
703 } else {
704 promise.set_value( { .exists = ExistenceTest::EXISTS_YES,
705 .path_length = path.size() } );
706 }
707
708 data.text = "?";
709 data.text_set = true;
710 }
711 } else {
712 auto &res = m_existence_results.at( path );
713
714 if ( res.exists == ExistenceTest::EXISTS_YES ) {
715 data.text = "";
716 data.text_set = true;
717 } else if ( res.exists == ExistenceTest::EXISTS_NO ) {
718 data.text = "";
719 data.text_set = true;
720 }
721 }
722 } else if ( field == 1 ) {
723 std::string path = m_lv->getText( row, 1 );
724
725 if ( m_existence_results.count( path ) > 0 ) {
726 auto &res = m_existence_results.at( path );
727
728 if ( res.exists == ExistenceTest::EXISTS_NO ) {
729 data.strike_out = true;
730 data.strike_out_set = true;
731 data.strike_out_start = res.path_length + 1;
732 data.strike_out_start_set = true;
733 }
734
735 data.done = true;
736 }
737 }
738 }
739
moveTests()740 void DirBookmarkUI::moveTests()
741 {
742 for ( auto it = m_existence_tests.begin();
743 it != m_existence_tests.end();
744 ) {
745 std::future_status status = std::get<0>( *it ).wait_for( std::chrono::duration<int>::zero() );
746
747 auto next_it = it;
748 next_it++;
749
750 if ( status != std::future_status::ready ) {
751 auto f = std::move( std::get<0>( *it ) );
752
753 m_worker.enqueueFuture( std::move( f ) );
754 }
755
756 m_existence_tests.erase( it );
757 it = next_it;
758 }
759 }
760
checkExistResults()761 void DirBookmarkUI::checkExistResults()
762 {
763 if ( m_existence_tests.empty() ) {
764 return;
765 }
766
767 bool update_lv = false;
768
769 for ( auto it = m_existence_tests.begin();
770 it != m_existence_tests.end();
771 ) {
772 std::future_status status = std::get<0>( *it ).wait_for(std::chrono::duration<int>::zero());
773
774 if ( status == std::future_status::ready ) {
775 ExistenceTest::existence_state_t res = std::get<0>( *it ).get();
776
777 if ( std::get<2>( *it ) == true ) {
778 int row = std::get<1>( *it );
779
780 if ( m_lv->isValidRow( row ) ) {
781 std::string path = m_lv->getText( row, 1 );
782
783 m_existence_results[ path ] = res;
784
785 m_lv->clearOnDemandDataAvailableFlag( row );
786 update_lv = true;
787 }
788 }
789
790 auto next_it = it;
791 next_it++;
792
793 m_existence_tests.erase( it );
794
795 it = next_it;
796 } else {
797 it++;
798 }
799 }
800
801 if ( update_lv ) {
802 m_lv->redraw();
803 }
804 }
805