/*
 * Copyright (C) 2003, 2004, 2005 Johnathan Burchill
 * <jkerrb@users.sourceforge.net>
 */

#include "kdarview.h"

#include "archiveHandle.h"
#include "controller.h"
#include "kdarConfig.h"
#include "kdar.h"
#include "kdardeclarations.h"
#include "kdarEnums.h"
#include "kdarEventHandler.h"
#include "KDarInteraction.h"
#include "kdarListViewItem.h"
#include "kdarArchiveBrowserUpdatesEvent.h"
#include "kdarCancelButtonEvent.h"
#include "kdarCheckFileSizeEvent.h"
#include "kdarPostListViewItemEvent.h"
#include "kdarprogressdialog.h"
#include "kdarProgressEvent.h"
#include "kdarProgressDialogEvent.h"
#include "kdarSetCursorEvent.h"
#include "kdarStatusBarEvent.h"
#include "kdarTarListingEvent.h"
#include "kdarUserInteractionEvent.h"
#include "kdarUserInteractionStringEvent.h"
#include "kdarWarningEvent.h"

#include "newarchivestoragedirdialog.h"

#include <kaction.h>
#include <kapplication.h>
#include <kcombobox.h>
#include <kconfig.h>
#include <kcursor.h>
#include <kdebug.h>
#include <kdialogbase.h>
#include <kfiledialog.h>
#include <kfileitem.h>
#include <kiconloader.h>
#include <kio/job.h>
#include <klibloader.h>
#include <klineedit.h>
#include <klistview.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kpassdlg.h>
#include <kprinter.h>
#include <krun.h>
#include <kstatusbar.h>
#include <ktextbrowser.h>
#include <ktrader.h>
#include <kurl.h>
#include <kurlrequester.h>
#include <kurlpixmapprovider.h>
#include <kparts/componentfactory.h>

#include <qcheckbox.h>
#include <qdir.h>
#include <qdragobject.h>
#include <qevent.h>
#include <qfile.h>
#include <qframe.h>
#include <qlayout.h>
#include <qpaintdevicemetrics.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qregexp.h>
#include <qsemaphore.h>
#include <qsimplerichtext.h>
#include <qsplitter.h>
#include <qstring.h>
#include <qstylesheet.h>
#include <qthread.h>
#include <qtimer.h>
#include <qvalidator.h>
#include <qvbox.h>
#include <qwaitcondition.h>

#include <dar/libdar.hpp>

//auto_ptr
#include <memory>

//extern libdar::archive *theArchive;
libdar::archive *theArchive = 0;

//archiveItem is the basename of the archive
kdarListViewItem * archiveItem;

kdarView::kdarView( controller *aController, QWidget *parent )
    : DCOPObject( "kdarIface" ),
      KDARDlg( parent ),
      createDlg( new kdarCreateDialog( this ) ),
      createDlgWizard( new kdarCreateArchiveWizard( this ) ),
      extractDlg( new kdarExtractDialog ),
      m_controller( aController ),
      m_eventHandler( 0 ),
      kdarPixmapProvider( new KURLPixmapProvider ),
      fileSizeTimer( 0 ),
      progressTimer( 0 ),
      m_elapsedTimer( 0 ),
      m_rootDirListJob( 0 ),
      progressBar( 0 ),
      m_progressDialog( new kdarProgressDialog ),
      logDialog( 0 )
{
    kdDebug() << "kdarView::kdarView(): entering constructor" << endl;

    //Make sure the startTime is initialized. This will be reset when a new
    //operation begins.
    m_startTime = QDateTime::currentDateTime();

    //Configure some settings for the archive browser:
    kdDebug() << "kdarView::kdarView(): configuring archive browser" << endl;
    archiveFileView->setColumnWidthMode( 0, QListView::Manual );
    archiveFileView->setColumnWidthMode( 6, QListView::Maximum );
    archiveFileView->setSorting( 1 );

    //Set right alignment on all columns except the first
    kdDebug() << "kdarView::kdarView(): set right alignment on browser" << endl;
    int numCols = archiveFileView->columns();
    for( int i = 1; i < numCols; ++i )
    {
        archiveFileView->setColumnAlignment( i, Qt::AlignRight );
    }
    //The browser won't accept drops. What is wrong?
    kdDebug() << "kdarView::kdarView(): dnd-setup" << endl;
    setAcceptDrops( true );
    archiveFileView->setAcceptDrops( true );
    archiveFileView->setDragEnabled( true );

    //Set the controller's parent to this
    kdDebug() << "kdarView::kdarView(): m_controller->setParent()" << endl;
    m_controller->setParent( this );
    //Instantiate the KDarConfig object only AFTER the callback functions
    //have been set. Perhaps the callbacks should be set in m_controller?
    kdDebug() << "kdarView::kdarView(): new KDarConfig( this )" << endl;
    m_kdarconfig = new KDarConfig( this );
    //Now copy the m_kdarconfig object to the create and restore config
    //objects
    kdDebug() << "kdarView::kdarView(): copying m_kdarconfig to m_createConfig" << endl;
    m_createConfig = new KDarConfig( this, 0, m_kdarconfig, false );

    kdDebug() << "kdarView::kdarView(): copying m_kdarconfig to m_restoreConfig" << endl;
    m_restoreConfig = new KDarConfig( this, 0, m_kdarconfig, false );

    //We need an event handler:
    m_eventHandler = new kdarEventHandler( this, m_controller, m_kdarconfig );

    //Set the createConfig object to display only the relevant options:
    kdDebug() << "kdarView::kdarView(): m_createConfig->setupCreateConfig()" << endl;
    m_createConfig->setupCreateConfig();
    //Set the restoreConfig object to display only the relevant options:
    kdDebug() << "kdarView::kdarView(): m_restoreConfig->setupRestoreConfig()" << endl;
    m_restoreConfig->setupRestoreConfig();

    //Set the createDlg's KDarConfig pointer:
    kdDebug() << "kdarView::kdarView(): createDlg->setKDarConfig()" << endl;
    createDlg->setKDarConfig( m_createConfig );
    //Set the createWizard's KDarConfig pointer:
    kdDebug() << "kdarView::kdarView(): createDlgWizard->setKDarConfig()" << endl;
    createDlgWizard->setKDarConfig( m_createConfig );

    //Create dialog connections
    //Connect the createDlg "configure" clicked() signal to its slot

    logDialog = new KDialogBase( KDialogBase::Plain, i18n("caption for logDialog", "Message Log" ), 0/*KDialogBase::Close*/, KDialogBase::Default/*KDialogBase::Close*/, this, 0, false );
    QFrame *page = logDialog->plainPage();
    QVBoxLayout *logLayout = new QVBoxLayout( page, 0, logDialog->spacingHint() );
    logPart = KParts::ComponentFactory::createPartInstanceFromQuery<KParts::ReadOnlyPart>( "text/x-log", QString::null, page, 0, page, 0 );
    if ( logPart )
    {
        logPart->widget()->setMinimumWidth( logDialog->fontMetrics().maxWidth()*5 );
        logPart->widget()->setMinimumHeight( logDialog->fontMetrics().height()*5 );
        logLayout->addWidget( logPart->widget() );
//        part->widget()->show();
    }
    int logWidth = logDialog->fontMetrics().maxWidth()*20;
    int logHeight = logDialog->fontMetrics().height()*15;
    logDialog->resize( logWidth, logHeight );
//    logDialog->show();

    //Open the KDEWallet for storing passwords, if requested by user
    if ( m_kdarconfig->storePassword() )
    {
        bool walletOpened = m_controller->openKDEWallet();
        kdDebug() << "kdarView::kdarView(): walletOpened is " << walletOpened << endl;
        if ( !walletOpened )
        {
            //Inform user that the wallet could not be opened, so he/she
            //will have to enter passwords by hand.
            bool showMessage = KGlobal::config()->readBoolEntry( "showUnableToAccessKDEWalletMessage", true );
            if ( showMessage )
            {
                KMessageBox::information( 0, i18n( "Could not access the KDE Wallet. You will have to enter passwords by hand." ), i18n( "Sorry" ), "showUnableToAccessKDEWalletMessage" );
            }
        }
    }
    //Connect the m_progressDialog's userCancelled() signal to the
    //cancelOperation slot:
    connect( m_progressDialog, SIGNAL( userCancelled() ), this, SLOT( cancelOperation() ) );
    //disable parts of KDar that depend on missing libdar functions
    disableFeatures( m_kdarconfig );
    disableFeatures( m_createConfig );
    disableFeatures( m_restoreConfig );
}

kdarView::~kdarView()
{
    saveProperties();
    if ( m_kdarconfig ) delete m_kdarconfig;
    if ( createDlg ) delete createDlg;
    if ( createDlgWizard ) delete createDlgWizard;
    if ( extractDlg ) delete extractDlg;
}

