/* normalops.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2021 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "normalops.h"
#include "listermode.h"
#include "worker.h"
#include "workerinitialsettings.hh"
#include "nwc_path.hh"
#include "pers_string_list.hh"
#include "worker_locale.h"
#include "aguix/cyclebutton.h"
#include "aguix/button.h"
#include "aguix/stringgadget.h"
#include "aguix/fieldlistview.h"
#include "datei.h"
#include "virtualdirmode.hh"
#include "argclass.hh"
#include "fileentry.hh"
#include "stringmatcher_fnmatch.hh"
#include "pers_kvp.hh"
#include "aguix/choosebutton.h"

/******
  ChangeListerSetOp
*******/

const char *ChangeListerSetOp::name="ChangeListerSetOp";

bool ChangeListerSetOp::isName(const char *str)
{
  if(strcmp(str,name)==0) return true; else return false;
}

const char *ChangeListerSetOp::getName()
{
  return name;
}

ChangeListerSetOp::ChangeListerSetOp() : FunctionProto()
{
  mode=CLS_CURRENT_LISTER;
  hasConfigure = true;
    m_category = FunctionProto::CAT_SETTINGS;
}

ChangeListerSetOp::~ChangeListerSetOp()
{
}

ChangeListerSetOp *ChangeListerSetOp::duplicate() const
{
  ChangeListerSetOp *ta=new ChangeListerSetOp();
  ta->mode=mode;
  return ta;
}

int ChangeListerSetOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
  Lister *l1;
  switch(mode) {
    case CLS_LEFT_LISTER:
      l1 = msg->getWorker()->getLister(0);
      break;
    case CLS_RIGHT_LISTER:
      l1 = msg->getWorker()->getLister(1);
      break;
    case CLS_OTHER_LISTER:
      l1 = msg->getWorker()->getOtherLister( msg->getWorker()->getActiveLister() );
      break;
    default:
      l1 = msg->getWorker()->getActiveLister();
  }
  if(l1!=NULL) l1->configure();
  return 0;
}

const char *ChangeListerSetOp::getDescription()
{
  return catalog.getLocale(1260);
}

int ChangeListerSetOp::configure()
{
  AGUIX *aguix = Worker::getAGUIX();
  AWindow *win;
  CycleButton *rcyb;
  AGMessage *msg;
  int endmode=-1;
  char *tstr;
  const int cincw = AContainer::ACONT_MINH +
                    AContainer::ACONT_MINW +
                    AContainer::ACONT_MAXH;
  const int cfix = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW +
                   AContainer::ACONT_MAXH +
                   AContainer::ACONT_MAXW;
  
  tstr=(char*)_allocsafe(strlen(catalog.getLocale(293))+strlen(getDescription())+1);
  sprintf(tstr,catalog.getLocale(293),getDescription());
  win = new AWindow( aguix, 10, 10, 10, 10, tstr, AWindow::AWINDOW_DIALOG );
  win->create();
  _freesafe(tstr);

  AContainer *ac1 = win->setContainer( new AContainer( win, 1, 2 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );

  AContainer *ac1_1 = ac1->add( new AContainer( win, 2, 1 ), 0, 0 );
  ac1_1->setMinSpace( 5 );
  ac1_1->setMaxSpace( 5 );
  ac1_1->setBorderWidth( 0 );

  ac1_1->add( new Text( aguix, 0, 0, catalog.getLocale( 348 ) ), 0, 0, cfix );
  rcyb = (CycleButton*)ac1_1->add( new CycleButton( aguix, 0, 0, 100, 0 ), 1, 0, cincw );
  rcyb->addOption(catalog.getLocale(326));
  rcyb->addOption(catalog.getLocale(327));
  rcyb->addOption(catalog.getLocale(324));
  rcyb->addOption(catalog.getLocale(325));
  rcyb->resize(rcyb->getMaxSize(),rcyb->getHeight());
  ac1_1->readLimits();

  switch(mode) {
    case CLS_RIGHT_LISTER:
      rcyb->setOption(1);
      break;
    case CLS_CURRENT_LISTER:
      rcyb->setOption(2);
      break;
    case CLS_OTHER_LISTER:
      rcyb->setOption(3);
      break;
    default:
      rcyb->setOption(0);
      break;
  }
  
  AContainer *ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 1 );
  ac1_2->setMinSpace( 5 );
  ac1_2->setMaxSpace( -1 );
  ac1_2->setBorderWidth( 0 );
  Button *okb =(Button*)ac1_2->add( new Button( aguix,
                                                0,
                                                0,
                                                catalog.getLocale( 11 ),
                                                0 ), 0, 0, cfix );
  Button *cb = (Button*)ac1_2->add( new Button( aguix,
						0,
						0,
						catalog.getLocale( 8 ),
						0 ), 1, 0, cfix );
  
  win->setDoTabCycling( true );
  win->contMaximize( true );
  win->show();
  for(;endmode==-1;) {
    msg=aguix->WaitMessage(win);
    if(msg!=NULL) {
      switch(msg->type) {
        case AG_CLOSEWINDOW:
          if(msg->closewindow.window==win->getWindow()) endmode=1;
          break;
        case AG_BUTTONCLICKED:
          if(msg->button.button==okb) endmode=0;
          else if(msg->button.button==cb) endmode=1;
          break;
        case AG_KEYPRESSED:
            if ( win->isParent( msg->key.window, false ) == true ) {
                switch ( msg->key.key ) {
                    case XK_Escape:
                        endmode = 1;
                        break;
                }
            }
            break;
      }
      aguix->ReplyMessage(msg);
    }
  }
  
  if(endmode==0) {
    // ok
    switch(rcyb->getSelectedOption()) {
      case 1:
        mode=CLS_RIGHT_LISTER;
        break;
      case 2:
        mode=CLS_CURRENT_LISTER;
        break;
      case 3:
        mode=CLS_OTHER_LISTER;
        break;
      default:
        mode=CLS_LEFT_LISTER;
        break;
    }
  }
  
  delete win;

  return endmode;
}

