Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions |

# An FTP client

This is a more advanced example that implements a FTP client. It uses the QFtp class of Qt indirectly through the QUrlOperator class to do all FTP commands.

The API of the FtpMainWindow class (ftpmainwindow.h):

    /****************************************************************************
    ** $Id:  qt/ftpmainwindow.h   3.0.0   edited Jun 1 18:44 $
    **
    ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
    **
    ** This file is part of an example program for Qt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #ifndef FTPMAINWINDOW_H
    #define FTPMAINWINDOW_H

    #include <qmainwindow.h>
    #include <qurloperator.h>

    class FtpView;
    class QSplitter;
    class QVBox;
    class QSpinBox;
    class QComboBox;
    class QLineEdit;
    class QNetworkOperation;
    class QLabel;
    class QProgressBar;

    class FtpMainWindow : public QMainWindow
    {
        Q_OBJECT

    public:
        FtpMainWindow();

        QSplitter *mainSplitter() const {
            return splitter;
        }

    private:
        void setupLeftSide();
        void setupRightSide();
        void setupCenterCommandBar();
        void setup();

    private slots:
        void slotLocalDirChanged( const QString &path );
        void slotLocalDirChanged( const QUrlInfo &info );
        void slotRemoteDirChanged( const QString &path );
        void slotRemoteDirChanged( const QUrlInfo &info );
        void slotConnect();
        void slotUpload();
        void slotDownload();
        void slotLocalStart( QNetworkOperation * );
        void slotLocalFinished( QNetworkOperation * );
        void slotRemoteStart( QNetworkOperation * );
        void slotRemoteFinished( QNetworkOperation * );
        void slotLocalDataTransferProgress( int, int, QNetworkOperation * );
        void slotRemoteDataTransferProgress( int, int, QNetworkOperation * );
        void slotLocalMkDir();
        void slotLocalRemove();
        void slotRemoteMkDir();
        void slotRemoteRemove();
        void slotConnectionStateChanged( int, const QString &msg );

    private:
        QSplitter *splitter;
        QVBox *mainWidget;
        FtpView *leftView, *rightView;
        QComboBox *localCombo, *remoteHostCombo, *remotePathCombo, *userCombo;
        QLineEdit *passLined;
        QSpinBox *portSpin;
        QUrlOperator localOperator, remoteOperator, oldLocal, oldRemote;
        QLabel *progressLabel1, *progressLabel2;
        QProgressBar *progressBar1, *progressBar2;

    };

    #endif

The Implementation of the FtpMainWindow class (ftpmainwindow.cpp):

    /****************************************************************************
    ** $Id:  qt/ftpmainwindow.cpp   3.0.0   edited Jun 1 18:44 $
    **
    ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
    **
    ** This file is part of an example program for Qt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #include "ftpmainwindow.h"
    #include "ftpview.h"

    #include <qvbox.h>
    #include <qhbox.h>
    #include <qsplitter.h>
    #include <qcombobox.h>
    #include <qlabel.h>
    #include <qspinbox.h>
    #include <qlineedit.h>
    #include <qpushbutton.h>
    #include <qmessagebox.h>
    #include <qprogressbar.h>
    #include <qdir.h>
    #include <qinputdialog.h>
    #include <qapplication.h>
    #include <qstatusbar.h>

    FtpMainWindow::FtpMainWindow()
        : QMainWindow(),
          localOperator( "/" )
    {
        setup();

        // connect to the signals of the local QUrlOperator - this will be used to
        // work on the local file system (listing dirs, etc.) and to copy files
        // TO the local filesystem (downloading)
        connect( &localOperator, SIGNAL( newChildren( const QValueList<QUrlInfo> &, QNetworkOperation * ) ),
                 leftView, SLOT( slotInsertEntries( const QValueList<QUrlInfo> & ) ) );
        connect( &localOperator, SIGNAL( start( QNetworkOperation * ) ),
                 this, SLOT( slotLocalStart( QNetworkOperation *) ) );
        connect( &localOperator, SIGNAL( finished( QNetworkOperation * ) ),
                 this, SLOT( slotLocalFinished( QNetworkOperation *) ) );
        connect( leftView, SIGNAL( itemSelected( const QUrlInfo & ) ),
                 this, SLOT( slotLocalDirChanged( const QUrlInfo & ) ) );
        connect( &localOperator, SIGNAL( dataTransferProgress( int, int, QNetworkOperation * ) ),
                 this, SLOT( slotLocalDataTransferProgress( int, int, QNetworkOperation * ) ) );

        // connect to the signals of the remote QUrlOperator - this will be used to
        // work on the remote file system (on the FTP Server) and to copy files
        // TO the ftp server (uploading)
        connect( &remoteOperator, SIGNAL( newChildren( const QValueList<QUrlInfo> &, QNetworkOperation * ) ),
                 rightView, SLOT( slotInsertEntries( const QValueList<QUrlInfo> & ) ) );
        connect( &remoteOperator, SIGNAL( start( QNetworkOperation * ) ),
                 this, SLOT( slotRemoteStart( QNetworkOperation *) ) );
        connect( &remoteOperator, SIGNAL( finished( QNetworkOperation * ) ),
                 this, SLOT( slotRemoteFinished( QNetworkOperation *) ) );
        connect( rightView, SIGNAL( itemSelected( const QUrlInfo & ) ),
                 this, SLOT( slotRemoteDirChanged( const QUrlInfo & ) ) );
        connect( &remoteOperator, SIGNAL( dataTransferProgress( int, int, QNetworkOperation * ) ),
                 this, SLOT( slotRemoteDataTransferProgress( int, int, QNetworkOperation * ) ) );
        connect( &remoteOperator, SIGNAL( connectionStateChanged( int, const QString & ) ),
                 this, SLOT( slotConnectionStateChanged( int, const QString & ) ) );

        // read the local filesystem at the beginning once
        localOperator.listChildren();

        // create status bar
        (void)statusBar();
    }

    void FtpMainWindow::setupLeftSide()
    {
        // Setup the left side of the GUI, this is the listview
        // of the local filesystem

        QVBox *layout = new QVBox( splitter );
        layout->setSpacing( 5 );
        layout->setMargin( 5 );

        QHBox *h = new QHBox( layout );
        h->setSpacing( 5 );
        QLabel *l = new QLabel( tr( "Local Path:" ), h );
        l->setFixedWidth( l->sizeHint().width() );
        localCombo = new QComboBox( TRUE, h );
        localCombo->insertItem( "/" );

        connect( localCombo, SIGNAL( activated( const QString & ) ),
                 this, SLOT( slotLocalDirChanged( const QString & ) ) );

        leftView = new FtpView( layout );

        QHBox *bottom = new QHBox( layout );
        bottom->setSpacing( 5 );
        QPushButton *bMkDir = new QPushButton( tr( "New Directory" ), bottom );
        QPushButton *bRemove = new QPushButton( tr( "Remove" ), bottom );
        connect( bMkDir, SIGNAL( clicked() ),
                 this, SLOT( slotLocalMkDir() ) );
        connect( bRemove, SIGNAL( clicked() ),
                 this, SLOT( slotLocalRemove() ) );

        splitter->setResizeMode( layout, QSplitter::Stretch );
    }

    void FtpMainWindow::setupRightSide()
    {
        // Setup the right side of the GUI, this is the listview
        // of the remote filesystem (FTP), needs also lineedits/combos
        // for username, password, etc.

        QVBox *layout = new QVBox( splitter );
        layout->setSpacing( 5 );
        layout->setMargin( 5 );

        QHBox *h = new QHBox( layout );
        h->setSpacing( 5 );
        QLabel *l = new QLabel( tr( "Remote Host:" ), h );
        l->setFixedWidth( l->sizeHint().width() );
        remoteHostCombo = new QComboBox( TRUE, h );

        l = new QLabel( tr( "Port:" ), h );
        l->setFixedWidth( l->sizeHint().width() );
        portSpin = new QSpinBox( 0, 32767, 1, h );
        portSpin->setValue( 21 );
        portSpin->setFixedWidth( portSpin->sizeHint().width() );
        remoteOperator.setPort( portSpin->value() );

        h = new QHBox( layout );
        h->setSpacing( 5 );
        l = new QLabel( tr( "Remote Path:" ), h );
        l->setFixedWidth( l->sizeHint().width() );
        remotePathCombo = new QComboBox( TRUE, h );

        h = new QHBox( layout );
        h->setSpacing( 5 );
        l = new QLabel( tr( "Username:" ), h );
        l->setFixedWidth( l->sizeHint().width() );
        userCombo = new QComboBox( TRUE, h );

        l = new QLabel( tr( "Password:" ), h );
        l->setFixedWidth( l->sizeHint().width() );
        passLined = new QLineEdit( h );
        passLined->setEchoMode( QLineEdit::Password );

        rightView = new FtpView( layout );

        QHBox *bottom = new QHBox( layout );
        bottom->setSpacing( 5 );
        QPushButton *bMkDir = new QPushButton( tr( "New Directory" ), bottom );
        QPushButton *bRemove = new QPushButton( tr( "Remove" ), bottom );
        connect( bMkDir, SIGNAL( clicked() ),
                 this, SLOT( slotRemoteMkDir() ) );
        connect( bRemove, SIGNAL( clicked() ),
                 this, SLOT( slotRemoteRemove() ) );

        splitter->setResizeMode( layout, QSplitter::Stretch );

        connect( remotePathCombo, SIGNAL( activated( const QString & ) ),
                 this, SLOT( slotRemoteDirChanged( const QString & ) ) );
    }

    void FtpMainWindow::setupCenterCommandBar()
    {
        // Setup the command bar in the middle between the two views

        QVBox *w = new QVBox( splitter );
        splitter->setResizeMode( w, QSplitter::FollowSizeHint );
        w->setSpacing( 5 );
        w->setMargin( 5 );

        QPushButton *bConnect = new QPushButton( tr( "&Connect" ), w );
        (void)new QWidget( w );
        QPushButton *bUpload = new QPushButton( tr( "== &Upload ==>" ), w );
        QPushButton *bDownload = new QPushButton( tr( "<== &Download ==" ), w );
        (void)new QWidget( w );

        connect( bConnect, SIGNAL( clicked() ),
                 this, SLOT( slotConnect() ) );
        connect( bUpload, SIGNAL( clicked() ),
                 this, SLOT( slotUpload() ) );
        connect( bDownload, SIGNAL( clicked() ),
                 this, SLOT( slotDownload() ) );
    }

    void FtpMainWindow::setup()
    {
        // Setup the GUI

        mainWidget = new QVBox( this );
        splitter = new QSplitter( mainWidget );
        setupLeftSide();
        setupCenterCommandBar();
        setupRightSide();

        progressLabel1 = new QLabel( tr( "No Operation in Progress" ), mainWidget );
        progressBar1 = new QProgressBar( mainWidget );
        progressLabel2 = new QLabel( tr( "No Operation in Progress" ), mainWidget );
        progressBar2 = new QProgressBar( mainWidget );

        progressLabel1->hide();
        progressBar1->hide();
        progressLabel2->hide();
        progressBar2->hide();

        setCentralWidget( mainWidget );
    }

    void FtpMainWindow::slotLocalDirChanged( const QString &path )
    {
        // The user changed the path on the left side

        oldLocal = localOperator;
        localOperator.setPath( path );
        localOperator.listChildren();
    }

    void FtpMainWindow::slotLocalDirChanged( const QUrlInfo &info )
    {
        // The user changed the path on the left side

        oldLocal = localOperator;
        localOperator.addPath( info.name() );
        localOperator.listChildren();
        localCombo->insertItem( localOperator.path(), 0 );
        localCombo->setCurrentItem( 0 );
    }

    void FtpMainWindow::slotRemoteDirChanged( const QString &path )
    {
        // The user changed the path on the right side

        if ( !remoteOperator.isValid() )
            return;
        oldRemote = remoteOperator;
        remoteOperator.setPath( path );
        remoteOperator.listChildren();
    }

    void FtpMainWindow::slotRemoteDirChanged( const QUrlInfo &info )
    {
        // The user changed the path on the right side

        oldRemote = remoteOperator;
        remoteOperator.addPath( info.name() );
        remoteOperator.listChildren();
        remotePathCombo->insertItem( remoteOperator.path(), 0 );
        remotePathCombo->setCurrentItem( 0 );
    }

    void FtpMainWindow::slotConnect()
    {
        // The user pressed the connect button, so let's connect to the
        // FTP server
        // First we need to set stuff (host, path, etc.) which the user
        // entered on the right side to the remote QUrlOperator

        // protocol + hostname
        QString s = "ftp://" + remoteHostCombo->currentText();
        oldRemote = remoteOperator;
        remoteOperator = s;

        // path on the server
        if ( !remotePathCombo->currentText().isEmpty() )
            remoteOperator.setPath( remotePathCombo->currentText() );
        else
            remoteOperator.setPath( "/" );

        // if nothing or "ftp" or "anonymous" has been entered into the username combo,
        // let's connect anonymous, else private with password
        if ( !userCombo->currentText().isEmpty() &&
             userCombo->currentText().lower() != "anonymous" &&
             userCombo->currentText().lower() != "ftp" ) {
            remoteOperator.setUser( userCombo->currentText() );
            remoteOperator.setPassword( passLined->text() );
        }

        // set the port
        remoteOperator.setPort( portSpin->value() );

        // finally read the directory on the ftp server
        remoteOperator.listChildren();
    }

    void FtpMainWindow::slotUpload()
    {
        // the user pressed the upload button

        // if files have been selected on the left side (local filesystem)
        QValueList<QUrlInfo> files = leftView->selectedItems();
        if ( files.isEmpty() )
            return;

        // create a list of the URLs which should be copied
        QStringList lst;
        QValueList<QUrlInfo>::Iterator it = files.begin();
        for ( ; it != files.end(); ++it )
            lst << QUrl( localOperator, ( *it ).name() );

        // copy the list of selected files to the directory in which the
        // remoteOperator currently is (upload)
        remoteOperator.copy( lst, remoteOperator, FALSE );
    }

    void FtpMainWindow::slotDownload()
    {
        // if the user pressed the download button

        // if files have been selected on the right side (remote filesystem)
        QValueList<QUrlInfo> files = rightView->selectedItems();
        if ( files.isEmpty() )
            return;

        // create a list of the URLs which should be downloaded
        QStringList lst;
        QValueList<QUrlInfo>::Iterator it = files.begin();
        for ( ; it != files.end(); ++it )
            lst << QUrl( remoteOperator, ( *it ).name() );

        // copy the list of selected files to the directory in which the
        // localOperator currently is (download)
        localOperator.copy( lst, localOperator, FALSE );
    }

    void FtpMainWindow::slotLocalStart( QNetworkOperation *op )
    {
        // this slot is always called if the local QUrlOperator starts
        // listing a directory or dowloading a file

        if ( !op )
            return;

        if ( op->operation() == QNetworkProtocol::OpListChildren ) {
            // start listing a dir? clear the left view!
            leftView->clear();
        } else if ( op->operation() == QNetworkProtocol::OpGet ) {
            // start downloading a file? reset the progress bar!
            progressBar1->setTotalSteps( 0 );
            progressBar1->reset();
        }
    }

    void FtpMainWindow::slotLocalFinished( QNetworkOperation *op )
    {
        // this slot is always called if the local QUrlOperator finished
        // an operation

        if ( !op )
            return;

        if ( op && op->state() == QNetworkProtocol::StFailed ) {
            // an error happend, let the user know that
            QMessageBox::critical( this, tr( "ERROR" ), op->protocolDetail() );

            // do something depending in the error code
            int ecode = op->errorCode();
            if ( ecode == QNetworkProtocol::ErrListChildren || ecode == QNetworkProtocol::ErrParse ||
                 ecode == QNetworkProtocol::ErrUnknownProtocol || ecode == QNetworkProtocol::ErrLoginIncorrect ||
                 ecode == QNetworkProtocol::ErrValid || ecode == QNetworkProtocol::ErrHostNotFound ||
                 ecode == QNetworkProtocol::ErrFileNotExisting ) {
                localOperator = oldLocal;
                localCombo->setEditText( localOperator.path() );
                localOperator.listChildren();
            }
        } else if ( op->operation() == QNetworkProtocol::OpPut ) {
            // finished saving the downloaded file? reread the dir and hide the progress bar
            localOperator.listChildren();
            progressLabel1->hide();
            progressBar1->hide();
        } else if ( op->operation() == QNetworkProtocol::OpGet ) {
            // finished reading a file from the ftp server? reset the progress bar
            progressBar1->setTotalSteps( 0 );
            progressBar1->reset();
        }

    }

    void FtpMainWindow::slotRemoteStart( QNetworkOperation *op )
    {
        // this slot is always called if the remote QUrlOperator starts
        // listing a directory or uploading a file

        if ( !op )
            return;

        if ( op->operation() == QNetworkProtocol::OpListChildren ) {
            // start listing a dir? clear the right view!
            rightView->clear();
        } else if ( op->operation() == QNetworkProtocol::OpGet ) {
            // start downloading a file? reset the progress bar!
            progressBar2->setTotalSteps( 0 );
            progressBar2->reset();
        }
    }

    void FtpMainWindow::slotRemoteFinished( QNetworkOperation *op )
    {
        // this slot is always called if the remote QUrlOperator finished
        // an operation

        if ( !op )
            return;

        if ( op && op->state() == QNetworkProtocol::StFailed ) {
            // an error happend, let the user know that
            QMessageBox::critical( this, tr( "ERROR" ), op->protocolDetail() );

            // do something depending in the error code
            int ecode = op->errorCode();
            if ( ecode == QNetworkProtocol::ErrListChildren || ecode == QNetworkProtocol::ErrParse ||
                 ecode == QNetworkProtocol::ErrUnknownProtocol || ecode == QNetworkProtocol::ErrLoginIncorrect ||
                 ecode == QNetworkProtocol::ErrValid || ecode == QNetworkProtocol::ErrHostNotFound ||
                 ecode == QNetworkProtocol::ErrFileNotExisting ) {
                remoteOperator = oldRemote;
                remoteHostCombo->setEditText( remoteOperator.host() );
                remotePathCombo->setEditText( remoteOperator.path() );
                passLined->setText( remoteOperator.password() );
                userCombo->setEditText( remoteOperator.user() );
                portSpin->setValue( remoteOperator.port() );
                remoteOperator.listChildren();
            }
        } else if ( op->operation() == QNetworkProtocol::OpListChildren ) {
            // finished reading a dir? set the correct path to the pth combo of the right view
            remotePathCombo->setEditText( remoteOperator.path() );
        } else if ( op->operation() == QNetworkProtocol::OpPut ) {
            // finished saving the uploaded file? reread the dir and hide the progress bar
            remoteOperator.listChildren();
            progressLabel2->hide();
            progressBar2->hide();
        } else if ( op->operation() == QNetworkProtocol::OpGet ) {
            // finished reading a file from the local filesystem? reset the progress bar
            progressBar2->setTotalSteps( 0 );
            progressBar2->reset();
        }
    }

    void FtpMainWindow::slotLocalDataTransferProgress( int bytesDone, int bytesTotal,
                                                       QNetworkOperation *op )
    {
        // Show the progress here of the local QUrlOperator reads or writes data

        if ( !op )
            return;

        if ( !progressBar1->isVisible() ) {
            if ( bytesDone < bytesTotal) {
                progressLabel1->show();
                progressBar1->show();
                progressBar1->setTotalSteps( bytesTotal );
                progressBar1->setProgress( 0 );
                progressBar1->reset();
            } else
                return;
        }

        if ( progressBar1->totalSteps() == bytesTotal )
            progressBar1->setTotalSteps( bytesTotal );

        if ( op->operation() == QNetworkProtocol::OpGet )
            progressLabel1->setText( tr( "Read: %1" ).arg( op->arg( 0 ) ) );
        else if ( op->operation() == QNetworkProtocol::OpPut )
            progressLabel1->setText( tr( "Write: %1" ).arg( op->arg( 0 ) ) );
        else
            return;

        progressBar1->setProgress( bytesDone );
    }

    void FtpMainWindow::slotRemoteDataTransferProgress( int bytesDone, int bytesTotal,
                                                        QNetworkOperation *op )
    {
        // Show the progress here of the remote QUrlOperator reads or writes data

        if ( !op )
            return;

        if ( !progressBar2->isVisible() ) {
            if ( bytesDone < bytesTotal) {
                progressLabel2->show();
                progressBar2->show();
                progressBar2->setTotalSteps( bytesTotal );
                progressBar2->setProgress( 0 );
                progressBar2->reset();
            } else
                return;
        }

        if ( progressBar2->totalSteps() != bytesTotal )
            progressBar2->setTotalSteps( bytesTotal );

        if ( op->operation() == QNetworkProtocol::OpGet )
            progressLabel2->setText( tr( "Read: %1" ).arg( op->arg( 0 ) ) );
        else if ( op->operation() == QNetworkProtocol::OpPut )
            progressLabel2->setText( tr( "Write: %1" ).arg( op->arg( 0 ) ) );
        else
            return;

        progressBar2->setProgress( bytesDone );
    }

    void FtpMainWindow::slotLocalMkDir()
    {
        // create a dir on the local filesystem

        bool ok = FALSE;
        QString name = QInputDialog::getText( tr( "Directory Name:" ), QString::null, QLineEdit::Normal, QString::null, &ok, this );

        if ( !name.isEmpty() && ok )
            localOperator.mkdir( name );
    }

    void FtpMainWindow::slotLocalRemove()
    {
    }

    void FtpMainWindow::slotRemoteMkDir()
    {
        // create a dir on the remote filesystem (FTP server)

        bool ok = FALSE;
        QString name = QInputDialog::getText( tr( "Directory Name:" ), QString::null, QLineEdit::Normal, QString::null, &ok, this );

        if ( !name.isEmpty() && ok )
            remoteOperator.mkdir( name );
    }

    void FtpMainWindow::slotRemoteRemove()
    {
    }

    void FtpMainWindow::slotConnectionStateChanged( int, const QString &msg )
    {
        statusBar()->message( msg );
    }

The API of the FtpViewItem and FtpView classes (ftpview.h):

    /****************************************************************************
    ** $Id:  qt/ftpview.h   3.0.0   edited Sep 11 10:46 $
    **
    ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
    **
    ** This file is part of an example program for Qt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #ifndef FTPVIEW_H
    #define FTPVIEW_H

    #include <qlistview.h>
    #include <qvaluelist.h>
    #include <qurlinfo.h>

    class FtpViewItem : public QListViewItem
    {
    public:
        FtpViewItem( QListView *parent, const QUrlInfo &i );

        int compare( QListViewItem * i, int col, bool ascending ) const;
        QString text( int c ) const;
        const QPixmap* pixmap( int c ) const;

        QUrlInfo entryInfo() {
            return info;
        }

    private:
        QUrlInfo info;

    };

    class FtpView : public QListView
    {
        Q_OBJECT

    public:
        FtpView( QWidget *parent );
        QValueList<QUrlInfo> selectedItems() const;

    public slots:
        void slotInsertEntries( const QValueList<QUrlInfo> &info );

    signals:
        void itemSelected( const QUrlInfo &info );

    private slots:
        void slotSelected( QListViewItem *item );

    };

    #endif

Their Implementation (ftpview.cpp):

    /****************************************************************************
    ** $Id:  qt/ftpview.cpp   3.0.0   edited Sep 28 21:04 $
    **
    ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
    **
    ** This file is part of an example program for Qt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #include "ftpview.h"

    #include <qpixmap.h>
    #include <qvaluelist.h>

    /* XPM */
    static const char* closed_xpm[]={
        "15 15 6 1",
        ". c None",
        "b c #ffff00",
        "d c #000000",
        "* c #999999",
        "a c #cccccc",
        "c c #ffffff",
        "...............",
        "..*****........",
        ".*ababa*.......",
        "*abababa******.",
        "*cccccccccccc*d",
        "*cbababababab*d",
        "*cabababababa*d",
        "*cbababababab*d",
        "*cabababababa*d",
        "*cbababababab*d",
        "*cabababababa*d",
        "*cbababababab*d",
        "**************d",
        ".dddddddddddddd",
        "..............."};

    /* XPM */
    static const char* file_xpm[]={
        "13 15 5 1",
        ". c #7f7f7f",
        "# c None",
        "c c #000000",
        "b c #bfbfbf",
        "a c #ffffff",
        "..........###",
        ".aaaaaaaab.##",
        ".aaaaaaaaba.#",
        ".aaaaaaaacccc",
        ".aaaaaaaaaabc",
        ".aaaaaaaaaabc",
        ".aaaaaaaaaabc",
        ".aaaaaaaaaabc",
        ".aaaaaaaaaabc",
        ".aaaaaaaaaabc",
        ".aaaaaaaaaabc",
        ".aaaaaaaaaabc",
        ".aaaaaaaaaabc",
        ".bbbbbbbbbbbc",
        "ccccccccccccc"};

    QPixmap *folderIcon = 0;
    QPixmap *fileIcon = 0;

    FtpViewItem::FtpViewItem( QListView *parent, const QUrlInfo &i )
        : QListViewItem( parent, i.name() ), info( i )
    {
    }

    int FtpViewItem::compare( QListViewItem * i, int col, bool ascending ) const
    {
        FtpViewItem *other = (FtpViewItem*)i;
        switch ( col ) {
        case 1:
            if ( info.size() == other->info.size() )
                return 0;
            else
                return info.size() < other->info.size() ? -1 : 1;
        case 2:
            if ( info.lastModified() == other->info.lastModified() )
                return 0;
            else
                return info.lastModified() < other->info.lastModified() ? -1 : 1;
        default:
            // use default method for colum 0 and others added in the future
            return QListViewItem::compare( i, col, ascending );
        };
    }

    QString FtpViewItem::text( int c ) const
    {
        switch ( c ) {
        case 0:
            return info.name();
        case 1:
            return QString::number( info.size() );
        case 2:
            return info.lastModified().toString();
        }

        return "????";
    }

    const QPixmap *FtpViewItem::pixmap( int c ) const
    {
        if ( !folderIcon )
            folderIcon = new QPixmap( closed_xpm );
        if ( !fileIcon )
            fileIcon = new QPixmap( file_xpm );
        if ( info.isDir() && c == 0 )
            return folderIcon;
        else if ( info.isFile() && c == 0 )
            return fileIcon;
        return 0;
    }

    FtpView::FtpView( QWidget *parent )
        : QListView( parent )
    {
        addColumn( tr( "Name" ) );
        addColumn( tr( "Size" ) );
        addColumn( tr( "Last Modified" ) );
        setColumnAlignment( 1, Qt::AlignRight );
        setShowSortIndicator( TRUE );
        setAllColumnsShowFocus( TRUE );
        setSelectionMode( Extended );

        connect( this, SIGNAL( doubleClicked( QListViewItem * ) ),
                 this, SLOT( slotSelected( QListViewItem * ) ) );
        connect( this, SIGNAL( returnPressed( QListViewItem * ) ),
                 this, SLOT( slotSelected( QListViewItem * ) ) );
    }

    void FtpView::slotInsertEntries( const QValueList<QUrlInfo> &info )
    {
        QValueList<QUrlInfo>::ConstIterator it;
        for( it = info.begin(); it != info.end(); ++it ) {
            if ( (*it).name() != ".." && (*it).name() != "." && (*it).name()[ 0 ] == '.' )
                continue;
            FtpViewItem *item = new FtpViewItem( this, (*it) );
            if ( (*it).isDir() )
                item->setSelectable( FALSE );
        }
    }

    void FtpView::slotSelected( QListViewItem *item )
    {
        if ( !item )
            return;

        FtpViewItem *i = (FtpViewItem*)item;
        if ( i->entryInfo().isDir() )
            emit itemSelected( i->entryInfo() );
    }

    QValueList<QUrlInfo> FtpView::selectedItems() const
    {
        QValueList<QUrlInfo> lst;
        QListViewItemIterator it( (QListView*)this );
        for ( ; it.current(); ++it ) {
            if ( it.current()->isSelected() ) {
                lst << ( (FtpViewItem*)it.current() )->entryInfo();
            }
        }

        return lst;
    }

Main (main.cpp):

    /****************************************************************************
    ** $Id:  qt/main.cpp   3.0.0   edited Jun 1 18:44 $
    **
    ** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
    **
    ** This file is part of an example program for Qt.  This example
    ** program may be used, distributed and modified without limitation.
    **
    *****************************************************************************/

    #include <qapplication.h>
    #include <qnetwork.h>
    #include <qsplitter.h>

    #include "ftpmainwindow.h"

    int main( int argc, char **argv )
    {
        QApplication a( argc, argv );

        // call this to register the FTP network protocol
        // (and in the future more available ones)
        qInitNetworkProtocols();

        FtpMainWindow m;
        a.setMainWidget( &m );
        QValueList<int> sizes;
        sizes << 300 << 70 << 300;
        m.mainSplitter()->setSizes( sizes );
        m.resize( 800, 600 );
        m.show();
        return a.exec();
    }

See also Network Examples.