bool kdarView::cancelOperation()
{
    bool cancelled = false;
    //Ask user if he/she really wants to cancel the operation
    int result = KMessageBox::questionYesNo( m_progressDialog, i18n( "Are you sure you want to cancel this operation?" ), i18n( "Cancel operation?" )/*, KStdGUIItem::Yes(), KStdGUIItem::No()*/ );
    if ( result == KMessageBox::Yes )
    {
        //Cancel the operation
        kdDebug() << "kdarView::cancelOperation(): cancelling operation." << endl;
        cancelled = m_controller->cancelOperation();
        kdDebug() << "kdarView::cancelOperation(): operation cancelled is " << cancelled << endl;
        if ( cancelled )
        {
            //stop the progressbar if it is running:
            if ( m_createConfig->verbose() )
            {
                kdarProgressEvent *progressBarStop = new kdarProgressEvent( kdarProgressEvent::PROGRESS_STOP );
                QApplication::postEvent( this, progressBarStop );
            }
            //stop checking archive slice sizes:
            kdarCheckFileSizeEvent *checkFileSizeEventStop = new kdarCheckFileSizeEvent( kdarCheckFileSizeEvent::STOPTIMER );
            QApplication::postEvent( this, checkFileSizeEventStop );
            //Stop the listJob
            if ( m_rootDirListJob )
            {
                m_rootDirListJob->kill(); //deletes the job
                m_rootDirListJob = 0;
            }
        }
    }
    return cancelled;
}

void kdarView::dropEvent(QDropEvent *event)
{
    kdDebug() << "kdarView::dropEvent() reached." << endl;

    // this is a very simplistic implementation of a drop event.  we
    // will only accept a dropped URL.  the Qt dnd code can do *much*
    // much more, so please read the docs there
    QStrList uri;

    // see if we can decode a URI.. if not, just ignore it
    if ( QUriDrag::decode( event, uri ) )
    {
        // okay, we have a URI.. process it
        QString url, target;
        url = uri.first();
        KURL theURL = KURL::fromPathOrURL( url );
        // okay, somehow list this archive? or just select it?
        if ( theURL.isLocalFile() )
        {
            kdDebug() << "kdarView::dropEvent(): Local file!" << endl;
            if ( url.find(QRegExp("\\.[1-9][0-9]*\\.dar") ) >= 1)
            {
                kdDebug() << "kdarView::dropEvent(): I think it's a disk archive file" << endl;
                kdDebug() << "kdarView::dropEvent(): FIXME: slotArchiveChoose( theURL.path() );" << endl;
                //slotArchiveChoose( theURL.path() );
            }
            else
            {
                kdDebug() << "kdarView::dropEvent(): Not a disk archive file" << endl;
            }
        }
        kdDebug() << "kdarView::dropEvent(): You dropped..." << url << endl;
        kdDebug() << "kdarView::dropEvent(): The path is... " << theURL.path() << endl;
    }
}

void kdarView::customEvent( QCustomEvent * e )
{
    //Pass the event to the KDarEventHandler:
    m_eventHandler->handleEvent( e );
    //check the remaining event-types:
    if ( e->type() == (QEvent::Type) KDar::PROGRESS )
    {
        kdarProgressEvent* pe = (kdarProgressEvent*)e;
        switch ( pe->command() )
        {
            case kdarProgressEvent::PROGRESS_START:
                if ( m_createConfig->verbose() )
                {
                    //Show the progress dialog here?
                    if ( m_progressDialog )
                    {
                        //Reset the progressBar to 0
                        m_progressDialog->updateProgressBar( 0 );
                        m_progressDialog->show();
                    }
                    //initialize the file counters
                    m_filesProcessedAdded = 0;
                    m_filesProcessedSkipped = 0;
                    m_filesProcessedTotal = 0;
                    //A QTimer for progress checking (during creation)
                    progressTimer = new QTimer( this );
                    connect( progressTimer, SIGNAL( timeout() ), this, SLOT( slotUpdateProgressBar() ) );
                    progressTimer->start( PROGRESSINTERVAL );
                }
                break;
            case kdarProgressEvent::PROGRESS_STOP:
                if ( m_createConfig->verbose() )
                {
                    //Stop the listJob
                    if ( m_rootDirListJob )
                    {
                        m_rootDirListJob->kill(); //deletes the job
                        m_rootDirListJob = 0;
                    }
                    if ( progressTimer )
                    {
                        progressTimer->stop();
                        delete progressTimer;
                        progressTimer = 0;
                    }
                    //Hide the progress dialog
                    if ( m_progressDialog )
                    {
                        m_progressDialog->hide();
                    }
                    m_totalFiles = 0;
                }
                break;
            case kdarProgressEvent::PROGRESS_INCREASE_ADDED:
                if ( m_createConfig->verbose() )
                {
                    ++m_filesProcessedAdded;
                }
                break;
            case kdarProgressEvent::PROGRESS_INCREASE_SKIPPED:
                if ( m_createConfig->verbose() )
                {
                    ++m_filesProcessedSkipped;
                }
                break;
            case kdarProgressEvent::PROGRESS_INCREASE_TOTAL:
                if ( m_createConfig->verbose() )
                {
                    ++m_filesProcessedTotal;
                }
                break;
            case kdarProgressEvent::PROGRESS_SET_TOTAL:
                if ( m_createConfig->verbose() )
                {
                    m_totalFiles = pe->total();
                }
                break;
            default:
                kdDebug() << "kdarView::event(): invalid kdarProgressEvent command." << endl;
        }
    }
    if ( e->type() == ( QEvent::Type ) KDar::ARCHIVEBROWSERUPDATES )
    {
        kdarArchiveBrowserUpdatesEvent *ae = (kdarArchiveBrowserUpdatesEvent*) e;
        switch ( ae->command() )
        {
            case kdarArchiveBrowserUpdatesEvent::DISABLE:
                archiveFileView->setSorting(-1);
                //archiveFileView->setUpdatesEnabled( false );
                break;
            case kdarArchiveBrowserUpdatesEvent::ENABLE:
                archiveFileView->setSorting(1);
                //archiveFileView->setUpdatesEnabled( true );
                break;
            default:
                kdDebug() << "kdarView::event(): invalid kdarArchiveBrowserUpdatesEvent command." << endl;
        }
    }
    if ( e->type() == ( QEvent::Type ) KDar::CANCELBUTTON )
    {
        kdarCancelButtonEvent* cbe = (kdarCancelButtonEvent*)e;
        kdar * m_kdar = static_cast<kdar*>(parent());
        if ( m_kdar )
        {
            switch ( cbe->command() )
            {
                case kdarCancelButtonEvent::ENABLE:
                    m_kdar->setCancelButtonState( true );
                    break;
                case kdarCancelButtonEvent::DISABLE:
                    m_kdar->setCancelButtonState( false );
                    break;
                default:
                    kdDebug() << "kdarView::event(): invalid kdarCancelButtonEvent command." << endl;
            }
        }
    }
}

void kdarView::print(QPainter *p, KPrinter *printer, QPaintDeviceMetrics *metrics)
{
    // do the actual printing, here
    //copied basically from $QTDIR/examples/action/application.cpp
    int margin = 0;
    QRect body( margin, margin, metrics->width()-2*margin, metrics->height()-2*margin );
    QSimpleRichText richText( QStyleSheet::convertFromPlainText (archiveTextBrowser->text()), archiveTextBrowser->font(), archiveTextBrowser->context(), archiveTextBrowser->styleSheet(), archiveTextBrowser->mimeSourceFactory(), body.height() );
    richText.setWidth( p, body.width() );
    QRect view( body );
    int page = 1;
    do
    {
        richText.draw( p, body.left(), body.top(), view, colorGroup() );
        view.moveBy( 0, body.height() );
        p->translate( 0 , -body.height() );
        p->drawText( view.right() - p->fontMetrics().width( QString::number( page ) ), view.bottom() + p->fontMetrics().ascent() + 5, QString::number( page ) );
        if ( view.top()  >= richText.height() )
        {
            break;
        }
        printer->newPage();
        page++;
    } while (TRUE);
}