bool ChangeListerSetOp::save(Datei *fh)
{
  if ( fh == NULL ) return false;
  switch(mode) {
    case CLS_RIGHT_LISTER:
      fh->configPutPair( "mode", "right" );
      break;
    case CLS_CURRENT_LISTER:
      fh->configPutPair( "mode", "current" );
      break;
    case CLS_OTHER_LISTER:
      fh->configPutPair( "mode", "other" );
      break;
    default:
      fh->configPutPair( "mode", "left" );
      break;
  }
  return true;
}

void ChangeListerSetOp::setMode(int nv)
{
  switch(nv) {
    case CLS_RIGHT_LISTER:
      mode=nv;
      break;
    case CLS_CURRENT_LISTER:
      mode=nv;
      break;
    case CLS_OTHER_LISTER:
      mode=nv;
      break;
    default:
      mode=CLS_LEFT_LISTER;
  }
}

/*************
 Ende ChangeListerSetOp
**************/

/******
  SwitchListerOp
*******/

const char *SwitchListerOp::name="SwitchListerOp";

bool SwitchListerOp::isName(const char *str)
{
  if(strcmp(str,name)==0) return true; else return false;
}

const char *SwitchListerOp::getName()
{
  return name;
}

SwitchListerOp::SwitchListerOp() : FunctionProto()
{
    m_category = FunctionProto::CAT_CURSOR;
}

SwitchListerOp::~SwitchListerOp()
{
}

SwitchListerOp *SwitchListerOp::duplicate() const
{
  SwitchListerOp *ta=new SwitchListerOp();
  return ta;
}

int SwitchListerOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
  Lister *l1;
  l1 = msg->getWorker()->getOtherLister( msg->getWorker()->getActiveLister() );
  if(l1!=NULL) l1->makeActive();
  return 0;
}

const char *SwitchListerOp::getDescription()
{
  return catalog.getLocale(1261);
}

/*************
 Ende SwitchListerOp
**************/

/******
  FilterSelectOp
*******/

const char *FilterSelectOp::name="FilterSelectOp";
int FilterSelectOp::instance_counter = 0;
size_t FilterSelectOp::history_size = 1000;
int FilterSelectOp::lastw = -1;
int FilterSelectOp::lasth = -1;
std::unique_ptr< PersistentStringList > FilterSelectOp::m_history;

