Logo Search packages:      
Sourcecode: webissues version File versions  Download package

folderview.cpp

/**************************************************************************
* This file is part of the WebIssues program
* Copyright (C) 2006 Michał Męciński
* Copyright (C) 2007 WebIssues Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
**************************************************************************/

#include "folderview.h"

#include <QTreeView>
#include <QHeaderView>
#include <QLayout>
#include <QLabel>
#include <QComboBox>
#include <QAction>
#include <QMenu>
#include <QMessageBox>
#include <QInputDialog>

#include "models/tableitemmodel.h"
#include "models/tablemodels.h"
#include "models/rowfilters.h"
#include "models/columnconditionsettings.h"
#include "models/treeviewsettings.h"
#include "models/treeviewhelper.h"
#include "data/datamanager.h"
#include "data/updateevent.h"
#include "data/updatebatch.h"
#include "data/connectioninfo.h"
#include "widgets/searcheditbox.h"
#include "dialogs/issuedialogs.h"
#include "dialogs/filterdialog.h"
#include "dialogs/columnsettingsdialog.h"
#include "xmlui/builder.h"
#include "connectionmanager.h"
#include "viewmanager.h"
#include "iconloader.h"

using namespace WebIssues;

00045 FolderView::FolderView( QObject* parent, QWidget* parentWidget ) : View( parent ),
    m_model( NULL ),
    m_filter( NULL ),
    m_filterType( NoFilter )
{
    QAction* action;

    action = new QAction( IconLoader::icon( "file-reload" ), tr( "&Update Folder" ), this );
    action->setShortcut( QKeySequence::Refresh );
    connect( action, SIGNAL( triggered() ), this, SLOT( updateFolder() ) );
    setAction( "updateFolder", action );

    action = new QAction( IconLoader::icon( "issue-open" ), tr( "&Open Issue" ), this );
    action->setShortcut( QKeySequence::Open );
    connect( action, SIGNAL( triggered() ), this, SLOT( openIssue() ) );
    setAction( "openIssue", action );

    action = new QAction( IconLoader::icon( "issue-new" ), tr( "&Add Issue..." ), this );
    action->setShortcut( QKeySequence::New );
    connect( action, SIGNAL( triggered() ), this, SLOT( addIssue() ) );
    setAction( "addIssue", action );

    action = new QAction( IconLoader::icon( "filter" ), tr( "&Change Filter..." ), this );
    action->setShortcut( tr( "Ctrl+F" ) );
    connect( action, SIGNAL( triggered() ), this, SLOT( changeFilter() ) );
    setAction( "changeFilter", action );

    action = new QAction( IconLoader::icon( "filter-save" ), tr( "&Save Filter As..." ), this );
    connect( action, SIGNAL( triggered() ), this, SLOT( saveFilterAs() ) );
    setAction( "saveFilterAs", action );

    action = new QAction( tr( "&Rename Filter..." ), this );
    connect( action, SIGNAL( triggered() ), this, SLOT( renameFilter() ) );
    setAction( "renameFilter", action );

    action = new QAction( tr( "&Delete Filter" ), this );
    connect( action, SIGNAL( triggered() ), this, SLOT( deleteFilter() ) );
    setAction( "deleteFilter", action );

    action = new QAction( IconLoader::icon( "configure-columns" ), tr( "C&onfigure Columns..." ), this );
    connect( action, SIGNAL( triggered() ), this, SLOT( configureColumns() ) );
    setAction( "configureColumns", action );

    setTitle( "menuMain", tr( "&Folder" ) );
    setTitle( "menuEdit", tr( "&Edit" ) );

    loadXmlFile( ":/resources/folderview.xml" );

    QWidget* main = new QWidget( parentWidget );

    QVBoxLayout* mainLayout = new QVBoxLayout( main );
    mainLayout->setMargin( 0 );
    mainLayout->setSpacing( 0 );

    QHBoxLayout* filterLayout = new QHBoxLayout();
    filterLayout->setMargin( 3 );
    filterLayout->setSpacing( 5 );

    mainLayout->addLayout( filterLayout );

    QLabel* filterLabel = new QLabel( tr( "Filte&r:" ), main );
    filterLayout->addWidget( filterLabel );

    m_filterCombo = new QComboBox( main );
    m_filterCombo->setMinimumWidth( 200 );

    connect( m_filterCombo, SIGNAL( activated( int ) ), this, SLOT( filterActivated( int ) ) );

    filterLayout->addWidget( m_filterCombo );

    filterLabel->setBuddy( m_filterCombo );

    filterLayout->addStretch( 1 );

    m_searchBox = new SearchEditBox( main );

    connect( m_searchBox, SIGNAL( textChanged( const QString& ) ), this, SLOT( quickSearchChanged( const QString& ) ) );

    filterLayout->addWidget( m_searchBox );

    m_list = new QTreeView( main );
    m_list->setSortingEnabled( true );
    m_list->setRootIsDecorated( false );
    m_list->setContextMenuPolicy( Qt::CustomContextMenu );

    connect( m_list, SIGNAL( customContextMenuRequested( const QPoint& ) ),
        this, SLOT( listContextMenu( const QPoint& ) ) );
    connect( m_list, SIGNAL( doubleClicked( const QModelIndex& ) ),
        this, SLOT( doubleClicked( const QModelIndex& ) ) );

    mainLayout->addWidget( m_list );

    m_list->header()->setContextMenuPolicy( Qt::CustomContextMenu );

    connect( m_list->header(), SIGNAL( customContextMenuRequested( const QPoint& ) ),
        this, SLOT( headerContextMenu( const QPoint& ) ) );

    setMainWidget( main );

    setViewerSizeHint( QSize( 700, 500 ) );

    m_list->setFocus();
}