void kdarView::readProperties()
{
    // the 'config' object points to the session managed
    // config file.  this function is automatically called whenever
    // the app is being restored.  read in here whatever you wrote
    // in 'saveProperties'
    kdDebug() << "kdarView::readProperties(): restoreLayout()" << endl;
    archiveFileView->restoreLayout( m_kdarconfig->globalConfig(), "KDar Layout" );
    //Read in the mainWindowSplitter sizes
    m_kdarconfig->globalConfig()->setGroup( "KDar Layout" );
    QValueList<int> splitterSizes = m_kdarconfig->globalConfig()->readIntListEntry( "mainWindowSplitterSizes" );
    if ( ! splitterSizes.empty() )
    {
        mainWindowSplitter->setSizes( splitterSizes );
    }
    kdDebug() << "kdarView::readProperties(): readGlobalSettings()" << endl;
    m_kdarconfig->readGlobalSettings();

    //Ask user for default storage directory if it doesn't exist yet...
    kdDebug() << "kdarView::readProperties(): storageDir setup" << endl;
    QString storageDir = m_kdarconfig->archiveStorageDirectory();
    QString backupDir = "";
    if ( storageDir[0] != '/')
    {
        newArchiveStorageDirDialog storageDirDlg;
        bool finished( false );
        QString homeDir = getenv( "HOME" );
        homeDir += "/";
        if ( homeDir.isNull() )
        {
            homeDir = "";
        }
        backupDir = homeDir + "dar_backups/";
        storageDirDlg.newArchiveStorageDir->lineEdit()->setText( backupDir );
        while ( !finished )
        {

            if ( storageDirDlg.exec() )
            {
                storageDir = storageDirDlg.newArchiveStorageDir->lineEdit()->text();
                if ( storageDir[0] == '/' )
                {
                    finished = true;
                }
            }
            else
            {
                //The user can now skip this step. The user can change this
                //later to a different directory. Will default to $HOME.
                storageDir = homeDir;
                finished = true;
            }
        }
        QDir defaultStorageDir( storageDir );
        if ( !defaultStorageDir.exists() )
        {
            //The directory does not exist: ask user whether to create it
            int result = KMessageBox::questionYesNoList( 0, i18n( "The directory that you chose does not exist. Do you want to create it?" ), storageDir, i18n( "Create directory?" ) );
            if ( result == KMessageBox::Yes )
            {
                //Create the directory.
                if ( !defaultStorageDir.mkdir( storageDir ) )
                {
                    KMessageBox::sorry( 0, i18n( "Unable to create backup directory. Please choose a new backup directory in the \"Settings\" dialog." ) );
                    storageDir = homeDir;
                }
            }
            else
            {
                storageDir = homeDir;
            }
        }
        m_kdarconfig->setArchiveStorageDirectory( storageDir );
        m_createConfig->setArchiveStorageDirectory( storageDir );
        m_restoreConfig->setArchiveStorageDirectory( storageDir );
    }
    kdDebug() << "kdarView::readProperties(): m_kdar->restoreRecentURLEntries()" << endl;
    kdar * m_kdar = static_cast<kdar*>(parent());
    if ( m_kdar ) m_kdar->restoreRecentURLEntries( m_kdarconfig->globalConfig() );
    kdDebug() << "kdarView::readProperties(): m_kdarconfig->updateGUI()" << endl;
    m_kdarconfig->updateGUI();
    kdDebug() << "kdarView::readProperties(): updateGUI()" << endl;
    updateGUI();

}

void kdarView::saveProperties()
{
    // the 'config' object points to the session managed
    // config file.  anything you write here will be available
    // later when this app is restored
        kdDebug() << "setting config file params" << endl;

    archiveFileView->saveLayout(m_kdarconfig->globalConfig(), "KDar Layout");
    //Save the mainWindowSplitter sizes:
    m_kdarconfig->globalConfig()->setGroup( "KDar Layout" );
    m_kdarconfig->globalConfig()->writeEntry( "mainWindowSplitterSizes", mainWindowSplitter->sizes() );

    kdDebug() << "saving the kdarconfig settings" << endl;
    m_kdarconfig->writeGlobalSettings();

    kdar * m_kdar = static_cast<kdar*>( parent() );
    if ( m_kdar )
    {
        m_kdar->saveRecentURLEntries( m_kdarconfig->globalConfig() );
    }
}

void kdarView::slotArchiveChoose( const QString & name )
{
    //Need some way to interact with user:
    KDarInteraction userInteractionDialog( m_controller );

    QString archiveName( name );
    //If archiveName was not passed, user chooses an archive file to open
    //Check that the archiveName file exists. Otherwise, cancel.
    archiveHandle archiveNameHandle( name );
    QFile archiveFile( archiveNameHandle.getArchivePath() + "/" + archiveNameHandle.getArchiveBasename() + ".1." + EXTENSION );
    kdDebug() << "file exists is " << archiveFile.exists() << endl;
    if ( archiveName.isEmpty() || !archiveFile.exists() )
    {
        archiveName = KFileDialog::getOpenFileName( KDARDIRKEY, "*.dar", this, "Select archive to open" );
        //We'll use this when we have a way to operate on remote archives and
        //filesystems.
//        KURL archiveURL = KFileDialog::getOpenURL(m_kdarconfig->archiveStorageDirectory(), (QString) "*.dar", this, (QString) "Select archive to open");
//        archiveName = archiveURL.url();
    }
    //if user cancels, do nothing

    if ( archiveName.isEmpty() )
    {
        kdDebug() << "kdarView::slotArchiveChoose(): user cancelled opening an archive. Returning." << endl;
        return;
    }
    if ( archiveName[0] == '/' )
    {
        m_kdarconfig->setArchiveName( archiveName );
        kdDebug() << "about to open the archive " << archiveName << endl;
        try
        {
            kdar * m_kdar = static_cast<kdar*>( parent() );
            m_controller->openArchive( m_kdarconfig );
            if ( m_kdar ) m_kdar->addRecentURL( archiveName );
        }
        catch( libdar::Egeneric &e )
        {
            userInteractionDialog.warning( e.get_message() );
//             libdar::user_interaction_warning(e.get_message());
        }
    }
    else
    {
        kdDebug() << "kdarView::slotArchiveChoose(): FIXME to open archives in current directory, from commandline." << endl;
    }
}

void kdarView::slotArchiveChoose( const KURL & name )
{
    //If the file doesn't exist, then remove it from the recent list
    if ( !QFile::exists( name.path() ) )
    {
        //remove from recent
        kdar * m_kdar = static_cast<kdar*>( parent() );
        if ( m_kdar ) m_kdar->removeRecentURL( name );
    }
    else
    {
        slotArchiveChoose( name.path() );
    }
}

void kdarView::slotArchiveContextMenu( KListView *, QListViewItem* contextItem, const QPoint & point )
{
    if (contextItem != 0)
    {
        kdarListViewItem * kdarContextItem = static_cast<kdarListViewItem*>(contextItem);
        kdDebug() << "Context menu item: " << kdarContextItem->text(0) << endl;
        kdar * m_kdar = static_cast<kdar*>( parent() );
        if ( m_kdar )
        {
            m_kdar->popupContextMenu( point );
        }
    }
}