bool FilterSelectOp::isName(const char *str)
{
  if(strcmp(str,name)==0) return true; else return false;
}

const char *FilterSelectOp::getName()
{
  return name;
}

FilterSelectOp::FilterSelectOp() : FunctionProto()
{
    m_filter = "*";
    current_filter = "";
  
    if ( instance_counter == 0 ) {
        initHistory();
    }
    instance_counter++;
    hasConfigure = true;
    m_category = FunctionProto::CAT_SELECTIONS;

    m_mode = FILTER_SELECT;
}

FilterSelectOp::~FilterSelectOp()
{
    instance_counter--;
    if ( instance_counter == 0 ) {
        closeHistory();
    }
}

FilterSelectOp *FilterSelectOp::duplicate() const
{
  FilterSelectOp *ta=new FilterSelectOp();
  ta->m_filter = m_filter;
  ta->m_auto_filter = m_auto_filter;
  ta->setImmediateFilterApply( immediateFilterApply() );
  return ta;
}

int FilterSelectOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
    Lister *l1;
    ListerMode *lm1;

    if ( msg->mode == msg->AM_MODE_DNDACTION ) {
        return 0;
    }

    l1 = msg->getWorker()->getActiveLister();
    if ( ! l1 ) {
        return 0;
    }

    lm1=l1->getActiveMode();
    if ( ! lm1 ) {
        return 0;
    }

    if ( auto vdm = dynamic_cast< VirtualDirMode * >( lm1 ) ) {
        std::list< NM_specialsourceExt > extfilelist;
        std::string entry_basename;

        lm1->getSelFiles( extfilelist, ListerMode::LM_GETFILES_ONLYACTIVE );
        for ( auto &ss1 : extfilelist ) {
            if ( ss1.entry() ) {
                entry_basename = ss1.entry()->name;
            }
        }

        if ( m_immediate_filter_apply ) {
            vdm->selectByFilter( m_filter, m_mode == FILTER_SELECT ? true : false );
        } else if ( requestfilter( entry_basename ) == true ) {
            vdm->selectByFilter( current_filter, m_mode == FILTER_SELECT ? true : false );
        }
    } else {
        lm1->not_supported();
    }

    return 0;
}

const char *FilterSelectOp::getDescription()
{
  return catalog.getLocale(1262);
}