00149 FolderView::~FolderView()
{
    if ( isEnabled() ) {
        TreeViewSettings settings;
        settings.openIssuesList( m_typeId );

        settings.saveColumnWidths( TreeViewHelper::readColumnWidths( m_list ) );
    }
}

00159 void FolderView::initialUpdate()
{
    m_filter = new IssueRowFilter( this );

    m_model = new TableItemModel( this );
    m_model->setRowFilter( m_filter );
    m_model->setRootTableModel( new IssuesTableModel( id(), m_model ), dataManager->issues()->parentIndex(), id() );

    connect( m_model, SIGNAL( layoutChanged() ), this, SLOT( updateActions() ) );
    connect( m_model, SIGNAL( layoutChanged() ), this, SLOT( updateSummary() ) );
    connect( m_model, SIGNAL( modelReset() ), this, SLOT( updateActions() ) );
    connect( m_model, SIGNAL( modelReset() ), this, SLOT( updateSummary() ) );

    setAccess( checkDataAccess(), true );

    if ( dataManager->folderUpdateNeeded( id() ) )
        updateFolder();
}

Access FolderView::checkDataAccess()
{
    const FolderRow* folder = dataManager->folders()->find( id() );
    if ( !folder )
        return NoAccess;

    m_projectId = folder->projectId();
    m_typeId = folder->typeId();

    if ( connectionManager->connectionInfo()->access() != AdminAccess ) {
        int userId = connectionManager->connectionInfo()->userId();
        const MemberRow* member = dataManager->members()->find( userId, m_projectId );
        if ( !member )
            return NoAccess;
    }

    const TypeRow* type = dataManager->types()->find( m_typeId );
    if ( !type )
        return UnknownAccess;

    return NormalAccess;
}

00201 void FolderView::enableView()
{
    updateFilters();

    TreeViewSettings settings;
    settings.openIssuesList( m_typeId );

    m_model->setColumns( settings.loadColumns() );

    m_list->setModel( m_model );

    m_list->sortByColumn( 0, Qt::AscendingOrder );

    TreeViewHelper::applyColumnWidths( m_list, settings.loadColumnWidths() );

    connect( m_list->selectionModel(), SIGNAL( selectionChanged( const QItemSelection&, const QItemSelection& ) ),
        this, SLOT( updateActions() ) );

    updateCaption();
    updateActions();
}

