1 /* dirsizeop.cc
2  * This file belongs to Worker, a file manager for UN*X/X11.
3  * Copyright (C) 2001-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 "showdircacheop.h"
23 #include "listermode.h"
24 #include "virtualdirmode.hh"
25 #include "worker.h"
26 #include "worker_locale.h"
27 #include "aguix/stringgadget.h"
28 #include "aguix/button.h"
29 #include "aguix/fieldlistview.h"
30 #include "nwc_path.hh"
31 #include "argclass.hh"
32 #include <algorithm>
33 
34 const char *ShowDirCacheOp::name = "ShowDirCacheOp";
35 
ShowDirCacheOp()36 ShowDirCacheOp::ShowDirCacheOp() : FunctionProto()
37 {
38 }
39 
~ShowDirCacheOp()40 ShowDirCacheOp::~ShowDirCacheOp()
41 {
42 }
43 
44 ShowDirCacheOp*
duplicate() const45 ShowDirCacheOp::duplicate() const
46 {
47   ShowDirCacheOp *ta=new ShowDirCacheOp();
48   return ta;
49 }
50 
51 bool
isName(const char * str)52 ShowDirCacheOp::isName( const char *str )
53 {
54   if ( strcmp( str, name ) == 0 ) return true; else return false;
55 }
56 
57 const char *
getName()58 ShowDirCacheOp::getName()
59 {
60   return name;
61 }
62 
63 int
run(std::shared_ptr<WPUContext> wpu,ActionMessage * msg)64 ShowDirCacheOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
65 {
66   ListerMode *lm1;
67   if(msg->mode!=msg->AM_MODE_DNDACTION) {
68     Lister *l1=msg->getWorker()->getActiveLister();
69     if(l1!=NULL) {
70       lm1 = l1->getActiveMode();
71       if(lm1!=NULL) {
72           showCacheList( msg );
73       }
74     }
75   }
76   return 0;
77 }
78 
79 const char *
getDescription()80 ShowDirCacheOp::getDescription()
81 {
82   return catalog.getLocale( 1286);
83 }
84 
showCacheList(ActionMessage * msg)85 void ShowDirCacheOp::showCacheList( ActionMessage *msg )
86 {
87     ListerMode *lm1;
88     Lister *l1 = msg->getWorker()->getActiveLister();
89 
90     if ( l1 == NULL ) return;
91 
92     lm1 = l1->getActiveMode();
93 
94     if ( lm1 == NULL ) return;
95 
96     VirtualDirMode *vdm = dynamic_cast< VirtualDirMode *>( lm1 );
97 
98     AWindow *win;
99     int my_w, my_h, endmode, mw, mh;
100     AGMessage *agmsg;
101     FieldListView *cachelv;
102     StringGadget *cachesg;
103     int parents, cachebegin;
104     AGUIX *aguix = Worker::getAGUIX();
105     std::list< std::string > cache_entries;
106     int row;
107 
108     if ( vdm != NULL ) {
109         cache_entries = vdm->getNameOfCacheEntries();
110     }
111 
112     win = new AWindow( aguix, 10, 10, 10, 10, catalog.getLocale( 523 ), AWindow::AWINDOW_DIALOG );
113     win->create();
114 
115     AContainer *ac1 = win->setContainer( new AContainer( win, 1, 3 ), true );
116     ac1->setMinSpace( 5 );
117     ac1->setMaxSpace( 5 );
118     ac1->setBorderWidth( 5 );
119 
120     ac1->add( new Text( aguix, 0, 0, catalog.getLocale( 524 ) ),
121               0, 0, AContainer::CO_INCWNR );
122 
123     AContainer *ac1_2 = ac1->add( new AContainer( win, 1, 2 ), 0, 1 );
124     ac1_2->setMinSpace( 0 );
125     ac1_2->setMaxSpace( 0 );
126     ac1_2->setBorderWidth( 0 );
127 
128     cachelv = (FieldListView*)ac1_2->add( new FieldListView( aguix, 0, 0, 50, 50 ,0 ),
129                                           0, 0, AContainer::CO_MIN );
130     cachelv->setHBarState( 2 );
131     cachelv->setVBarState( 2 );
132 
133     cachesg = (StringGadget*)ac1_2->add( new StringGadget( aguix, 0, 0, 50, "", 0 ),
134                                          0, 1, AContainer::CO_INCW );
135 
136     AContainer *ac1_1 = ac1->add( new AContainer( win, 2, 1 ), 0, 2 );
137     ac1_1->setMinSpace( 5 );
138     ac1_1->setMaxSpace( -1 );
139     ac1_1->setBorderWidth( 0 );
140     Button *okb =(Button*)ac1_1->add( new Button( aguix,
141                                                   0,
142                                                   0,
143                                                   catalog.getLocale( 11 ),
144                                                   0 ), 0, 0, AContainer::CO_FIX );
145     Button *cancelb = (Button*)ac1_1->add( new Button( aguix,
146                                                        0,
147                                                        0,
148                                                        catalog.getLocale( 8 ),
149                                                        0 ), 1, 0, AContainer::CO_FIX );
150 
151     std::string cwd = lm1->getCurrentDirectory();
152     if ( ! cwd.empty() ) {
153         char *tstr1 = dupstring( cwd.c_str() );
154         for ( ;; ) {
155             char *tstr2 = NWC::Path::parentDir( tstr1, NULL );
156             if ( tstr2 == NULL ) break;
157 
158             // add tstr2 to the lv
159             row = cachelv->addRow();
160             cachelv->setText( row, 0 , tstr2 );
161             cachelv->setPreColors( row, FieldListView::PRECOLOR_ONLYACTIVE );
162 
163             _freesafe( tstr1 );
164             tstr1 = tstr2;
165             if ( strcmp( tstr1, "/" ) == 0 ) break;
166         }
167         _freesafe( tstr1 );
168     }
169 
170     parents = cachelv->getElements();
171 
172     std::string delim1( strlen( catalog.getLocale( 523 ) ), '-' );
173     row = cachelv->addRow();
174     cachelv->setText( row, 0, delim1 );
175     cachelv->setPreColors( row, FieldListView::PRECOLOR_NOTSELORACT );
176     row = cachelv->addRow();
177     cachelv->setText( row, 0, catalog.getLocale( 523 ) );
178     cachelv->setPreColors( row, FieldListView::PRECOLOR_NOTSELORACT );
179     row = cachelv->addRow();
180     cachelv->setText( row, 0, catalog.getLocale( 812 ) );
181     cachelv->setPreColors( row, FieldListView::PRECOLOR_NOTSELORACT );
182     row = cachelv->addRow();
183     cachelv->setText( row, 0, delim1 );
184     cachelv->setPreColors( row, FieldListView::PRECOLOR_NOTSELORACT );
185 
186     cachebegin = row + 1;
187 
188     if ( ! cache_entries.empty() ) {
189         for ( auto &e : cache_entries ) {
190             row = cachelv->addRow();
191             cachelv->setText( row, 0, e );
192             cachelv->setPreColors( row, FieldListView::PRECOLOR_ONLYACTIVE );
193         }
194     }
195 
196     // maximize cachelv and store sizes
197     cachelv->maximizeX();
198     cachelv->maximizeY();
199     my_w = cachelv->getWidth();
200     my_h = cachelv->getHeight();
201 
202     // now resize container to 80% screen size
203     int rx, ry, rw, rh;
204 
205     aguix->getLargestDimensionOfCurrentScreen( &rx, &ry,
206                                                &rw, &rh );
207 
208     mw = rw * 80 / 100;
209     mh = rh * 80 / 100;
210     ac1->resize( mw, mh );
211     ac1->rearrange();
212 
213     // and check whether the cachelv needs less space
214     // and set min parameter to match 80% or less
215     if ( my_w < cachelv->getWidth() ) {
216         ac1_2->setMinWidth( my_w, 0, 0 );
217     } else {
218         ac1_2->setMinWidth( cachelv->getWidth(), 0, 0 );
219     }
220     if ( my_h < cachelv->getHeight() ) {
221         ac1_2->setMinHeight( my_h, 0, 0 );
222     } else {
223         ac1_2->setMinHeight( cachelv->getHeight(), 0, 0 );
224     }
225 
226     win->contMaximize( true );
227     win->setDoTabCycling( true );
228     cachesg->takeFocus();
229 
230     if ( parents > 0 ) {
231         cachelv->setActiveRow( 0 );
232         cachesg->setText( cachelv->getText( 0, 0 ).c_str() );
233     } else if ( ! cache_entries.empty() ) {
234         cachelv->setActiveRow( cachebegin );
235         cachesg->setText( cachelv->getText( cachebegin, 0 ).c_str() );
236     }
237 
238     // catch msgs before mapping, this are mostly resize msgs
239     while ( ( agmsg = aguix->GetMessage( win ) ) != NULL ) aguix->ReplyMessage( agmsg );
240 
241     win->show();
242 
243     for( endmode = -1; endmode == -1; ) {
244         agmsg = aguix->WaitMessage( win );
245         if ( agmsg != NULL ) {
246             switch ( agmsg->type ) {
247                 case AG_CLOSEWINDOW:
248                     if ( agmsg->closewindow.window == win->getWindow() ) endmode = 1;
249                     break;
250                 case AG_BUTTONCLICKED:
251                     if ( agmsg->button.button == okb ) endmode = 0;
252                     else if ( agmsg->button.button == cancelb ) endmode = 1;
253                     break;
254                 case AG_FIELDLV_ONESELECT:
255                 case AG_FIELDLV_MULTISELECT:
256                     if ( agmsg->fieldlv.lv == cachelv ) {
257                         row = cachelv->getActiveRow();
258                         if ( cachelv->isValidRow( row ) == true ) {
259                             if ( ( row < parents ) ||
260                                  ( row >= cachebegin ) ) {
261                                 // this is one of the parents
262                                 cachesg->setText( cachelv->getText( row, 0 ).c_str() );
263                             }
264                         }
265                     }
266                     break;
267                 case AG_FIELDLV_DOUBLECLICK:
268                     if ( agmsg->fieldlv.lv == cachelv &&
269                          cachelv->isValidRow( agmsg->fieldlv.row ) == true ) {
270                         if ( ( agmsg->fieldlv.row < parents ) ||
271                              ( agmsg->fieldlv.row >= cachebegin ) ) {
272                             // this is one of the parents
273                             endmode = 0;
274                         }
275                     }
276                     break;
277                 case AG_STRINGGADGET_CONTENTCHANGE:
278                     if ( agmsg->stringgadget.sg == cachesg ) {
279                         //TODO: U.U. merkt user ein Lag, deshalb koennte man ein Flag setzen und
280                         // ausserhalb messen, wenn letzte Nachricht her ist und dann suchen
281                         // Aber dann muss ich getMessage machen
282                         const char *tstr = cachesg->getText();
283                         for ( row = 0; row < cachelv->getElements(); row++ ) {
284                             if ( strcmp( tstr, cachelv->getText( row, 0 ).c_str() ) == 0 ) {
285                                 if ( ( row >= 0 && row < parents ) ||
286                                      ( row >= cachebegin && row < ( cachebegin + (int)cache_entries.size() ) ) ) {
287                                     cachelv->setActiveRow( row );
288                                     cachelv->showActive();
289                                 }
290                                 break;
291                             }
292                         }
293                     }
294                     break;
295                 case AG_STRINGGADGET_CANCEL:
296                     if ( agmsg->stringgadget.sg == cachesg ) endmode = 1;
297                     break;
298                 case AG_STRINGGADGET_OK:
299                     if ( agmsg->stringgadget.sg == cachesg ) endmode = 0;
300                     break;
301                 case AG_KEYPRESSED:
302                     if ( win->isParent( agmsg->key.window, false ) == true ) {
303                         switch ( agmsg->key.key ) {
304                             case XK_Up:
305                                 row = cachelv->getActiveRow();
306                                 if ( cachelv->isValidRow( row ) == true ) {
307                                     if ( ( row >= parents ) && ( row <= cachebegin ) ) {
308                                         row = parents - 1;
309                                     } else {
310                                         row--;
311                                     }
312                                     if ( row >= 0 ) {
313                                         cachelv->setActiveRow( row );
314                                         cachelv->showActive();
315                                         cachesg->setText( cachelv->getText( row, 0 ).c_str() );
316                                     }
317                                 }
318                                 break;
319                             case XK_Down:
320                                 row = cachelv->getActiveRow();
321                                 if ( cachelv->isValidRow( row ) == true ) {
322                                     if ( ( row >= ( parents - 1 ) ) && ( row < cachebegin ) ) {
323                                         row = cachebegin;
324                                     } else {
325                                         row++;
326                                     }
327                                     if ( cachelv->isValidRow( row ) == true ) {
328                                         cachelv->setActiveRow( row );
329                                         cachelv->showActive();
330                                         cachesg->setText( cachelv->getText( row, 0 ).c_str() );
331                                     }
332                                 }
333                                 break;
334                             case XK_Prior:
335                                 row = cachelv->getActiveRow();
336                                 if ( cachelv->isValidRow( row ) == true ) {
337                                     row -= cachelv->getMaxDisplayV() - 1;
338                                     if ( ( row >= parents ) && ( row < cachebegin ) ) row = parents - 1;
339                                     if ( row < 0 ) {
340                                         if ( parents > 0 ) row = 0;
341                                         else row = cachebegin;
342                                     }
343                                 } else {
344                                     if ( parents > 0 ) row = 0;
345                                     else if ( ! cache_entries.empty() ) row = cachebegin;
346                                 }
347                                 if ( cachelv->isValidRow( row ) == true ) {
348                                     cachelv->setActiveRow( row );
349                                     cachelv->showActive();
350                                     cachesg->setText( cachelv->getText( row, 0 ).c_str() );
351                                 }
352                                 break;
353                             case XK_Next:
354                                 row = cachelv->getActiveRow();
355                                 if ( cachelv->isValidRow( row ) == true ) {
356                                     row += cachelv->getMaxDisplayV() - 1;
357                                     if ( ( row >= parents ) && ( row < cachebegin ) ) row = cachebegin;
358                                     if ( row >= ( cachebegin + (int)cache_entries.size() ) ) {
359                                         if ( ! cache_entries.empty() ) row = cachebegin + cache_entries.size() - 1;
360                                         else row = parents - 1;
361                                     }
362                                 } else {
363                                     if ( parents > 0 ) row = 0;
364                                     else if ( ! cache_entries.empty() ) row = cachebegin;
365                                 }
366                                 if ( cachelv->isValidRow( row ) == true ) {
367                                     cachelv->setActiveRow( row );
368                                     cachelv->showActive();
369                                     cachesg->setText( cachelv->getText( row, 0 ).c_str() );
370                                 }
371                                 break;
372                             case XK_Home:
373                                 row = -1;
374                                 if ( parents > 0 ) row = 0;
375                                 else if ( ! cache_entries.empty() ) row = cachebegin;
376                                 if ( cachelv->isValidRow( row ) == true ) {
377                                     cachelv->setActiveRow( row );
378                                     cachelv->showActive();
379                                     cachesg->setText( cachelv->getText( row, 0 ).c_str() );
380                                 }
381                                 break;
382                             case XK_End:
383                                 row = -1;
384                                 if ( ! cache_entries.empty() ) row = cachebegin + cache_entries.size() - 1;
385                                 else if ( parents > 0 ) row = parents - 1;
386                                 if ( cachelv->isValidRow( row ) == true ) {
387                                     cachelv->setActiveRow( row );
388                                     cachelv->showActive();
389                                     cachesg->setText( cachelv->getText( row, 0 ).c_str() );
390                                 }
391                                 break;
392                             case XK_Return:
393                             case XK_KP_Enter:
394                                 if ( cancelb->getHasFocus() == false ) {
395                                     endmode = 0;
396                                 }
397                                 break;
398                             case XK_Escape:
399                                 endmode = 1;
400                                 break;
401                         }
402                     }
403                     break;
404             }
405             aguix->ReplyMessage( agmsg );
406         }
407     }
408     if ( endmode == 0 ) {
409         // ok->take cachesg and enterdir
410         std::string dir = cachesg->getText();
411 
412         if ( std::find( cache_entries.begin(),
413                         cache_entries.end(),
414                         dir ) != cache_entries.end() ) {
415             std::list< RefCount< ArgClass > > args;
416 
417             args.push_back( new StringArg( dir ) );
418             lm1->runCommand( "show_cache_entry", args );
419         } else {
420             std::list< RefCount< ArgClass > > args;
421 
422             args.push_back( new StringArg( dir ) );
423             lm1->runCommand( "enter_dir", args );
424         }
425     }
426     delete win;
427 
428     return;
429 }
430