int FilterSelectOp::configure()
{
  StringGadget *sg;
  AGUIX *aguix = Worker::getAGUIX();
  AWindow *win;
  char *tstr;
  const int cincw = AContainer::ACONT_MINH +
                    AContainer::ACONT_MINW +
                    AContainer::ACONT_MAXH;
  const int cfix = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW +
                   AContainer::ACONT_MAXH +
                   AContainer::ACONT_MAXW;

  tstr=(char*)_allocsafe(strlen(catalog.getLocale(293))+strlen(getDescription())+1);
  sprintf(tstr,catalog.getLocale(293),getDescription());
  win = new AWindow( aguix, 10, 10, 10, 10, tstr, AWindow::AWINDOW_DIALOG );
  win->create();
  _freesafe(tstr);
  
  AContainer *ac1 = win->setContainer( new AContainer( win, 1, 4 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );

  auto autofilter_cb = ac1->addWidget( new ChooseButton( aguix, 0, 0, m_auto_filter,
                                                         catalog.getLocale( 1370 ), LABEL_RIGHT, 0 ),
                                       0, 0, AContainer::CO_INCWNR );

  AContainer *ac1_1 = ac1->add( new AContainer( win, 2, 1 ), 0, 1 );
  ac1_1->setMinSpace( 5 );
  ac1_1->setMaxSpace( 5 );
  ac1_1->setBorderWidth( 0 );

  ac1_1->add( new Text( aguix, 0, 0, catalog.getLocale( 349 ) ), 0, 0, cfix );
  sg = (StringGadget*)ac1_1->add( new StringGadget( aguix, 0, 0, 100,
                                                    m_filter.c_str(),
                                                    0 ), 1, 0, cincw );
  
  auto immediate_cb = ac1->addWidget( new ChooseButton( aguix, 0, 0, m_immediate_filter_apply,
                                                        catalog.getLocale( 1384 ), LABEL_RIGHT, 0 ),
                                      0, 2, AContainer::CO_INCWNR );

  AContainer *ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 3 );
  ac1_2->setMinSpace( 5 );
  ac1_2->setMaxSpace( -1 );
  ac1_2->setBorderWidth( 0 );
  Button *okb =(Button*)ac1_2->add( new Button( aguix,
                                                0,
                                                0,
                                                catalog.getLocale( 11 ),
                                                0 ), 0, 0, cfix );
  Button *cancelb = (Button*)ac1_2->add( new Button( aguix,
						     0,
						     0,
						     catalog.getLocale( 8 ),
						     0 ), 1, 0, cfix );

  win->setDoTabCycling( true );
  win->contMaximize( true );
  win->show();
  AGMessage *msg;
  while((msg=aguix->GetMessage(NULL))!=NULL) aguix->ReplyMessage(msg);
  int ende=0;

  if ( autofilter_cb->getState() == true ) {
      ac1_1->hide();
  } else {
      ac1_1->show();
  }

  while(ende==0) {
    msg=aguix->WaitMessage(win);
    if(msg!=NULL) {
      if(msg->type==AG_CLOSEWINDOW) {
        if(msg->closewindow.window==win->getWindow()) ende=-1;
      } else if(msg->type==AG_BUTTONCLICKED) {
        if(msg->button.button==okb) ende=1;
        else if(msg->button.button==cancelb) ende=-1;
      } else if ( msg->type == AG_CHOOSECLICKED ) {
          if ( msg->choose.button == autofilter_cb ) {
              if ( autofilter_cb->getState() == true ) {
                  ac1_1->hide();
                  immediate_cb->setState( false );
              } else {
                  ac1_1->show();
              }
          } else if ( msg->choose.button == immediate_cb ) {
              if ( immediate_cb->getState() == true ) {
                  autofilter_cb->setState( false );
                  ac1_1->show();
              }
          }
      } else if ( msg->type == AG_KEYPRESSED ) {
          if ( win->isParent( msg->key.window, false ) == true ) {
              switch ( msg->key.key ) {
                  case XK_Escape:
                      ende = -1;
                      break;
              }
          }
      }
      aguix->ReplyMessage(msg);
    }
  }
  if(ende==1) {
      m_filter = sg->getText();
      m_auto_filter = autofilter_cb->getState();
      m_immediate_filter_apply = immediate_cb->getState();
  }
  delete win;
  return (ende==1)?0:1;
}

bool FilterSelectOp::save(Datei *fh)
{
  if ( fh == NULL ) return false;
  fh->configPutPairString( "filter", m_filter.c_str() );
  if ( m_auto_filter == false ) {
      fh->configPutPairBool( "autofilter", m_auto_filter );
  }

  if ( immediateFilterApply() == true ) {
      fh->configPutPairBool( "immediatefilterapply", immediateFilterApply() );
  }

  return true;
}

void FilterSelectOp::setMode( filter_select_mode nm )
{
    m_mode = nm;
}