void kdarView::slotArchiveCreate()
{
    //create an archive of filesystem data

    //This code prepares the m_createConfig object for the controller.
    bool attemptRun(false);
    if ( m_kdarconfig->useCreateArchiveWizard() )
    {
        attemptRun = createDlgWizard->exec();
    }
    else
    {
        attemptRun = createDlg->exec();
    }
    //Put the creation code in a loop, so user can fix the settings if there
    //was a problem (i.e. the storage directory is the root directory)
    //TODO: This is probably overkill. Must be a better way.
    bool goodToGo( true );
    while ( attemptRun )
    {
        //Add the archive name, directory to backup, reference archive,
        //and dry run settings to the m_createConfig object.
        QString newArchiveDirectory;
        QString archiveBaseTest;
        if ( m_kdarconfig->useCreateArchiveWizard() )
        {
            //get the root directory (the one to backup)
            newArchiveDirectory=createDlgWizard->rootDirectoryKURLRequester->lineEdit()->text();
            //if user cancels, do nothing
            if ( newArchiveDirectory.isEmpty() )
            {
                KMessageBox::sorry( createDlgWizard, i18n( "create archive: sorry", "You did not select a directory to backup." ) );
                goodToGo = false;
            }
            //do a check that the directory exists, eh!
            //if !fileexists... return;
            //get the  new archive basename
            archiveBaseTest = createDlgWizard->archiveNameKURLRequester->lineEdit()->text();
            if ( goodToGo )
            {
                if ( archiveBaseTest.isEmpty() || ( archiveBaseTest.findRev( '/' ) == ( (int ) archiveBaseTest.length() -1 ) ) )
                {
                    KMessageBox::sorry( createDlgWizard, i18n( "create archive: sorry", "You did not choose a name for the archive." ) );
                    goodToGo = false;
                }
            }
            if ( goodToGo )
            {
                //Insert full path into archiveBaseTest if necessary.
                if ( archiveBaseTest[0] != '/' )
                {
                    //User wants to use the default storage directory.
                    archiveBaseTest = m_createConfig->archiveStorageDirectory() + archiveBaseTest;
                }
                //Check that the storage directory and the directory to
                //back up are not the same
                KURL storageNameKURL( archiveBaseTest );
                KURL backupNameKURL( newArchiveDirectory );
                kdDebug() << "storage directory: " << storageNameKURL.directory() << endl;
                kdDebug() << "backup directory: " << backupNameKURL.directory() << endl;
                if ( storageNameKURL.directory() == backupNameKURL.path( -1 ) )
                {
                    kdDebug() << "the directories are the same!" << endl;
                    if ( m_createConfig->libdarCreateFileMask().is_covered( kdar::toStdString( storageNameKURL.fileName() + QString( ".1." ) + QString ( EXTENSION ) ) ) )
                    {
                        //Display a message
                        KMessageBox::sorry( createDlgWizard, i18n( "create archive: sorry", "Your archive would be created in the root directory. If you really want to do this, you must exclude the archive from inclusion using a file filter. Otherwise, create the archive in another directory." ) );
                        goodToGo = false;
                    }
                }
            }
            if ( goodToGo )
            {
                //Do a check here to make sure that all of the directory
                //filters are subdirectories of the root
                //This doesn't actually work as intended. It fails on globs.

                //The root directory
                kdDebug() << "kdarView::slotArchiveCreate(): root is " << newArchiveDirectory << endl;
                QStringList directoryList = m_createConfig->directoryMaskList();
                QString badDirectoryFilters( "" );
                QString cleanRoot = KDarConfig::cleanPath( newArchiveDirectory );
                uint len = cleanRoot.length();
                for( QStringList::Iterator directoryIterator = directoryList.begin(); directoryIterator != directoryList.end(); ++directoryIterator )
                {
                    if ( KDarConfig::cleanPath( *directoryIterator ).left( len ) != cleanRoot )
                    {
                        badDirectoryFilters += KDarConfig::cleanPath( *directoryIterator )+ "\n";
                        goodToGo = false;
                    }
                }
                if ( !goodToGo )
                {
                    //Display message:
                    KMessageBox::sorry( createDlgWizard, i18n( "The following directory filters are not subdirectories of \"%1\":\n %2 Please remove them from the list in the configuration dialog." ).arg( cleanRoot).arg( badDirectoryFilters ) );
                }
            }
            if ( goodToGo && createDlgWizard->diffBackupCheckBox->isChecked() )
            {
                if ( createDlgWizard->referenceArchiveKURLRequester->lineEdit()->text().isEmpty() )
                {
                    KMessageBox::sorry( createDlgWizard, i18n( "create archive: sorry", "You did not choose a reference archive." ) );
                    goodToGo = false;
                }
            }
        } // end of wizard code
        else
        {
            //user not using the wizard. Here is the advanced dialog code.
            //get the root directory (the one to backup)
            newArchiveDirectory = createDlg->rootDirectoryKURLRequester->lineEdit()->text();
            //if user cancels, do nothing
            if ( newArchiveDirectory.isEmpty() )
            {
                KMessageBox::sorry( createDlg, i18n( "create archive: sorry", "You did not select a directory to backup." ) );
                goodToGo = false;
            }
            //do a check that the directory exists, eh!
            //if !fileexists... return;
            //get the  new archive basename
            archiveBaseTest = createDlg->archiveNameKURLRequester->lineEdit()->text();
            if ( goodToGo )
            {
                if ( archiveBaseTest.isEmpty() || ( archiveBaseTest.findRev( '/' ) == ( (int ) archiveBaseTest.length() -1 ) ) )
                {
                    KMessageBox::sorry( createDlg, i18n( "create archive: sorry", "You did not choose a name for the archive." ) );
                    goodToGo = false;
                }
            }
            if ( goodToGo )
            {
                //Insert full path into archiveBaseTest if necessary.
                if (archiveBaseTest[0] != '/')
                {
                    //User wants to use the default storage directory.
                    archiveBaseTest = m_createConfig->archiveStorageDirectory() + archiveBaseTest;
                }
                //Check that the storage directory and the directory to back up are not the same
                KURL storageNameKURL( archiveBaseTest );
                KURL backupNameKURL( newArchiveDirectory );
                kdDebug() << "storage directory: " << storageNameKURL.directory() << endl;
                kdDebug() << "backup directory: " << backupNameKURL.directory() << endl;
                if ( storageNameKURL.directory() == backupNameKURL.path( -1 ) )
                {
                    kdDebug() << "the directories are the same!" << endl;
                    if ( m_createConfig->libdarCreateFileMask().is_covered( kdar::toStdString( storageNameKURL.fileName() + QString( ".1." ) + QString ( EXTENSION ) ) ) )
                    {
                        //Display a message
                        KMessageBox::sorry( createDlg, i18n( "create archive: sorry", "Your archive would be created in the root directory. If you really want to do this, you must exclude the archive from inclusion using a file filter. Otherwise, create the archive in another directory." ) );
                        goodToGo = false;
                    }
                }
            }
            if ( goodToGo )
            {
                //Do a check here to make sure that all of the directory
                //filters are subdirectories of the root

                //The root directory
                kdDebug() << "kdarView::slotArchiveCreate(): root is " << newArchiveDirectory.utf8() << endl;
                QStringList directoryList = m_createConfig->directoryMaskList();
                QString badDirectoryFilters( "" );
                QString cleanRoot = KDarConfig::cleanPath( newArchiveDirectory );
                uint len = cleanRoot.length();
                for( QStringList::Iterator directoryIterator = directoryList.begin(); directoryIterator != directoryList.end(); ++directoryIterator )
                {
                    if ( KDarConfig::cleanPath( *directoryIterator ).left( len ) != cleanRoot )
                    {
                        badDirectoryFilters += KDarConfig::cleanPath( *directoryIterator )+ "\n";
                        goodToGo = false;
                    }
                }
                if ( !goodToGo )
                {
                    //Display message:
                    KMessageBox::sorry( createDlg, i18n( "The following directory filters are not subdirectories of \"%1\":\n %2 Please remove them from the list in the configuration dialog." ).arg( cleanRoot ).arg( badDirectoryFilters ) );
                }
            }
            if ( goodToGo && createDlg->diffBackupCheckBox->isChecked() )
            {
                if ( createDlg->referenceArchiveKURLRequester->lineEdit()->text().isEmpty() )
                {
                    KMessageBox::sorry( createDlg, "You did not choose a reference archive.");
                    goodToGo = false;
                }
            }
        }
        //Start the creation thread:
        if ( goodToGo )
        {
            //Set attemptRun to false so we don't execute this again!
            attemptRun = false;
            //Set the createConfig's newArchiveDirectory:
            m_createConfig->setDirectoryToBackup( newArchiveDirectory );
            //Set the NewArchiveName
            m_createConfig->setNewArchiveName( archiveBaseTest );
            if ( m_kdarconfig->useCreateArchiveWizard() )
            {
                //Set the differentialBackup status
                m_createConfig->setDifferentialBackup( createDlgWizard->diffBackupCheckBox->isChecked() );
                //Set the differentialBackupArchiveName
                //Prepend with default directory if needed:
                QString refArchive = createDlgWizard->referenceArchiveKURLRequester->lineEdit()->text();
                if ( refArchive[0] != '/' )
                {
                    //User wants to use the default storage directory.
                    refArchive = m_createConfig->archiveStorageDirectory() + refArchive;
                }
                m_createConfig->setDifferentialBackupArchiveName( refArchive );
                //Set the dry run option
                m_createConfig->setDryRun( createDlgWizard->dryRunCheckBox->isChecked() );
                //Set the thread priority
                m_createConfig->setPriority( QThread::InheritPriority );
            }
            else
            {
                //Set the differentialBackup status
                m_createConfig->setDifferentialBackup( createDlg->diffBackupCheckBox->isChecked() );
                //Set the differentialBackupArchiveName
                //Prepend with default directory if needed:
                QString refArchive = createDlg->referenceArchiveKURLRequester->lineEdit()->text();
                if ( refArchive[0] != '/' )
                {
                    //User wants to use the default storage directory.
                    refArchive = m_createConfig->archiveStorageDirectory() + refArchive;
                }
                m_createConfig->setDifferentialBackupArchiveName( refArchive );
                //Set the dry run option
                m_createConfig->setDryRun( createDlg->dryRunCheckBox->isChecked() );
                //Set the thread priority
                m_createConfig->setPriority( createDlg->priorityKComboBox->currentItem() );
            }
            if ( m_createConfig->differentialBackup() )
            {
                //Set the archiveName in m_createConfig
                m_createConfig->setArchiveName( m_createConfig->differentialBackupArchiveName() );
            }

            //Calculate the total number of files that will be added:
            //Should be able to do this on a time comparable to unix
            //command "du -s"
            if ( m_createConfig->verbose() )
            {
                m_tmpTotalFiles = 0;
                libdar::et_mask directoryMask = m_createConfig->libdarCreateDirectoryMask();
                libdar::et_mask fileMask = m_createConfig->libdarCreateFileMask();
                m_rootDirListJob = KIO::KDarListRecursive( m_createConfig->directoryToBackup(), directoryMask, fileMask );
                connect( m_rootDirListJob, SIGNAL( entries( KIO::Job *, const unsigned long ) ), this, SLOT( slotIncrementTotalFiles( KIO::Job *, const unsigned long ) ) );
                connect( m_rootDirListJob, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotSetTotalFiles( KIO::Job * ) ) );
            }
            //Ask the controller to start the creation process.
            m_controller->createArchive( m_createConfig );
            //break out of the while loop.
        }
        else
        {
            //There was a problem with the creation settings or
            //the user cancelled, so try again.
            if ( m_kdarconfig->useCreateArchiveWizard() )
            {
                attemptRun = createDlgWizard->exec();
            }
            else
            {
                attemptRun = createDlg->exec();
            }
            goodToGo = true;
        }
    }
}