00223 void FolderView::disableView()
{
    m_list->setModel( NULL );

    updateCaption();
}

void FolderView::updateCaption()
{
    QString name = tr( "Unknown Folder" );
    if ( isEnabled() ) {
        const FolderRow* row = dataManager->folders()->find( id() );
        if ( row )
            name = row->name();
    }
    setCaption( name );
}

void FolderView::updateActions()
{
    m_selectedIssueId = 0;

    QModelIndex index = selectedIndex();
    if ( index.isValid() )
        m_selectedIssueId = m_model->data( index, TableItemModel::RowIdRole ).toInt();

    action( "openIssue" )->setEnabled( m_selectedIssueId != 0 );
    action( "saveFilterAs" )->setEnabled( m_filterType == NewFilter );
    action( "renameFilter" )->setEnabled( m_filterType == SettingsFilter );
    action( "deleteFilter" )->setEnabled( m_filterType == SettingsFilter );
}

void FolderView::updateSummary()
{
    int items = m_model->rowCount( QModelIndex() );
    int total = m_model->totalCount();

    if ( items == total )
        emit showSummary( QPixmap(), tr( "%1 issues" ).arg( items ) );
    else
        emit showSummary( QPixmap(), tr( "%1 issues (of %2 total)" ).arg( items ).arg( total ) );
}

void FolderView::updateFolder()
{
    if ( isEnabled() && !isUpdating() ) {
        UpdateBatch* batch = new UpdateBatch();
        batch->updateFolder( id() );

        executeUpdate( batch );
    }
}

void FolderView::openIssue()
{
    if ( isEnabled() && m_selectedIssueId != 0 )
        viewManager->openIssueView( m_selectedIssueId, 0 );
}

void FolderView::addIssue()
{
    if ( isEnabled() ) {
        AddIssueDialog dialog( id(), mainWidget() );
        if ( dialog.exec() == QDialog::Accepted )
            viewManager->openIssueView( dialog.issueId(), 0 );
    }
}

void FolderView::changeFilter()
{
    if ( isEnabled() ) {
        FilterDialog dialog( m_projectId, mainWidget() );

        TreeViewSettings settings;
        settings.openIssuesList( m_typeId );

        dialog.setAvailableColumns( settings.availableColumns() );
        dialog.setConditions( m_filter->conditions() );

        connect( &dialog, SIGNAL( settingsApplied() ), this, SLOT( applyFilter() ) );

        dialog.exec();
    }
}