bool FilterSelectOp::requestfilter( const std::string &fullname )
{
  int w, h;
  StringGadget *sg;
  FieldListView *lv;
  AGUIX *aguix = Worker::getAGUIX();
  AWindow *win;
  int row;
  bool lvstill;
  int lastrow;
  const int cincw = AContainer::ACONT_MINH +
                    AContainer::ACONT_MINW +
                    AContainer::ACONT_MAXH;
  const int cincwnr = cincw +
                      AContainer::ACONT_NORESIZE;
  const int cfix = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW +
                   AContainer::ACONT_MAXH +
                   AContainer::ACONT_MAXW;
  const int cmin = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW;

  win = new AWindow( aguix, 10, 10, 10, 10,
                     catalog.getLocale( ( m_mode == FILTER_DESELECT ) ? 269 : 268 ),
                     AWindow::AWINDOW_DIALOG );
  win->create();

  AContainer *ac1 = win->setContainer( new AContainer( win, 1, 4 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );

  ac1->add( new Text( aguix, 0, 0,
                      catalog.getLocale( ( m_mode == 1 ) ? 271 : 270 )
                      ), 0, 0, cincwnr );
  ac1->add( new Text( aguix, 0, 0, catalog.getLocale( 272 ) ), 0, 1, cincwnr );

  AContainer *ac1_1 = ac1->add( new AContainer( win, 1, 2 ), 0, 2 );
  ac1_1->setMinSpace( 0 );
  ac1_1->setMaxSpace( 0 );
  ac1_1->setBorderWidth( 0 );

  lv = (FieldListView*)ac1_1->add( new FieldListView( aguix, 0, 0, 100, 7 * aguix->getCharHeight(), 0 ), 0, 0, cmin );

  lv->setNrOfFields( 2 );
  lv->setGlobalFieldSpace( 5 );
  lv->setFieldText( 0, catalog.getLocale( 1443 ) );
  lv->setFieldText( 1, catalog.getLocale( 1444 ) );
  lv->setShowHeader( true );
  lv->setConsiderHeaderWidthForDynamicWidth( true );
  lv->setHBarState( 2 );
  lv->setVBarState( 2 );
  lv->setDisplayFocus( true );
  lv->setAcceptFocus( true );

  std::string default_value = m_filter;

  if ( m_auto_filter && ! current_filter.empty() ) {
      default_value = current_filter;
  }

  bool matched = false;

  std::list< std::string > cur_history = m_history->getList();

  if ( fullname.empty() ) {
      for ( auto &p : cur_history ) {
          row = lv->insertRow( 0 );
          lv->setText( row, 0, p );
          lv->setPreColors( row, FieldListView::PRECOLOR_ONLYACTIVE );
      }
  } else {
      for ( auto &p : cur_history ) {
          StringMatcherFNMatch matcher;

          matcher.setMatchString( p );

          if ( ! matcher.match( fullname ) ) continue;

          row = lv->insertRow( 0 );
          lv->setText( row, 0, p );
          lv->setPreColors( row, FieldListView::PRECOLOR_ONLYACTIVE );
          
          if ( m_auto_filter && ! matched && p != "*" ) {
              default_value = p;

              // the latest entry is at the beginning, so stop matching
              // after the first hit
              matched = true;
          }
      }

      for ( auto &p : cur_history ) {
          StringMatcherFNMatch matcher;

          matcher.setMatchString( p );

          if ( matcher.match( fullname ) ) continue;

          row = lv->insertRow( 0 );
          lv->setText( row, 1, p );
          lv->setPreColors( row, FieldListView::PRECOLOR_ONLYACTIVE );
          //lv->setStrikeOut( row, 0, true );
      }
  }
  
  lv->showRow( cur_history.size() - 1 );
  lv->redraw();

  if ( m_auto_filter && ! matched ) {
      std::string::size_type dot_pos = fullname.rfind( "." );

      if ( dot_pos != std::string::npos ) {
          std::string suffix( fullname, dot_pos );

          default_value = "*";
          default_value += suffix;
      } else {
          default_value = "*";
      }
  }

  sg=(StringGadget*)ac1_1->add( new StringGadget( aguix, 0, 0, 100,
						  default_value.c_str(),
						  0 ), 0, 1, cincw );

  sg->selectAll( false );
  
  AContainer *ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 3 );
  ac1_2->setMinSpace( 5 );
  ac1_2->setMaxSpace( -1 );
  ac1_2->setBorderWidth( 0 );
  Button *okb =(Button*)ac1_2->add( new Button( aguix,
                                                0,
                                                0,
                                                catalog.getLocale( 11 ),
                                                0 ), 0, 0, cfix );
  Button *cancelb = (Button*)ac1_2->add( new Button( aguix,
						     0,
						     0,
						     catalog.getLocale( 8 ),
						     0 ), 1, 0, cfix );
  win->contMaximize( true );

  w = Worker::getPersKVPStore().getIntValue( "filterselect-width",
                                             win->getWidth(),
                                             10000 );
  h = Worker::getPersKVPStore().getIntValue( "filterselect-height",
                                             win->getHeight(),
                                             10000 );
  //w = ( lastw > 0 ) ? lastw : win->getWidth();
  //h = ( lasth > 0 ) ? lasth : win->getHeight();

  win->setDoTabCycling( true );
  win->resize(w,h);
  win->show();
  AGMessage *msg;
  while((msg=aguix->GetMessage(NULL))!=NULL) aguix->ReplyMessage(msg);
  int ende=0;
  sg->takeFocus();
  lastrow = -1;
  lvstill = false;
  while(ende==0) {
    msg=aguix->WaitMessage(win);
    if(msg!=NULL) {
      if(msg->type==AG_CLOSEWINDOW) {
        if(msg->closewindow.window==win->getWindow()) ende=-1;
      } else if(msg->type==AG_BUTTONCLICKED) {
        if(msg->button.button==okb) ende=1;
        else if(msg->button.button==cancelb) ende=-1;
      } else if(msg->type==AG_STRINGGADGET_OK) {
        if(msg->stringgadget.sg==sg) ende=1;
      } else if(msg->type==AG_STRINGGADGET_CANCEL) {
        if(msg->stringgadget.sg==sg) ende=-1;
      } else if ( msg->type == AG_KEYPRESSED ) {
        if ( win->isParent( msg->key.window, false ) == true ) {
          switch ( msg->key.key ) {
          case XK_Up:
            if ( sg->isActive() == true ) {
              lv->setActiveRow( lv->getElements() - 1 );
              lv->takeFocus();
              lv->showActive();
              lastrow = lv->getActiveRow();
              sg->setText( lv->getText( lastrow, 0 ).c_str() );
            }
            lvstill = false;
            break;
          case XK_Down:
            if ( lv->getHasFocus() == true ) {
              if ( ( lv->getActiveRow() == ( lv->getElements() - 1 ) ) &&
                 ( lvstill == true ) ) {
                lv->setActiveRow( -1 );
                sg->takeFocus();
              }
            }
            break;
          case XK_Escape:
            ende = -1;
            break;
          case XK_Return:
            if ( cancelb->getHasFocus() == false )
              ende = 1;
            break;
          }
        }
      } else if ( ( msg->type == AG_FIELDLV_ONESELECT ) || ( msg->type == AG_FIELDLV_MULTISELECT ) ) {
        row = lv->getActiveRow();
        if ( row == lastrow ) lvstill = true;
        else lvstill = false;
        lastrow = row;
        if ( lv->isValidRow( row ) == true ) {
            if ( lv->getText( row, 0 ).empty() ) {
                sg->setText( lv->getText( row, 1 ).c_str() );
            } else {
                sg->setText( lv->getText( row, 0 ).c_str() );
            }
        }
      }
      aguix->ReplyMessage(msg);
    }
  }
  if(ende==1) {
      current_filter = sg->getText();
      addHistoryItem( current_filter );
  }

  Worker::getPersKVPStore().setIntValue( "filterselect-width",
                                         win->getWidth() );
  Worker::getPersKVPStore().setIntValue( "filterselect-height",
                                         win->getHeight() );

  lastw = win->getWidth();
  lasth = win->getHeight();
  delete win;
  return (ende==1?true:false);
}