void kdarView::slotArchiveDescend(QListViewItem * expandItem)
{
    //populate an item in the KListView with the contents of an archive
    //subdirectory
    m_controller->populateArchiveTree( 0, expandItem );
}

void kdarView::slotArchiveDiff()
{
    //compare the archive against the filesystem
    m_controller->diffArchive( m_kdarconfig );
}

void kdarView::slotArchiveExtract()
{
    //restore an archive onto the filesystem
    if ( !theArchive )
    {
        slotArchiveChoose();
        m_controller->waitForThread( controller::OPEN_THREAD );
    }
    if ( !theArchive )
    {
        KMessageBox::sorry( this, i18n( "restore archive: sorry", "Could not open the archive for restoring." ) );
        return;
    }
    if ( extractDlg->exec() )
    {
        QString extractArchiveDirectory = extractDlg->extractKURLRequester->lineEdit()->text();
        //if user cancels, do nothing
        kdDebug() << "slotArchiveRestore(): extract directory is " << extractArchiveDirectory << endl;
        if ( extractArchiveDirectory.isEmpty() || extractArchiveDirectory[0] != '/' )
        {
            //Inform user that they need to specify a directory
            KMessageBox::sorry( this, i18n( "restore archive: sorry", "You did not select a valid restoration directory." ) );
            return;
        }
        m_restoreConfig->setExtractArchiveDirectory( extractArchiveDirectory );
        m_restoreConfig->setDryRun( extractDlg->dryRunCheckBox->isChecked() );
        m_controller->restoreArchive( m_restoreConfig );
    }
}

void kdarView::slotArchiveIsolate()
{
    m_controller->isolateArchive( m_kdarconfig );
}

void kdarView::slotArchiveList( const bool loadArchive )
{
    //Initiate an archive listing
    m_controller->listArchive( m_kdarconfig, loadArchive );
}

void kdarView::slotArchiveTest()
{
    //test the archive
    m_controller->testArchive( m_kdarconfig );
}

void kdarView::slotClearMessages()
{
    //Clear the message window
    archiveTextBrowser->clear();
}

void kdarView::slotElapsedTime()
{
    //Calculate the elapsed time and display it in the progress dialog.
    if ( m_elapsedTimer ) m_elapsedTimer->stop();
    if ( m_progressDialog ) m_progressDialog->setElapsedTime( elapsedTime() );
    if ( m_elapsedTimer ) m_elapsedTimer->start( TIMEELAPSEDINTERVAL );
}

void kdarView::slotChangePassword()
{
    if ( m_controller )
    {
        m_controller->changePassword();
    }
    //Remove password from the temporary storage in the controller.
    if ( m_controller ) m_controller->clearPassword();
}

void kdarView::slotCreationCheckFileSize()
{
    //Stop the timer
    if ( fileSizeTimer ) fileSizeTimer->stop();
    //Check the filesize
    archiveHandle newArchiveHandle( m_createConfig->newArchiveName() );
    long i = newArchiveHandle.lastArchiveSliceNumber();
    QFile newArchiveFile( m_createConfig->newArchiveName() + QString( "." ) + QString::number( i ) + QString( "." ) + EXTENSION );
    if ( newArchiveFile.exists() )
    {
        long sizeKB( newArchiveFile.size()/1024 );
        long sizeMB( newArchiveFile.size()/1048576 );
        long size;
        QString sizeSuffix;
        if ( sizeKB < 2048 )
        {
            size = sizeKB;
            sizeSuffix = i18n( "archive current slice size, kilobytes", "kB" );
        }
        else
        {
            size = sizeMB;
            sizeSuffix = i18n( "archive current slice size, megabytes", "MB" );
        }
        QString statusText;
        statusText = i18n( "e.g., Writing slice 2: 3534 MB", "Writing slice %1:   %2 %3" ).arg( QString::number( i ) ).arg( size, 4 ).arg( sizeSuffix );
        //Use the new progress dialog...
        if ( m_progressDialog )
        {
            m_progressDialog->setSliceInfo( statusText );
        }
    }
    else
    {
        kdDebug() << "kdar::slotCreationCheckFileSize(): " << m_createConfig->newArchiveName() << "does not exist." << endl;
    }
    //Start timer again
    if ( fileSizeTimer ) fileSizeTimer->start( CHECKINTERVAL );
}

void kdarView::slotUpdateProgressBar()
{
    //Update the progress bar with current number of files added to archive.
    if ( m_createConfig->verbose() )
    {
        if ( m_totalFiles > 0 )
        {
            int percentage( (int) ( (float) m_filesProcessedAdded / (float) m_totalFiles * 100 ) );
            //kdDebug() << "percentage is " << percentage << endl;
//            if ( progressBar ) progressBar->setProgress( percentage );
            if ( m_progressDialog )
            {
                m_progressDialog->updateProgressBar( percentage );
                QString operation( i18n( "Creation" ) );
                m_progressDialog->updateCaption( i18n( "i.e., Creation 10% complete...", "%1 %2% complete..." ).arg( operation ).arg( QString::number( percentage ) ) );
            }
        }
    }
}

void kdarView::slotIncrementTotalFiles( KIO::Job *, const unsigned long newArchiveEntries )
{
    m_tmpTotalFiles += newArchiveEntries;
}

void kdarView::slotSetTotalFiles( KIO::Job* )
{
    if ( m_createConfig->verbose() )
    {
        kdarProgressEvent *progressSetTotalFiles = new kdarProgressEvent( kdarProgressEvent::PROGRESS_SET_TOTAL, m_tmpTotalFiles );
        QApplication::postEvent( this, progressSetTotalFiles );
        //Delete the listJob
        if ( m_rootDirListJob )
        {
            m_rootDirListJob = 0;
        }
    }
}

void kdarView::slotConfigureCreationSettings()
{
    //Copy the createConfig instance so that we can
    //cancel the changes if necessary
    KDarConfig * tmpConfig( new KDarConfig(this, 0, m_createConfig, false) );
    tmpConfig->setupCreateConfig();
    disableFeatures( tmpConfig );
    if ( tmpConfig->exec() )
    {
        *m_createConfig = *tmpConfig;
    }
    delete tmpConfig;
}

void kdarView::slotConfigureRestoreSettings()
{
    //Copy the restoreConfig instance so that we can cancel the changes if necessary
    KDarConfig * tmpConfig( new KDarConfig(this, 0, m_restoreConfig, false) );
    tmpConfig->setupRestoreConfig();
    disableFeatures( tmpConfig );
    if ( tmpConfig->exec() )
    {
        *m_restoreConfig = *tmpConfig;
    }
    delete tmpConfig;
}

