/src/libtomahawk/widgets/checkdirtree.cpp
http://github.com/tomahawk-player/tomahawk · C++ · 397 lines · 283 code · 66 blank · 48 comment · 39 complexity · 29dec88a4eb2417a957544a3ddea28b1 MD5 · raw file
- /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
- *
- * Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
- * Copyright 2011, Leo Franchi <lfranchi@kde.org>
- *
- * Tomahawk 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 3 of the License, or
- * (at your option) any later version.
- *
- * Tomahawk is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "CheckDirTree.h"
- #include "utils/Logger.h"
- #include "TomahawkSettings.h"
- #include "Source.h"
- #include <QCoreApplication>
- #include <QProcess>
- static QString s_macVolumePath = "/Volumes";
- CheckDirModel::CheckDirModel( QWidget* parent )
- : QFileSystemModel( parent )
- , m_shownVolumes( false )
- {
- #ifdef Q_OS_MAC
- m_setFilePath = QString( "%1/SetFile" ) .arg( QCoreApplication::applicationDirPath() );
- m_getFileInfoPath = QString( "%1/GetFileInfo" ).arg( QCoreApplication::applicationDirPath() );
- QProcess* checkVolumeVisible = new QProcess( this );
- connect( checkVolumeVisible, SIGNAL( readyReadStandardOutput() ), this, SLOT( getFileInfoResult() ) );
- qDebug() << "Running GetFileInfo:" << m_getFileInfoPath << "-aV" << s_macVolumePath;
- checkVolumeVisible->start( m_getFileInfoPath, QStringList() << "-aV" << s_macVolumePath );
- #endif
- }
- CheckDirModel::~CheckDirModel()
- {
- #ifdef Q_OS_MAC
- // reset to previous state
- if ( m_shownVolumes )
- QProcess::startDetached( QString( "%1 -a V %2" ).arg( m_setFilePath).arg( s_macVolumePath ) );
- #endif
- }
- void
- CheckDirModel::getFileInfoResult()
- {
- #ifdef Q_OS_MAC
- QProcess* p = qobject_cast< QProcess* >( sender() );
- Q_ASSERT( p );
- QByteArray res = p->readAll().trimmed();
- qDebug() << "Got output from GetFileInfo:" << res;
- // 1 means /Volumes is hidden, so we show it while the dialog is visible
- if ( res == "1" )
- {
- // Remove the hidden flag for the /Volumnes folder so all mount points are visible in the default (Q)FileSystemModel
- QProcess* showProcess = new QProcess( this );
- qDebug() << "Running SetFile:" << QString( "%1 -a v %2" ).arg( m_setFilePath ).arg( s_macVolumePath );
- showProcess->start( QString( "%1 -a v %2" ).arg( m_setFilePath ).arg( s_macVolumePath ) );
- connect( showProcess, SIGNAL( readyReadStandardError() ), this, SLOT( processErrorOutput() ) );
- m_shownVolumes = true;
- QTimer::singleShot( 500, this, SLOT( volumeShowFinished() ) );
- }
- p->terminate();
- p->deleteLater();
- #endif
- }
- void
- CheckDirModel::volumeShowFinished()
- {
- reset();
- }
- void
- CheckDirModel::processErrorOutput()
- {
- QProcess* p = qobject_cast< QProcess* >( sender() );
- Q_ASSERT( p );
- qDebug() << "Got ERROR OUTPUT from subprocess in CheckDirModel:" << p->readAll();
- }
- Qt::ItemFlags
- CheckDirModel::flags( const QModelIndex& index ) const
- {
- return QFileSystemModel::flags( index ) | Qt::ItemIsUserCheckable;
- }
- QVariant
- CheckDirModel::data( const QModelIndex& index, int role ) const
- {
- #ifdef Q_WS_MAC
- // return the 'My Computer' icon for the /Volumes folder
- if ( index.column() == 0 && filePath( index ) == s_macVolumePath )
- {
- switch ( role )
- {
- case Qt::DecorationRole:
- return myComputer( role );
- default:
- break;
- }
- }
- #endif
- if ( role == Qt::CheckStateRole )
- {
- return m_checkTable.contains( index ) ? m_checkTable.value( index ) : Qt::Unchecked;
- }
- else
- {
- return QFileSystemModel::data( index, role );
- }
- }
- bool
- CheckDirModel::setData( const QModelIndex& index, const QVariant& value, int role )
- {
- bool b = QFileSystemModel::setData( index, value, role );
- if ( role == Qt::CheckStateRole )
- {
- m_checkTable.insert( index, (Qt::CheckState)value.toInt() );
- emit dataChanged( index, index );
- emit dataChangedByUser( index );
- }
- return b;
- }
- void
- CheckDirModel::setCheck( const QModelIndex& index, const QVariant& value )
- {
- QFileSystemModel::setData( index, value, Qt::CheckStateRole );
- m_checkTable.insert( index, (Qt::CheckState)value.toInt() );
- emit dataChanged( index, index );
- }
- Qt::CheckState
- CheckDirModel::getCheck( const QModelIndex& index )
- {
- return (Qt::CheckState)data( index, Qt::CheckStateRole ).toInt();
- }
- CheckDirTree::CheckDirTree( QWidget* parent )
- : QTreeView( parent )
- {
- m_dirModel.setFilter( QDir::Dirs | QDir::NoDotAndDotDot );
- m_dirModel.setRootPath( "/" );
- m_dirModel.setNameFilters( QStringList() << "[^\\.]*" );
- setModel( &m_dirModel );
- setColumnHidden( 1, true );
- setColumnHidden( 2, true );
- setColumnHidden( 3, true );
- //header()->hide();
- connect( &m_dirModel, SIGNAL( dataChangedByUser( QModelIndex ) ),
- SLOT( updateNode( QModelIndex ) ) );
- connect( &m_dirModel, SIGNAL( dataChangedByUser( const QModelIndex& ) ),
- SIGNAL( changed() ) );
- connect( &m_dirModel, SIGNAL( modelReset() ),
- SLOT( modelReset() ) );
- connect( this, SIGNAL( collapsed( QModelIndex ) ),
- SLOT( onCollapse( QModelIndex ) ) );
- connect( this, SIGNAL( expanded( QModelIndex ) ),
- SLOT( onExpand( QModelIndex ) ) );
- }
- void
- CheckDirTree::checkPath( const QString& path, Qt::CheckState state )
- {
- QModelIndex index = m_dirModel.index( path );
- m_dirModel.setCheck( index, state );
- updateNode( index );
- }
- void
- CheckDirTree::setExclusions( const QStringList& list )
- {
- foreach ( const QString& path, list )
- {
- checkPath( path, Qt::Unchecked );
- }
- }
- QStringList
- CheckDirTree::getCheckedPaths()
- {
- QStringList checks;
- QModelIndex root = rootIndex();
- getChecksForNode( root, checks );
- return checks;
- }
- void
- CheckDirTree::getChecksForNode( const QModelIndex& index, QStringList& checks )
- {
- // Look at first node
- // Is it checked?
- // - move on to next node
- // Is it unchecked?
- // - add to list
- // - move to next node
- // Is it partially checked?
- // - recurse
- int numChildren = m_dirModel.rowCount( index );
- for ( int i = 0; i < numChildren; ++i )
- {
- QModelIndex kid = m_dirModel.index( i, 0, index );
- Qt::CheckState check = m_dirModel.getCheck( kid );
- if ( check == Qt::Checked )
- {
- checks.append( m_dirModel.filePath( kid ) );
- }
- else if ( check == Qt::Unchecked )
- {
- continue;
- }
- else if ( check == Qt::PartiallyChecked )
- {
- getChecksForNode( kid, checks );
- }
- else
- {
- Q_ASSERT( false );
- }
- }
- }
- QStringList
- CheckDirTree::getExclusions()
- {
- QStringList exclusions;
- QModelIndex root = rootIndex();
- getExclusionsForNode( root, exclusions );
- return exclusions;
- }
- void
- CheckDirTree::getExclusionsForNode( const QModelIndex& index, QStringList& exclusions )
- {
- // Look at first node
- // Is it checked?
- // - move on to next node
- // Is it unchecked?
- // - add to list
- // - move to next node
- // Is it partially checked?
- // - recurse
- int numChildren = m_dirModel.rowCount( index );
- for ( int i = 0; i < numChildren; ++i )
- {
- QModelIndex kid = m_dirModel.index( i, 0, index );
- Qt::CheckState check = m_dirModel.getCheck( kid );
- if ( check == Qt::Checked )
- {
- continue;
- }
- else if ( check == Qt::Unchecked )
- {
- exclusions.append( m_dirModel.filePath( kid ) );
- }
- else if ( check == Qt::PartiallyChecked )
- {
- getExclusionsForNode( kid, exclusions );
- }
- else
- {
- Q_ASSERT( false );
- }
- }
- }
- void
- CheckDirTree::onCollapse( const QModelIndex& /*idx*/ )
- {
- }
- void
- CheckDirTree::onExpand( const QModelIndex& idx )
- {
- // If the node is partially checked, that means we have been below it
- // setting some stuff, so only fill down if we are unchecked.
- if ( m_dirModel.getCheck( idx ) != Qt::PartiallyChecked )
- {
- fillDown( idx );
- }
- }
- void
- CheckDirTree::updateNode( const QModelIndex& idx )
- {
- // Start by recursing down to the bottom and then work upwards
- fillDown( idx );
- updateParent( idx );
- }
- void
- CheckDirTree::modelReset()
- {
- foreach ( const QString& dir, TomahawkSettings::instance()->scannerPaths() )
- {
- checkPath( dir, Qt::Checked );
- }
- }
- void
- CheckDirTree::fillDown( const QModelIndex& parent )
- {
- // Recursion stops when we reach a directory which has never been expanded
- // or one that has no children.
- if ( !isExpanded( parent ) || !m_dirModel.hasChildren( parent ) )
- {
- return;
- }
- Qt::CheckState state = m_dirModel.getCheck( parent );
- int numChildren = m_dirModel.rowCount( parent );
- for ( int i = 0; i < numChildren; ++i )
- {
- QModelIndex kid = m_dirModel.index( i, 0, parent );
- m_dirModel.setCheck( kid, state );
- fillDown( kid );
- }
- }
- void
- CheckDirTree::updateParent( const QModelIndex& index )
- {
- QModelIndex parent = index.parent();
- if ( !parent.isValid() )
- {
- // We have reached the root
- return;
- }
- // Initialise overall state to state of first child
- QModelIndex kid = m_dirModel.index( 0, 0, parent );
- Qt::CheckState overall = m_dirModel.getCheck( kid );
- int numChildren = m_dirModel.rowCount( parent );
- for ( int i = 1; i <= numChildren; ++i )
- {
- kid = m_dirModel.index( i, 0, parent );
- Qt::CheckState state = m_dirModel.getCheck( kid );
- if ( state != overall )
- {
- // If we ever come across a state different than the first child,
- // we are partially checked
- overall = Qt::PartiallyChecked;
- break;
- }
- }
- m_dirModel.setCheck( parent, overall );
- updateParent( parent );
- }