void FilterSelectOp::initHistory()
{
    std::string str1;

    str1 = WorkerInitialSettings::getInstance().getConfigBaseDir();
    str1 = NWC::Path::join( str1, "filterselect-history" );

    m_history = std::unique_ptr< PersistentStringList >( new PersistentStringList( str1 ) );
}

void FilterSelectOp::closeHistory()
{
    m_history.reset();
}

std::list< std::string > FilterSelectOp::getHistory()
{
    if ( m_history ) {
        return m_history->getList();
    }

    std::string str1;

    str1 = WorkerInitialSettings::getInstance().getConfigBaseDir();
    str1 = NWC::Path::join( str1, "filterselect-history" );

    auto h = std::unique_ptr< PersistentStringList >( new PersistentStringList( str1 ) );

    return h->getList();
}

void FilterSelectOp::addHistoryItem( const std::string &str )
{
    if ( str.empty() ) return;

    if ( m_history->contains( str ) ) {
        m_history->removeEntry( str );
        m_history->pushFrontEntry( str );
    } else {
        if ( m_history->size() >= history_size ) {
            m_history->removeLast();
        }
        m_history->pushFrontEntry( str );
    }
}

void FilterSelectOp::setFilter( const char *str )
{
  if ( str == NULL ) return;
  m_filter = str;
}