void kdarView::slotSaveCreationProfile()
{
    //Pop up a save file dialog
    QString saveFilename = KFileDialog::getSaveFileName( KDARDIRKEY, QString( "*" ) + KDAREXTENSION, 0, i18n( "saving a creation profile", "Choose a name for the profile" ) );
    //If successful, set the m_createConfig's KConfig to store to the new file.
    kdar *m_kdar = static_cast<kdar*>( parent() );
    bool okayToWrite = true;
    bool noSave = false;
    QString infoMessage( i18n( "The profile settings were not saved." ) );
    //We need a pointer to the creation dialog: either createDlg or createDlgWizard
    QWidget * parent;
    if ( m_kdarconfig->useCreateArchiveWizard() )
    {
        parent = ( QWidget * ) createDlgWizard;
    }
    else
    {
        parent = ( QWidget * ) createDlg;
    }
    //Continue if the filaname is not empty
    if ( !saveFilename.isEmpty() )
    {
        //Make sure the file ends with .kdar
        if ( !saveFilename.endsWith( KDAREXTENSION ) )
        {
            saveFilename.append( KDAREXTENSION );
        }
        QFile configFile( saveFilename );
        if ( configFile.exists() )
        {
            int result = KMessageBox::questionYesNo( parent, i18n( "The following file already exists:\n\n %1\n\n Do you want to overwrite it?" ).arg( saveFilename ), i18n( "Overwrite profile?" ) );
            if ( result == KMessageBox::No ) okayToWrite = false;
        }
        //Can we create the file?
        if ( okayToWrite )
        {
            if ( configFile.open( IO_ReadWrite ) )
            {
                configFile.close();
                KConfig * newConfig = new KConfig( saveFilename, false, false );
                m_createConfig->setGlobalConfig( newConfig );
                if ( m_kdarconfig->useCreateArchiveWizard() )
                {
                    m_createConfig->setDirectoryToBackup( createDlgWizard->rootDirectoryKURLRequester->lineEdit()->text() );
                    m_createConfig->setNewArchiveName( createDlgWizard->archiveNameKURLRequester->lineEdit()->text() );
                    m_createConfig->setDifferentialBackup( createDlgWizard->diffBackupCheckBox->isChecked() );
                    m_createConfig->setDifferentialBackupArchiveName( createDlgWizard->referenceArchiveKURLRequester->lineEdit()->text() );
                    m_createConfig->setDryRun( createDlgWizard->dryRunCheckBox->isChecked() );
                }
                else
                {
                    m_createConfig->setDirectoryToBackup( createDlg->rootDirectoryKURLRequester->lineEdit()->text() );
                    m_createConfig->setNewArchiveName( createDlg->archiveNameKURLRequester->lineEdit()->text() );
                    m_createConfig->setDifferentialBackup( createDlg->diffBackupCheckBox->isChecked() );
                    m_createConfig->setDifferentialBackupArchiveName( createDlg->referenceArchiveKURLRequester->lineEdit()->text() );
                    m_createConfig->setDryRun( createDlg->dryRunCheckBox->isChecked() );
                }
                m_createConfig->writeGlobalSettings();
                kdDebug() << "slotSaveCreationProfile(): saved settings." << endl;
                //Display a message that the settings were saved.
                if ( m_kdar ) m_kdar->statusBar()->message( i18n( "saving a creation profile", "Settings saved." ), DURATION );
            }
            else
            {
                infoMessage = i18n( "Could not save profile\n\n \"%1\"\n\nReason: %2." ).arg( saveFilename ).arg( qApp->translate( "QFile", configFile.errorString() ) );
                KMessageBox::sorry( parent, infoMessage );
                infoMessage = "";
                noSave = true;
            }
        }
        else
        {
            noSave = true;
        }
    }
    if ( noSave )
    {
        //Display a message that the settings were not saved.
        if ( !infoMessage.isEmpty() ) KMessageBox::information( parent, infoMessage );
        if ( m_kdar ) m_kdar->statusBar()->message( i18n( "saving a creation profile", "Settings not saved." ), DURATION );
    }
}

void kdarView::slotRestoreCreationProfile( const QString & profile )
{
    //Pop up an open file dialog --- the file must exist on disk!
    QString restoreFilename( profile );
    if ( restoreFilename.isEmpty() )
    {
        restoreFilename = KFileDialog::getOpenFileName( KDARDIRKEY, QString( "*" ) + KDAREXTENSION, 0, i18n( "restoring a creation profile", "Choose the profile to restore" ) );
    }
    //If successful, set the m_createConfig's KConfig to restore from the new file.
    kdar *m_kdar = static_cast<kdar*>(parent());
    if ( !restoreFilename.isEmpty() )
    {
        //Make sure the file ends with .kdar
        if ( !restoreFilename.endsWith( KDAREXTENSION ) )
        {
            restoreFilename.append( KDAREXTENSION );
        }
        //Is the file readable?
        QFile configFile( restoreFilename );
        if ( configFile.open( IO_ReadOnly ) )
        {
            configFile.close();
            KConfig* newConfig = new KConfig( restoreFilename, false, false );
            m_createConfig->setGlobalConfig( newConfig );
            m_createConfig->readGlobalSettings();
            m_createConfig->updateGUI();
            //update the create dialogs' settings.
            if ( m_kdarconfig->useCreateArchiveWizard() )
            {
                createDlgWizard->rootDirectoryKURLRequester->lineEdit()->setText( m_createConfig->directoryToBackup() );
                if ( !createDlgWizard->rootDirectoryKURLRequester->lineEdit()->text().isEmpty() )
                {
                    //The archive root directory page: must be selected to continue...
                    createDlgWizard->setNextEnabled( createDlgWizard->page( 2 ), true );
                }
                else
                {
                    createDlgWizard->setNextEnabled( createDlgWizard->page( 2 ), false );
                }
                createDlgWizard->archiveNameKURLRequester->lineEdit()->setText( m_createConfig->newArchiveName() );
                if ( !createDlgWizard->rootDirectoryKURLRequester->lineEdit()->text().isEmpty() )
                {
                    //This is the archive name page: name must beentered to continue...
                    createDlgWizard->setNextEnabled( createDlgWizard->page( 1 ), true );
                }
                else
                {
                    createDlgWizard->setNextEnabled( createDlgWizard->page( 1 ), false );
                }
                createDlgWizard->setNextEnabled( createDlgWizard->page( 0 ), true );
                createDlgWizard->diffBackupCheckBox->setChecked( m_createConfig->differentialBackup() );
                createDlgWizard->referenceArchiveKURLRequester->lineEdit()->setText( m_createConfig->differentialBackupArchiveName() );
                createDlgWizard->dryRunCheckBox->setChecked( m_createConfig->dryRun() );
            }
            else
            {
                createDlg->rootDirectoryKURLRequester->lineEdit()->setText( m_createConfig->directoryToBackup() );
                createDlg->archiveNameKURLRequester->lineEdit()->setText( m_createConfig->newArchiveName() );
                createDlg->diffBackupCheckBox->setChecked( m_createConfig->differentialBackup() );
                createDlg->referenceArchiveKURLRequester->lineEdit()->setText( m_createConfig->differentialBackupArchiveName() );
                createDlg->dryRunCheckBox->setChecked( m_createConfig->dryRun() );
            }
            kdDebug() << "slotRestoreCreationProfile(): saved restored." << endl;
            //Display a message that the settings were restored.
            if ( m_kdar ) m_kdar->statusBar()->message( i18n( "restoring a creation profile", "Settings restored." ), DURATION );
        }
        else
        {
            //Display the error message
            KMessageBox::sorry( extractDlg, i18n( "Failed to open profile\n\n \"%1\"\n\nReason: %2." ).arg( restoreFilename ).arg( qApp->translate( "QFile", configFile.errorString() ) ) );
        }
    }
    else
    {
        //Display a message that the settings were not restored.
        if ( m_kdar ) m_kdar->statusBar()->message( i18n( "restoring a creation profile", "Settings not restored." ), DURATION );
    }
}

void kdarView::slotSaveRestoreProfile()
{
    //Pop up a save file dialog
    QString saveFilename = KFileDialog::getSaveFileName( KDARDIRKEY, QString( "*" ) + KDAREXTENSION, 0, i18n( "saving a restoration profile", "Choose a name for the profile" ) );
    //If successful, set the m_restoreConfig's KConfig to store to the new file.
    kdar *m_kdar = static_cast<kdar*>(parent());
    bool okayToWrite = true;
    bool noSave = false;
    QString infoMessage( i18n( "The profile settings were not saved." ) );
    //We need a pointer to the creation dialog: either createDlg or createDlgWizard
    QWidget * parent;
    if ( m_kdarconfig->useCreateArchiveWizard() )
    {
        parent = ( QWidget * ) createDlgWizard;
    }
    else
    {
        parent = ( QWidget * ) createDlg;
    }
    if ( !saveFilename.isEmpty() )
    {
        //Make sure the file ends with .kdar
        if ( !saveFilename.endsWith( KDAREXTENSION ) )
        {
            saveFilename.append( KDAREXTENSION );
        }
        QFile configFile( saveFilename );
        if ( configFile.exists() )
        {
            int result = KMessageBox::questionYesNo( parent, i18n( "The following file already exists:\n\n %1\n\n Do you want to overwrite it?" ).arg( saveFilename ), i18n( "Overwrite profile?" ) );
            if ( result == KMessageBox::No ) okayToWrite = false;
        }
        //Can we create the file?
        if ( okayToWrite )
        {
            if ( configFile.open( IO_ReadWrite ) )
            {
                configFile.close();
                KConfig * newConfig = new KConfig( saveFilename, false, false );
                m_restoreConfig->setGlobalConfig( newConfig );
                m_restoreConfig->setExtractArchiveDirectory( extractDlg->extractKURLRequester->lineEdit()->text() );
                kdDebug() << "kdarView::slotSaveRestoreProfile(): extraction directory is " << m_restoreConfig->extractArchiveDirectory() << endl;
                m_restoreConfig->setDryRun( extractDlg->dryRunCheckBox->isChecked() );
                m_restoreConfig->writeGlobalSettings();
                kdDebug() << "slotSaveRestoreProfile(): saved settings." << endl;
                //Display a message that the settings were saved.
                if ( m_kdar ) m_kdar->statusBar()->message( i18n( "saving a restoration profile", "Settings saved." ), DURATION );
            }
            else
            {
                infoMessage = i18n( "Could not save profile\n\n \"%1\"\n\nReason: %2." ).arg( saveFilename ).arg( qApp->translate( "QFile", configFile.errorString() ) );
                KMessageBox::sorry( parent, infoMessage );
                infoMessage = "";
                noSave = true;
            }
        }
        else
        {
            noSave = true;
        }
    }
    if ( noSave )
    {
        //Display a message that the settings were not saved.
        if ( !infoMessage.isEmpty() ) KMessageBox::information( parent, infoMessage );
        if ( m_kdar ) m_kdar->statusBar()->message( i18n( "saving a restoration profile", "Settings not saved." ), DURATION );
    }
}