void FolderView::saveFilterAs()
{
    if ( isEnabled() && m_filterType == NewFilter ) {
        QString name = QInputDialog::getText( mainWidget(), tr( "Save Filter As" ),
            tr( "Enter the name of the filter to save:" ), QLineEdit::Normal, tr( "New Filter" ) );

        if ( !name.isNull() ) {
            ColumnConditionSettings settings;
            settings.openIssueFilters( m_typeId );

            if ( settings.filterExists( name ) ) {
                if ( QMessageBox::warning( mainWidget(), tr( "Warning" ),
                    tr( "<qt>Do you want to overwrite the existing filter <b>%1</b>?</qt>" ).arg( name ),
                    QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
                    return;
            }

            settings.saveFilter( name, m_filter->conditions() );

            m_filterType = SettingsFilter;
            m_filterName = name;

            m_newConditions.clear();

            viewManager->postViewEvent( metaObject()->className(), ViewEvent::UpdateFilters, m_typeId );
        }
    }
}

void FolderView::renameFilter()
{
    if ( isEnabled() && m_filterType == SettingsFilter ) {
        QString name = QInputDialog::getText( mainWidget(), tr( "Rename Filter" ),
            tr( "Enter the new name of the filter:" ), QLineEdit::Normal, m_filterName );

        if ( !name.isNull() ) {
            ColumnConditionSettings settings;
            settings.openIssueFilters( m_typeId );

            if ( settings.filterExists( name ) ) {
                if ( QMessageBox::warning( mainWidget(), tr( "Warning" ),
                    tr( "<qt>Do you want to overwrite the existing filter <b>%1</b>?</qt>" ).arg( name ),
                    QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
                    return;
            }

            settings.renameFilter( m_filterName, name );

            m_filterType = SettingsFilter;
            m_filterName = name;

            viewManager->postViewEvent( metaObject()->className(), ViewEvent::UpdateFilters, m_typeId );
        }
    }
}

void FolderView::deleteFilter()
{
    if ( isEnabled() && m_filterType == SettingsFilter ) {
        if ( QMessageBox::warning( mainWidget(), tr( "Delete Filter" ),
            tr( "<qt>Are you sure you want to delete filter <b>%1</b>?</qt>" ).arg( m_filterName ),
            QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
            return;

        ColumnConditionSettings settings;
        settings.openIssueFilters( m_typeId );

        settings.deleteFilter( m_filterName );

        m_filterType = NoFilter;

        viewManager->postViewEvent( metaObject()->className(), ViewEvent::UpdateFilters, m_typeId );
    }
}

void FolderView::configureColumns()
{
    if ( isEnabled() ) {
        ColumnSettingsDialog dialog( mainWidget() );

        const TypeRow* type = dataManager->types()->find( m_typeId );
        QString name = type ? type->name() : QString();

        dialog.setPrompt( tr( "Default columns settings for issues of type <b>%1</b>:" ).arg( name ) );

        TreeViewSettings settings;
        settings.openIssuesList( m_typeId );

        dialog.setAvailableColumns( settings.availableColumns() );
        dialog.setDefaultColumns( settings.defaultColumns() );
        dialog.setFixedColumns( 2 );

        dialog.setColumns( settings.loadColumns() );

        connect( &dialog, SIGNAL( settingsApplied() ), this, SLOT( applyColumns() ) );

        dialog.exec();
    }
}

void FolderView::applyColumns()
{
    if ( isEnabled() ) {
        TreeViewSettings settings;
        settings.openIssuesList( m_typeId );

        ColumnSettingsDialog* dialog = (ColumnSettingsDialog*)sender();
        settings.saveColumns( dialog->columns() );

        viewManager->postViewEvent( metaObject()->className(), ViewEvent::UpdateColumnList, m_typeId );
    }
}

00421 void FolderView::updateEvent( UpdateEvent* e )
{
    setAccess( checkDataAccess() );

    if ( isEnabled() ) {
        if ( e->unit() == UpdateEvent::Projects )
            updateCaption();

        if ( e->unit() == UpdateEvent::Types )
            updateColumnList();
    }

    if ( e->unit() == UpdateEvent::Projects ) {
        if ( dataManager->folderUpdateNeeded( id() ) )
            updateFolder();
    }
}

00439 void FolderView::viewEvent( ViewEvent* e )
{
    if ( isEnabled() && e->action() == ViewEvent::UpdateColumnList && e->id() == m_typeId )
        updateColumnList();
    else if ( isEnabled() && e->action() == ViewEvent::UpdateFilters && e->id() == m_typeId )
        updateFilters();
    else
        View::viewEvent( e );
}

void FolderView::headerContextMenu( const QPoint& pos )
{
    QMenu* menu = builder()->contextMenu( "contextHeader" );
    if ( menu )
        menu->exec( m_list->header()->mapToGlobal( pos ) );
}

void FolderView::listContextMenu( const QPoint& pos )
{
    QModelIndex index = m_list->indexAt( pos );

    QString menuName;
    if ( index.isValid() )
        menuName = "contextIssue";
    else
        menuName = "contextNull";

    QMenu* menu = builder()->contextMenu( menuName );
    if ( menu )
        menu->exec( m_list->viewport()->mapToGlobal( pos ) );
}

void FolderView::doubleClicked( const QModelIndex& index )
{
    if ( index.isValid() ) {
        int issueId = m_model->data( index, TableItemModel::RowIdRole ).toInt();
        viewManager->openIssueView( issueId, 0 );
    }
}

void FolderView::updateColumnList()
{
    TreeViewSettings settings;
    settings.openIssuesList( m_typeId );

    settings.saveColumnWidths( TreeViewHelper::readColumnWidths( m_list ) );

    Column sortColumn = m_model->sortColumn();
    Qt::SortOrder sortOrder = m_model->sortOrder();

    QList<Column> columns = settings.loadColumns();

    m_model->setColumns( settings.loadColumns() );

    int index = columns.indexOf( sortColumn );
    if ( index >= 0 )
        m_list->sortByColumn( index, sortOrder );
    else
        m_list->sortByColumn( 0, Qt::AscendingOrder );

    TreeViewHelper::applyColumnWidths( m_list, settings.loadColumnWidths() );
}

void FolderView::quickSearchChanged( const QString& text )
{
    m_filter->setQuickSearch( text );
}

void FolderView::updateFilters()
{
    m_filterCombo->clear();

    m_filterCombo->addItem( tr( "(All Issues)" ) );

    ColumnConditionSettings settings;
    settings.openIssueFilters( m_typeId );

    QStringList filters = settings.filterNames();

    if ( filters.count() > 0 ) {
        filters.sort();

        m_filterCombo->addItems( filters );

        if ( m_filterType == SettingsFilter ) {
            for ( int i = 0; i < filters.count(); i++ ) {
                if ( filters[ i ] == m_filterName ) {
                    m_filterCombo->setCurrentIndex( i + 1 );
                    break;
                }
            }
        }
    }

    if (  m_newConditions.count() > 0 ) {
        m_filterCombo->addItem( tr( "(Unnamed Filter)" ) );
        if ( m_filterType == NewFilter )
            m_filterCombo->setCurrentIndex( m_filterCombo->count() - 1 );
    }

    if ( m_filterCombo->currentIndex() == 0 )
        m_filterType = NoFilter;

    loadCurrentFilter();

    updateActions();
}

void FolderView::filterActivated( int index )
{
    if ( index == 0 )
        m_filterType = NoFilter;
    else if ( index == m_filterCombo->count() - 1 && m_newConditions.count() > 0 )
        m_filterType = NewFilter;
    else {
        m_filterType = SettingsFilter;
        m_filterName = m_filterCombo->currentText();
    }

    loadCurrentFilter();

    updateActions();
}

void FolderView::loadCurrentFilter()
{
    switch ( m_filterType ) {
        case NoFilter:
            m_filter->setConditions( QList<ColumnCondition>() );
            break;

        case SettingsFilter: {
            ColumnConditionSettings settings;
            settings.openIssueFilters( m_typeId );

            QList<ColumnCondition> conditions = settings.loadFilter( m_filterName );
            m_filter->setConditions( conditions );
            break;
        }

        case NewFilter:
            m_filter->setConditions( m_newConditions );
            break;
    }
}

void FolderView::applyFilter()
{
    if ( isEnabled() ) {
        m_filterType = NewFilter;

        FilterDialog* dialog = (FilterDialog*)sender();
        m_newConditions = dialog->conditions();

        updateFilters();
    }
}

QModelIndex FolderView::selectedIndex()
{
    if ( !m_list->selectionModel() )
        return QModelIndex();

    QModelIndexList selection = m_list->selectionModel()->selectedRows();
    if ( selection.isEmpty() )
        return QModelIndex();

    return selection.at( 0 );
}

#include "folderview.moc"

Generated by  Doxygen 1.6.0   Back to index