void FilterSelectOp::setAutoFilter( const bool nv )
{
    m_auto_filter = nv;
}

void FilterSelectOp::setImmediateFilterApply( bool nv )
{
    m_immediate_filter_apply = nv;
}

bool FilterSelectOp::immediateFilterApply() const
{
    return m_immediate_filter_apply;
}

/*************
 Ende FilterSelectOp
**************/

/******
  FilterUnSelectOp
*******/

const char *FilterUnSelectOp::name="FilterUnSelectOp";

bool FilterUnSelectOp::isName(const char *str)
{
  if(strcmp(str,name)==0) return true; else return false;
}

const char *FilterUnSelectOp::getName()
{
  return name;
}

FilterUnSelectOp::FilterUnSelectOp() : FilterSelectOp()
{
    m_category = FunctionProto::CAT_SELECTIONS;
    setMode( FILTER_DESELECT );
}

FilterUnSelectOp::~FilterUnSelectOp()
{
}

FilterUnSelectOp *FilterUnSelectOp::duplicate() const
{
  FilterUnSelectOp *ta=new FilterUnSelectOp();
  ta->m_filter = m_filter;
  ta->m_auto_filter = m_auto_filter;
  ta->setImmediateFilterApply( immediateFilterApply() );
  return ta;
}

const char *FilterUnSelectOp::getDescription()
{
  return catalog.getLocale(1263);
}

/*************
 Ende FilterUnSelectOp
**************/

/******
  Path2OSideOp
*******/

const char *Path2OSideOp::name="Path2OSideOp";

bool Path2OSideOp::isName(const char *str)
{
  if(strcmp(str,name)==0) return true; else return false;
}

const char *Path2OSideOp::getName()
{
  return name;
}

Path2OSideOp::Path2OSideOp() : FunctionProto()
{
}

Path2OSideOp::~Path2OSideOp()
{
}

Path2OSideOp *Path2OSideOp::duplicate() const
{
  Path2OSideOp *ta=new Path2OSideOp();
  return ta;
}

int Path2OSideOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
    Lister *l1;
    ListerMode *lm1;

    std::string dir;

    if(msg->mode!=msg->AM_MODE_DNDACTION) {
        l1 = msg->getWorker()->getActiveLister();
        if(l1!=NULL) {
            lm1=l1->getActiveMode();
            if(lm1!=NULL) {
                dir = lm1->getCurrentDirectory();
            }
        }
        if ( ! dir.empty() ) {
            l1 = msg->getWorker()->getOtherLister( msg->getWorker()->getActiveLister());
            if(l1!=NULL) {
                if ( l1->getActiveMode() == NULL ) {
                    l1->switch2Mode( 0 );
                }
                lm1=l1->getActiveMode();
                if(lm1!=NULL) {
                    std::list< RefCount< ArgClass > > args;

                    args.push_back( RefCount< ArgClass >( new StringArg( dir ) ) );
                    lm1->runCommand( "enter_dir", args );
                }
            }
        }
    }

    return 0;
}

const char *Path2OSideOp::getDescription()
{
  return catalog.getLocale(1264);
}

/*************
 Ende Path2OSideOp
**************/

/******
  QuitOp
*******/

const char *QuitOp::name="QuitOp";

bool QuitOp::isName(const char *str)
{
  if(strcmp(str,name)==0) return true; else return false;
}

const char *QuitOp::getName()
{
  return name;
}

QuitOp::QuitOp() : FunctionProto()
{
  mode=Q_NORMAL_QUIT;
  hasConfigure = true;
}

QuitOp::~QuitOp()
{
}

QuitOp *QuitOp::duplicate() const
{
  QuitOp *ta=new QuitOp();
  ta->mode=mode;
  return ta;
}

int QuitOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
  msg->getWorker()->quit( mode == Q_QUICK_QUIT ? 1 : 0 );
  return 0;
}