void kdarView::slotRestoreRestoreProfile()
{
    //Pop up an open file dialog --- the file must exist on disk!
    QString restoreFilename = KFileDialog::getOpenFileName( KDARDIRKEY, QString( "*" ) + KDAREXTENSION, 0, i18n( "restoring a restoration profile", "Choose the profile to restore" ) );
    //If successful, set the m_restoreConfig's KConfig to restore from the new file.
    kdar *m_kdar = static_cast<kdar*>(parent());
    if ( !restoreFilename.isEmpty() )
    {
        //Make sure the file ends with .kdar
        if ( !restoreFilename.endsWith( KDAREXTENSION ) )
        {
            restoreFilename.append( KDAREXTENSION );
        }
        //Is the file readable?
        QFile configFile( restoreFilename );
        if ( configFile.open( IO_ReadOnly ) )
        {
            configFile.close();
            KConfig * newConfig = new KConfig( restoreFilename, false, false );
            m_restoreConfig->setGlobalConfig( newConfig );
            m_restoreConfig->readGlobalSettings();
            m_restoreConfig->updateGUI();
            //update the extractDlg's settings.
            kdDebug() << "kdarView::slotRestoreRestoreProfile(): extraction directory is " << m_restoreConfig->extractArchiveDirectory() << endl;
            extractDlg->extractKURLRequester->lineEdit()->setText( m_restoreConfig->extractArchiveDirectory() );
            extractDlg->dryRunCheckBox->setChecked( m_restoreConfig->dryRun() );
            kdDebug() << "kdarView::slotRestoreRestoreProfile(): restored settings." << endl;
            //Display a message that the settings were restored.
            if ( m_kdar ) m_kdar->statusBar()->message( i18n( "restoring a restoration profile", "Settings restored." ), DURATION );
        }
        else
        {
            //Display the error message
            KMessageBox::sorry( extractDlg, i18n( "Failed to open profile\n\n \"%1\"\n\nReason: %2." ).arg( restoreFilename ).arg( qApp->translate( "QFile", configFile.errorString() ) ) );
        }
    }
    else
    {
        //Display a message that the settings were not restored.
        if ( m_kdar ) m_kdar->statusBar()->message( i18n( "restoring a restoration profile", "Settings not restored." ), DURATION );
    }
}

void kdarView::slotExportDarCreateCommand()
{
    //Set the new archive name and root directory in the config object
    if ( m_kdarconfig->useCreateArchiveWizard() )
    {
        m_createConfig->setNewArchiveName( createDlgWizard->archiveNameKURLRequester->lineEdit()->text() );
        m_createConfig->setDirectoryToBackup( createDlgWizard->rootDirectoryKURLRequester->lineEdit()->text() );
        m_createConfig->setDifferentialBackup( createDlgWizard->diffBackupCheckBox->isChecked() );
        m_createConfig->setDifferentialBackupArchiveName( createDlgWizard->referenceArchiveKURLRequester->lineEdit()->text() );
    }
    else
    {
        m_createConfig->setNewArchiveName( createDlg->archiveNameKURLRequester->lineEdit()->text() );
        m_createConfig->setDirectoryToBackup( createDlg->rootDirectoryKURLRequester->lineEdit()->text() );
        m_createConfig->setDifferentialBackup( createDlg->diffBackupCheckBox->isChecked() );
        m_createConfig->setDifferentialBackupArchiveName( createDlg->referenceArchiveKURLRequester->lineEdit()->text() );
    }

    //Ask user for filename to export the dar command as
    QString darFilename = KFileDialog::getSaveFileName( KDARDIRKEY, QString( "*.sh" ), 0, i18n( "Select a filename for the archive creation command" ) );
    if ( !darFilename.isEmpty() )
    {
        //Open the filename for writing, creating it.
        QFile darFile( darFilename );
        if ( darFile.open( IO_WriteOnly ) )
        {
            QTextStream darStream( &darFile );
            //Use "/bin/bash" for the shell
            darStream << "#!/bin/bash" << endl;
            darStream << endl;
            darStream << i18n( "# Run this script to create an archive using the following dar command." ) << endl;
            darStream << endl;
            //send the create dar command string to the file
            darStream << m_createConfig->buildDarCommandLine( KDar::LIBDAR_CREATE );
            //Change permissions to allow execution of the script
            //Is this a security hole?
            //Wait until qt4 to do this?
            //Close the file.
            darFile.close();
        }
        else
        {
            KMessageBox::sorry( this, i18n( "Failed to open file for export." ) );
        }
    }
}

void kdarView::slotExportDarRestoreCommand()
{
    //Ask user for filename to export the dar command as
    QString darFilename = KFileDialog::getSaveFileName( KDARDIRKEY, QString( "*.sh" ), 0, i18n( "Select a filename for the archive restoration command" ) );
    if ( !darFilename.isEmpty() )
    {
        //Open the filename for writing, creating it.
        QFile darFile( darFilename );
        if ( darFile.open( IO_WriteOnly ) )
        {
            QTextStream darStream( &darFile );
            //Use "/bin/bash" for the shell
            darStream << "#!/bin/bash" << endl;
            darStream << endl;
            darStream << i18n( "# Run this script, from a directory that contains an archive, to restore that archive using the following dar command." ) << endl;
            darStream << i18n( "# As it is, this command would restore the named archive (-x argument) onto its original location on the system that created it." ) << endl;
            darStream << i18n( "# Modify the command as needed so that dar restores the archive to the desired location (-R argument) on your system." ) << endl;
            darStream << endl;
            //Use the basename of the archive for the -x argument, not a full path
            KDarConfig *darRestoreConfig = new KDarConfig( this, 0, m_restoreConfig, 0 );
            archiveHandle base( m_restoreConfig->archiveName() );
            darRestoreConfig->setArchiveName( base.getArchiveBasename() );
            darRestoreConfig->setArchiveStorageDirectory( "./" );
            darRestoreConfig->setExtractArchiveDirectory( extractDlg->extractKURLRequester->lineEdit()->text() );
            //send the restore dar command string to the file
            darStream << darRestoreConfig->buildDarCommandLine( KDar::LIBDAR_RESTORE );
            //Change permissions to allow execution of the script
            //Is this a security hole?
            //Wait until qt4 to do this?
            //Close the file.
            darFile.close();
            if ( darRestoreConfig ) delete darRestoreConfig;
            darRestoreConfig = 0;
        }
        else
        {
            KMessageBox::sorry( this, i18n( "Failed to open file for export." ) );
        }
    }
}

void kdarView::updateGUI()
{
    //Update KDar's fonts
    kapp->setFont( m_kdarconfig->generalFont() );
    archiveFileView->setFont( m_kdarconfig->fileBrowserFont() );
    archiveTextBrowser->setFont( m_kdarconfig->messageWindowFont() );
    kdar * m_kdar = static_cast<kdar*>(parent());
    if ( m_kdar ) m_kdar->statusBar()->setFont( m_kdarconfig->statusBarFont() );
}

void kdarView::optionsPreferences()
{
    QString oldArchiveStorageDirectory = m_kdarconfig->archiveStorageDirectory();
    QString statusMessage( i18n( "preferences", "Settings not changed." ) );
    KDarConfig *tmpConfig = new KDarConfig( this, 0, m_kdarconfig, false );
    disableFeatures( tmpConfig );
    //Connect the configure object's changePassword button to
    //an appropriate slot
    connect( tmpConfig, SIGNAL( changeWalletPassword() ), this, SLOT( slotChangePassword() ) );

    if ( tmpConfig->exec() )
    {
        *m_kdarconfig = *tmpConfig;
        //User has changed some global settings here, so update the
        //m_createConfig and m_restoreConfig objects as well.
        *m_createConfig = *tmpConfig;
        *m_restoreConfig = *tmpConfig;
        statusMessage = i18n( "preferences", "Settings changed." );
        QString nullDir = m_kdarconfig->archiveStorageDirectory();
        if ( nullDir[0] != '/' )
        {
            //Send message that the archiveStorage Directory is unchanged.
            statusMessage = i18n( "preferences", "Settings changed. Invalid archive storage directory: left unchanged." );
            //Put the old archiveStorageDir back into the URLRequester.
            m_kdarconfig->setArchiveStorageDirectory( oldArchiveStorageDirectory );
            m_kdarconfig->archiveStorageDirKURLRequester->lineEdit()->setText( oldArchiveStorageDirectory);
        }
        updateGUI();
        m_kdarconfig->writeGlobalSettings();
    }
    //Send status message.
    kdar * m_kdar = static_cast<kdar*>(parent());
    if ( m_kdar ) m_kdar->statusBar()->message(statusMessage, DURATION);
    if ( tmpConfig )
    {
        delete tmpConfig;
        tmpConfig = 0;
    }
}

KConfig * kdarView::globalConfig() const
{
    kdDebug() << "kdarView::globalConfig(): returning m_kdarconfig->globalConfig()" << endl;
    return KGlobal::config();
}

void kdarView::slotArchiveOpenFromDoubleClick(QListViewItem * item)
{
    kdDebug() << "kdarView::slotArchiveOpenFromDoubleClick reached." << endl;
    if (!item) return;
    if ( !item->parent() && !item->firstChild() )
    {
        //ensure that we have at least the top level of the listView populated
        slotArchiveList();
    }
    else
    {
        //If the item has children and it is closed, open it, and vice-versa
        item->setOpen(!item->isOpen());
    }
}

void kdarView::showLogWindow( bool setVisible )
{
    if ( logDialog )
    {
        if ( setVisible )
        {
            if ( !QFile::exists( m_kdarconfig->logFile() ) )
            {
                //create the log file
                QFile file( m_kdarconfig->logFile() );
                file.open( IO_WriteOnly | IO_Append );
                file.close();
            }
            logPart->openURL( m_kdarconfig->logFile() );
            logDialog->show();
        }
        else
        {
            logDialog->hide();
            logPart->closeURL();
        }
    }
}

QString kdarView::elapsedTime()
{
    QString timeString( "" );
    QDateTime currentTime = QDateTime::currentDateTime();
    //calculate days, hours, minutes, seconds
    int days = m_startTime.daysTo( currentTime );
    int seconds = m_startTime.secsTo( currentTime );
    int totaltime = seconds;
    //days
    if ( days > 0 )
    {
        timeString += i18n( "%n day, ", "%n days, ", days );
        seconds -= days * 86400;
    }
    //hours
    int hours = seconds / 3600;
    if ( hours > 0 )
    {
        timeString += i18n( "%n hour, ", "%n hours, ", hours );
        seconds -= hours * 3600;
    }
    //minutes
    int minutes = seconds / 60;
    if ( minutes > 0 )
    {
        timeString += i18n( "%n minute, ", "%n minutes, ", minutes );
        seconds -= minutes * 60;
    }
    //seconds
    if ( seconds > 0 )
    {
        timeString += i18n( "%n second, ", "%n seconds, ", seconds );
    }
    //milliseconds
    if ( totaltime == 0 )
    {
        //To print out times in milliseconds, let's subtract the startTime
        //from the currentTime and print the Current time's milliseconds.
        int secs = m_startTime.secsTo( QDateTime( m_startTime.date() ) );
        currentTime.addSecs( secs );
        timeString += i18n( "total time for operation, in milliseconds. Leave \", \" at the end.", "%1 seconds, " ).arg( currentTime.toString( "0.zzz" ) );
    }
    timeString.remove( timeString.length() - 2, 2 );
    //return string
    return timeString;
}

void kdarView::appendMessage( const QString & message )
{
    if ( !message.isNull() ) archiveTextBrowser->append( message );
}

void kdarView::startFileSizeChecks()
{
    if ( !fileSizeTimer )
    {
        //We need to start a new timer:
        if ( !m_createConfig->dryRun() )
        {
            QString mediaText( m_createConfig->mediaText() );
            if ( !m_createConfig->splitArchiveCheckBox->isChecked() )
            {
                mediaText = i18n( "unspecified (not splitting archive)" );
            }
            if ( m_progressDialog )
            {
                m_progressDialog->setMediaInfo( mediaText );
                m_progressDialog->setSliceInfo( i18n( "Writing slice 1..." ) );
            }
            //create a QTimer for checking the filesize during
            //creation operations
            fileSizeTimer = new QTimer( this );
            connect( fileSizeTimer, SIGNAL( timeout() ), this, SLOT( slotCreationCheckFileSize() ) );
            fileSizeTimer->start( CHECKINTERVAL );
            //Provide user with the elapsed time so far:
            m_elapsedTimer = new QTimer( this );
            connect( m_elapsedTimer, SIGNAL( timeout() ), this, SLOT( slotElapsedTime() ) );
            m_elapsedTimer->start( TIMEELAPSEDINTERVAL );
            //Get the current time so we can inform the user
            //how long it took to make the backup.
            m_startTime = QDateTime::currentDateTime();
        }
        else
        {
            if ( m_progressDialog )
            {
                m_progressDialog->setSliceInfo( i18n( "Dry run: not writing slices." ) );
            }
        }
    }
}

void kdarView::stopFileSizeChecks()
{
    if ( fileSizeTimer )
    {
        fileSizeTimer->stop();
        delete fileSizeTimer;
        fileSizeTimer = 0;
    }
    //Stop the elapsedTimer:
    if ( m_elapsedTimer )
    {
        m_elapsedTimer->stop();
        delete m_elapsedTimer;
        m_elapsedTimer = 0;
    }
    //Print the elapsed time to the log file
    QString elapsedTimeString = i18n( "Total time elapsed since libdar operation began.", "Total time: %1.\n").arg( elapsedTime() );
    if ( m_controller ) m_controller->writeLogMessage( elapsedTimeString );
    //Display the elapsed time on the message window.
    appendMessage( elapsedTimeString );
}

bool kdarView::suspendFileSizeChecks()
{
    bool fileSizeTimerRunning = false;
    if ( fileSizeTimer )
    {
        fileSizeTimerRunning = fileSizeTimer->isActive();
        if ( fileSizeTimerRunning ) fileSizeTimer->stop();
    }
    return fileSizeTimerRunning;
}

void kdarView::resumeFileSizeChecks()
{
    bool fileSizeTimerRunning = false;
    if ( fileSizeTimer )
    {
        fileSizeTimerRunning = fileSizeTimer->isActive();
        if ( !fileSizeTimerRunning ) fileSizeTimer->start( CHECKINTERVAL );
    }
}

void kdarView::displayStatusBarMessage( const QString & message, const int duration )
{
    kdar * m_kdar = static_cast<kdar*>( parent() );
    if ( m_kdar ) m_kdar->statusBar()->message( message, duration );
}

void kdarView::displayNewArchive( QString & text, bool clearView )
{
    if ( clearView ) archiveFileView->clear();
    archiveItem = new kdarListViewItem( archiveFileView, text );
    //set kdar pixmap
    QPixmap smallIcon = SmallIcon( "kdar" );
    archiveItem->setPixmap( 0, smallIcon );
    //This item will contain children:
    (void) new kdarListViewItem( archiveItem, "<empty>" );
}

void kdarView::enableWallet( bool enable )
{
    m_kdarconfig->setStorePassword( enable );
}

bool kdarView::useWallet() const
{
    return m_kdarconfig->storePassword();
}

void kdarView::updateProgressDialogFileInfo( QString & message )
{
        if ( m_progressDialog ) m_progressDialog->setFileInfo( message );
}

void kdarView::updateProgressDialogFileExtraInfo( QString & message )
{
        if ( m_progressDialog ) m_progressDialog->setFileExtraInfo( message );
}

void kdarView::disableFeatures( KDarConfig * config )
{
    if ( !config ) return;
    //compression algorithms
    if ( !m_controller->handlesZCompression() )
    {
        //libz missing
        config->disableZCompression();
    }
    if ( !m_controller->handlesBZ2Compression() )
    {
        //libbz2 missing
        config->disableBZ2Compression();
    }
    if ( !m_controller->handlesZCompression() && !m_controller->handlesBZ2Compression() )
    {
        config->disableCompressionModule();
    }
    //strong cryptography
    if ( !m_controller->handlesStrongCrypto() )
    {
        //libcrypto missing
        config->disableStrongCrypto();
    }
    //kde wallet

}

#include "kdarview.moc"