const char *QuitOp::getDescription()
{
  return catalog.getLocale(1265);
}

int QuitOp::configure()
{
  AGUIX *aguix = Worker::getAGUIX();
  AWindow *win;
  CycleButton *rcyb;
  AGMessage *msg;
  int endmode=-1;
  char *tstr;
  const int cincw = AContainer::ACONT_MINH +
                    AContainer::ACONT_MINW +
                    AContainer::ACONT_MAXH;
  const int cfix = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW +
                   AContainer::ACONT_MAXH +
                   AContainer::ACONT_MAXW;
  
  tstr=(char*)_allocsafe(strlen(catalog.getLocale(293))+strlen(getDescription())+1);
  sprintf(tstr,catalog.getLocale(293),getDescription());
  win = new AWindow( aguix, 10, 10, 10, 10, tstr, AWindow::AWINDOW_DIALOG );
  win->create();
  _freesafe(tstr);

  AContainer *ac1 = win->setContainer( new AContainer( win, 1, 2 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );

  AContainer *ac1_1 = ac1->add( new AContainer( win, 2, 1 ), 0, 0 );
  ac1_1->setMinSpace( 5 );
  ac1_1->setMaxSpace( 5 );
  ac1_1->setBorderWidth( 0 );

  ac1_1->add( new Text( aguix, 0, 0, catalog.getLocale( 350 ) ), 0, 0, cfix );
  rcyb = (CycleButton*)ac1_1->add( new CycleButton( aguix, 0, 0, 100, 0 ), 1, 0, cincw );
  rcyb->addOption(catalog.getLocale(351));
  rcyb->addOption(catalog.getLocale(352));
  rcyb->resize(rcyb->getMaxSize(),rcyb->getHeight());
  ac1_1->readLimits();

  switch(mode) {
    case Q_QUICK_QUIT:
      rcyb->setOption(1);
      break;
    default:
      rcyb->setOption(0);
      break;
  }
  
  AContainer *ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 1 );
  ac1_2->setMinSpace( 5 );
  ac1_2->setMaxSpace( -1 );
  ac1_2->setBorderWidth( 0 );
  Button *okb =(Button*)ac1_2->add( new Button( aguix,
                                                0,
                                                0,
                                                catalog.getLocale( 11 ),
                                                0 ), 0, 0, cfix );
  Button *cb = (Button*)ac1_2->add( new Button( aguix,
						0,
						0,
						catalog.getLocale( 8 ),
						0 ), 1, 0, cfix );
  
  win->setDoTabCycling( true );
  win->contMaximize( true );
  win->show();
  for(;endmode==-1;) {
    msg=aguix->WaitMessage(win);
    if(msg!=NULL) {
      switch(msg->type) {
        case AG_CLOSEWINDOW:
          if(msg->closewindow.window==win->getWindow()) endmode=1;
          break;
        case AG_BUTTONCLICKED:
          if(msg->button.button==okb) endmode=0;
          else if(msg->button.button==cb) endmode=1;
          break;
        case AG_KEYPRESSED:
            if ( win->isParent( msg->key.window, false ) == true ) {
                switch ( msg->key.key ) {
                    case XK_Escape:
                        endmode = 1;
                        break;
                }
            }
            break;
      }
      aguix->ReplyMessage(msg);
    }
  }
  
  if(endmode==0) {
    // ok
    switch(rcyb->getSelectedOption()) {
      case 1:
        mode=Q_QUICK_QUIT;
        break;
      default:
        mode=Q_NORMAL_QUIT;
        break;
    }
  }
  
  delete win;

  return endmode;
}

bool QuitOp::save(Datei *fh)
{
  if ( fh == NULL ) return false;
  switch(mode) {
    case Q_QUICK_QUIT:
      fh->configPutPair( "mode", "quick" );
      break;
    default:
      fh->configPutPair( "mode", "normal" );
      break;
  }
  return true;
}

void QuitOp::setMode(int nmode)
{
  if(nmode==Q_QUICK_QUIT) mode=nmode;
  else mode=Q_NORMAL_QUIT;
}

/*************
 Ende QuitOp
**************/

