Esempio n. 1
0
    def _create_filter_models( self ):
        #CREAR PROXY MODEL         


        self.proxymodel.setDynamicSortFilter( True )
        self.proxymodel.setFilterRole( Qt.EditRole )
        self.proxymodel.setFilterRegExp( "1" )
        self.proxymodel.setFilterKeyColumn( CONCILIADO )

#CREAR PROXY MODEL PARA VERIFICAR SI FUE GENERADO POR EL BANCO
        delbancoproxymodel = QSortFilterProxyModel( self )
        delbancoproxymodel.setSourceModel( self.proxymodel )
        delbancoproxymodel.setDynamicSortFilter( True )
        delbancoproxymodel.setFilterRole( Qt.EditRole )
        delbancoproxymodel.setFilterRegExp( "0" )
        delbancoproxymodel.setFilterKeyColumn( DELBANCO )

#CREAR PROXY MODEL PARA VERIFICAR SI FUE GENERADO  POR LA EMPRESA
        empresaproxymodel = QSortFilterProxyModel( self )
        empresaproxymodel.setSourceModel( self.proxymodel )
        empresaproxymodel.setDynamicSortFilter( True )
        empresaproxymodel.setFilterRole( Qt.EditRole )
        empresaproxymodel.setFilterRegExp( "1" )
        empresaproxymodel.setFilterKeyColumn( DELBANCO )

        filtroMenos = "^" + str( constantes.IDND ) + "$|^" + str( constantes.IDCHEQUE ) + "$|^" + str( constantes.IDERROR ) +"$|^" + str( constantes.IDERROR ) + "$"
        filtroMas = "[" + filtroMenos + "]"

#CREAR MODELO PARA DEPOSITOS
        self._setup_proxy_model(DetalleTableModel(self), empresaproxymodel, filtroMas, IDTIPODOC, self.tablalibromas)

#CREAR MODELO PARA CHEQUES
        self._setup_proxy_model(DetalleTableModel(self), empresaproxymodel, filtroMenos, IDTIPODOC, self.tablalibromenos)


#CREAR MODELO PARA NOTAS DE CREDITO
        self._setup_proxy_model(DetalleTableModel(self), delbancoproxymodel, filtroMas, IDTIPODOC, self.tablabancomas)

#CREAR MODELO PARA NOTAS DE DEBITO
        self._setup_proxy_model(DetalleTableModel(self), delbancoproxymodel, filtroMenos, IDTIPODOC, self.tablabancomenos)
Esempio n. 2
0
class FrmConciliacion( Base , Ui_frmConciliacion ):
    """
    Formulario para crear nuevas conciliaciones bancarias
    """
    def __init__( self , parent = None ):
        """
        Constructor
        """

        super( FrmConciliacion, self ).__init__( parent )

        self.user = parent.user
        
        self.editmodel = None

        self.status = True

#        las acciones deberian de estar ocultas
        self.actionSave.setVisible( False )
        self.actionCancel.setVisible( False )

#        El modelo principal
        self.navmodel = RONavigationModel( self )
#        El modelo que filtra a self.navmodel
        self.navproxymodel = QSortFilterProxyModel( self )
        self.navproxymodel.setFilterKeyColumn( -1 )
        self.navproxymodel.setSourceModel( self.navmodel )
        self.navproxymodel.setFilterCaseSensitivity ( Qt.CaseInsensitive )

#        Este es el modelo con los datos de la tabla para navegar
        self.detailsmodel = ReadOnlyTableModel( self )
        self.proxymodel = QSortFilterProxyModel( self )
#        CREAR TODOS LOS PROXY MODEL
        self._create_filter_models()

        self.detailsmodel.dataChanged[QModelIndex, QModelIndex].connect( self.updateLabels )


#        Cargar los modelos en un hilo aparte
        QTimer.singleShot( 0, self.loadModels )


    def _create_filter_models( self ):
        #CREAR PROXY MODEL         


        self.proxymodel.setDynamicSortFilter( True )
        self.proxymodel.setFilterRole( Qt.EditRole )
        self.proxymodel.setFilterRegExp( "1" )
        self.proxymodel.setFilterKeyColumn( CONCILIADO )

#CREAR PROXY MODEL PARA VERIFICAR SI FUE GENERADO POR EL BANCO
        delbancoproxymodel = QSortFilterProxyModel( self )
        delbancoproxymodel.setSourceModel( self.proxymodel )
        delbancoproxymodel.setDynamicSortFilter( True )
        delbancoproxymodel.setFilterRole( Qt.EditRole )
        delbancoproxymodel.setFilterRegExp( "0" )
        delbancoproxymodel.setFilterKeyColumn( DELBANCO )

#CREAR PROXY MODEL PARA VERIFICAR SI FUE GENERADO  POR LA EMPRESA
        empresaproxymodel = QSortFilterProxyModel( self )
        empresaproxymodel.setSourceModel( self.proxymodel )
        empresaproxymodel.setDynamicSortFilter( True )
        empresaproxymodel.setFilterRole( Qt.EditRole )
        empresaproxymodel.setFilterRegExp( "1" )
        empresaproxymodel.setFilterKeyColumn( DELBANCO )

        filtroMenos = "^" + str( constantes.IDND ) + "$|^" + str( constantes.IDCHEQUE ) + "$|^" + str( constantes.IDERROR ) +"$|^" + str( constantes.IDERROR ) + "$"
        filtroMas = "[" + filtroMenos + "]"

#CREAR MODELO PARA DEPOSITOS
        self._setup_proxy_model(DetalleTableModel(self), empresaproxymodel, filtroMas, IDTIPODOC, self.tablalibromas)

#CREAR MODELO PARA CHEQUES
        self._setup_proxy_model(DetalleTableModel(self), empresaproxymodel, filtroMenos, IDTIPODOC, self.tablalibromenos)


#CREAR MODELO PARA NOTAS DE CREDITO
        self._setup_proxy_model(DetalleTableModel(self), delbancoproxymodel, filtroMas, IDTIPODOC, self.tablabancomas)

#CREAR MODELO PARA NOTAS DE DEBITO
        self._setup_proxy_model(DetalleTableModel(self), delbancoproxymodel, filtroMenos, IDTIPODOC, self.tablabancomenos)

    def _setup_proxy_model(self, model, source, regexp, column, table, role = Qt.DisplayRole):
        model.setSourceModel( source )
        model.setFilterRegExp( regexp )
        model.setFilterKeyColumn( column )
        model.setFilterRole(role)
        table.setModel( model )
        

    def updateModels( self ):
        """
        Recargar todos los modelos
        """
        try:
            if not(QSqlDatabase.database().isOpen() or QSqlDatabase.database().open()):
                raise Exception( "No se pudo abrir la base" )

            self.navmodel.setQuery( """
            SELECT
                c.Fecha,
                b.descripcion as Banco,
                cb.ctabancaria,
                m.Simbolo,
                cc.Codigo,
                c.saldolibro,
                c.saldobanco,
                cb.idcuentacontable,
                c.iddocumento
                FROM conciliaciones c
                JOIN cuentasbancarias cb ON c.idcuentabancaria = cb.idcuentacontable
                JOIN bancos b ON b.idbanco = cb.idbanco
                JOIN tiposmoneda m ON m.idtipomoneda = cb.idtipomoneda
                JOIN cuentascontables cc ON cc.idcuenta = cb.idcuentacontable
                ORDER BY c.iddocumento
                ;
            """ )
#        Este objeto mapea una fila del modelo self.navproxymodel a los controles
            self.mapper.setSubmitPolicy( QDataWidgetMapper.ManualSubmit )
            self.mapper.setModel( self.navproxymodel )
            self.mapper.addMapping( self.txtbanco, BANCO )
            self.mapper.addMapping( self.txtmoneda, MONEDA )
            self.mapper.addMapping( self.txtcuentabanco, CUENTABANCO )
            self.mapper.addMapping( self.txtcuenta, CUENTA )


#        asignar los modelos a sus tablas
            self.tablenavigation.setModel( self.navproxymodel )
            self.tabledetails.setModel( self.detailsmodel )
            self.proxymodel.setSourceModel( self.detailsmodel )

            self.tablenavigation.setColumnHidden( SALDOBANCO, True )
            self.tablenavigation.setColumnHidden( SALDOLIBRO, True )
            self.tablenavigation.setColumnHidden( IDCUENTABANCO, True )
            self.tablenavigation.setColumnHidden( IDDOC, True )

            self._ocultar_columnas()

        except UserWarning as inst:
            logging.error( unicode( inst ) )
            QMessageBox.critical( self, qApp.organizationName(), unicode( inst ) )
        except Exception as inst:
            logging.critical( unicode( inst ) )
            QMessageBox.critical( self, qApp.organizationName(),
                u"Hubo un error al tratar de iniciar una nueva conciliación "\
                + "bancaria" )
        finally:
            if QSqlDatabase.database().isOpen():
                QSqlDatabase.database().close()

    def updateDetailFilter( self, _index ):
        if self.tabWidget.currentIndex() == 0:
            self.cargarMovimientos()

    def cargarMovimientos( self ):
        index = self.mapper.currentIndex()
        saldobanco = Decimal( self.navmodel.record( index ).value( "saldobanco" ).toString() )
        saldolibro = Decimal( self.navmodel.record( index ).value( "saldolibro" ).toString() )

        fecha = self.navmodel.record( index ).value( "fecha" ).toDate()
        self.lblfecha.setText( fecha.toString( "MMMM yyyy" ).upper() )
        ctaBanco = self.navmodel.record( index ).value( "idcuentacontable" ).toString()
        try:
            if not self.database.isOpen():
                if not self.database.open():
                    raise Exception( "No se pudo abrir la base" )
            self.detailsmodel.setQuery( "CALL spMovimientoCuenta(" + ctaBanco + "," + fecha.toString( "yyyyMMdd" ) + ");" )
            self.proxymodel.setSourceModel( self.detailsmodel )
        except Exception as inst:
            logging.error( unicode( inst ) )
        finally:
            if self.database.isOpen():
                self.database.close()
        self.tablenavigation.selectRow( self.mapper.currentIndex() )


        self.spbsaldobanco.setValue( saldobanco )
        self.txtsaldolibro.setText( moneyfmt( saldolibro, 4, "C$" ) )

        nc = self.tablabancomas.model().total
        nd = self.tablabancomenos.model().total
        depositos = self.tablalibromas.model().total
        cheques = self.tablalibromenos.model().total
        self.txtcheque.setText( moneyfmt( cheques, 4, "C$" ) )
        self.txtdeposito.setText( moneyfmt( depositos, 4, self.editmodel.moneda ) )
        self.txtnotacredito.setText( moneyfmt( nc, 4, self.editmodel.moneda ) )
        self.txtnotadebito.setText( moneyfmt( nd, 4, self.editmodel.moneda ) )

        self.txttotallibro.setText( moneyfmt( saldobanco + depositos + cheques, 4, self.editmodel.moneda ) )
        self.txttotalbanco.setText( moneyfmt( saldolibro + nc + nd , 4, self.editmodel.moneda ) )
        dif = saldobanco + depositos + cheques - ( saldolibro + nc + nd )
        self.lbldiferencia.setText( moneyfmt( dif, 4, self.editmodel.moneda ) if dif != 0 else "CONCILIADO" )

    def updateLabels( self ):
        self.txttotallibro.setText( moneyfmt( self.editmodel.total_libro, 4, self.editmodel.moneda ) )
        self.txtcheque.setText( moneyfmt( self.editmodel.total_cheques, 4, self.editmodel.moneda ) )
        self.txtdeposito.setText( moneyfmt( self.editmodel.total_depositos, 4, self.editmodel.moneda ) )
        self.txtnotacredito.setText( moneyfmt( self.editmodel.total_nota_credito, 4, self.editmodel.moneda ) )
        self.txtnotadebito.setText( moneyfmt( self.editmodel.total_nota_debito, 4, self.editmodel.moneda ) )

        self.txttotalbanco.setText( moneyfmt( self.editmodel.total_banco, 4, self.editmodel.moneda ) )

        dif = self.editmodel.diferencia
        self.lbldiferencia.setText( ( "Diferencia " + moneyfmt( dif, 4, self.editmodel.moneda ) ) if dif != 0 else "CONCILIADO" )



    @pyqtSlot( float )
    def on_spbsaldobanco_valueChanged ( self, value ):
        """
        Asignar el saldo inicial del banco al modelo
        """
        if not self.editmodel is None:
#            value = self.spbsaldobanco.value()           
            self.editmodel.saldo_inicial_banco = Decimal( str( value ) )
            self.updateLabels()

    @pyqtSlot(  )
    def on_btnAdd_clicked(self):
     
                
        if not self.database.isOpen():
            if not self.database.open():
                raise UserWarning( u"No se pudo establecer la conexión con "\
                                   + "la base de datos" )
        try:
            mov = dlgmovimientosbancarios(self)
#            Rellenar el combobox de las CONCEPTOS


            if mov.conceptosModel.rowCount() == 0:
                raise UserWarning( u"No existen conceptos en la base de "\
                                   + "datos que justifiquen la elaboración de Notas de Crédito o Débito" )
            
            mov.exec_()
        except UserWarning as inst:
            QMessageBox.critical( self, qApp.organizationName(), unicode( inst ) )
            logging.error( unicode( inst ) )
            logging.error( mov.conceptosModel.query().lastError().text() )
#        except Exception as inst:
#            QMessageBox.critical( self, qApp.organizationName(),
#                                   "Hubo un problema al tratar de crear"\
#                                   + " el nuevo pago" )
#            logging.critical( unicode( inst ) )
#            logging.error( query.lastError().text() )
        finally:
            if QSqlDatabase.database().isOpen():
                QSqlDatabase.database().close()


        
        #        notas = dlgMovimientosBancarios( self )
#        notas.setWindowModality( Qt.WindowModal )
#        if notas.exec_() == QDialog.Accepted:
#            row = self.editmodel.rowCount()
#
#            datosDoc = notas.editmodel.datos
#
#            linea = LineaConciliacion( self.editmodel )
#            linea.fecha = datosDoc.dateTime.toString( "dd/MM/yy" )
#            linea.monto = datosDoc.total
#            linea.idTipoDoc = datosDoc.idTipoDoc
#
#            linea.concepto = notas.editmodel.codigoDoc + " " + linea.fecha
#            linea.saldo = self.editmodel.lines[row - 1].saldo + linea.monto
#            linea.conciliado = 1
#            linea.delBanco = 1
#            linea.concepto2 = notas.editmodel.descripcionDoc + " " + linea.fecha
#            linea.idDoc = 0
#            linea.datos = datosDoc
#            self.editmodel.insertRows( row )
#            self.editmodel.lines[row] = linea
#            index = self.editmodel.index( row, CONCILIADO )
#            self.editmodel.dataChanged.emit( index, index )
        


    def setControls( self, status ):
        """
        En esta funcion cambio el estado enabled de todos los items en el formulario
        @param status: false = editando        true = navegando
        """
        self.actionPrint.setVisible( status )
        self.btnAdd.setVisible( not status )
        self.btnRemove.setVisible( not status )
        self.actionSave.setVisible( not status )
        self.actionCancel.setVisible( not status )
        self.tabnavigation.setEnabled( status )
        self.actionNew.setVisible( status )
        self.actionGoFirst.setVisible( status )
        self.actionGoPrevious.setVisible( status )
        self.actionGoNext.setVisible( status )
        self.actionGoLast.setVisible( status )
        self.actionPreview.setVisible( status )

        self.spbsaldobanco.setReadOnly( status )
#        self.tabledetails.setColumnHidden(DELBANCO,not status)
        if status:
            self.navigate( 'last' )
            self.tabledetails.setEditTriggers( QAbstractItemView.NoEditTriggers )
        else:
            self.tabledetails.setEditTriggers( QAbstractItemView.AllEditTriggers )
            self.spbsaldobanco.setValue( 0 )
            self.tabWidget.setCurrentIndex( 0 )

    def newDocument( self ):
        """
        Iniciar un nuevo documento
        """
        query = QSqlQuery()
        try:
            if not QSqlDatabase.database().isOpen() and not QSqlDatabase.database().open():
                raise UserWarning( u"No se pudo establecer una conexión "
                                   "con la base de datos" )

            dlgCuenta = dlgSelectCuenta( self )

            fila = -1
    #REPETIR MIENTRAS NO SELECCIONE UNA FILA
            while fila == -1:
                if dlgCuenta.exec_() == QDialog.Accepted:
                    fila = dlgCuenta.tblCuenta.selectionModel().currentIndex().row()
                    if fila == -1:
                        QMessageBox.information( self, qApp.organizationName(),
                                              "Por favor seleccione una cuenta" )
                else:
    #SALIR
                    return




    # SI SELECCIONO UNA FILA SIGUE
            self.editmodel = ConciliacionModel( 
                dlgCuenta.data['saldo_inicial_libro'],
                dlgCuenta.data['fecha'],
                dlgCuenta.data['banco'],
                dlgCuenta.data['cuenta_bancaria'],
                dlgCuenta.data['id_cuenta_contable'],
                dlgCuenta.data['codigo_cuenta_contable'],
                dlgCuenta.data['moneda']
            )

            self.txtbanco.setText( self.editmodel.banco )
            self.txtcuentabanco.setText( self.editmodel.cuenta_bancaria )
            self.txtmoneda.setText( self.editmodel.moneda )
            self.txtcuenta.setText( self.editmodel.codigo_cuenta_contable )
            self.lblfecha.setText( self.editmodel.datetime.toString( "MMMM yyyy" ).upper() )



            if not query.exec_( "CALL spMovimientoCuenta( %d, %s )" % ( 
                    self.editmodel.id_cuenta_contable,
                    self.editmodel.fecha_conciliacion.toString( "yyyyMMdd" )
                )
            ):
                raise Exception( query.lastError().text() )

            row = 0
            while query.next():
                linea = LineaConciliacion( 
                    query.value( 5 ).toBool(), #del_banco
                    Decimal( query.value( 3 ).toString() ), #saldo_inicial
                    Decimal( query.value( DEBE ).toString() ), #monto
                    QDate.fromString( query.value( FECHA ).toString(), 'dd/M/yy' ), #fecha
                    query.value( 6 ).toInt()[0], # tipo_doc
                    query.value( 8 ).toInt()[0], # id_documento
                    query.value( CONCEPTO ).toString() #descripcion
                )
                
                linea.monto = Decimal( query.value( 2 ).toString() )
                self.editmodel.insertRows( row )
                self.editmodel.lines[row] = linea
                row += 1

            #self.editmodel.saldoInicialLibro = self.editmodel.lines[row - 1].saldo
            self.txtsaldolibro.setText( moneyfmt( self.editmodel.saldo_inicial_libro, 4, self.editmodel.moneda ) )
            self.updateLabels()

            self.proxymodel.setSourceModel( self.editmodel )

            self.setControls( False )
            self.tabnavigation.setEnabled( False )
            self.tabWidget.setCurrentIndex( 0 )
            self.tabledetails.setModel( self.editmodel )

            self.tabledetails.resizeColumnsToContents()

            self._ocultar_columnas()

            self.editmodel.dataChanged[QModelIndex, QModelIndex].connect( self.updateLabels )

        except UserWarning as inst:
            logging.error( unicode( inst ) )
            QMessageBox.critical( self, qApp.organizationName(),
                                   unicode( inst ) )
        except Exception as inst:
            logging.critical( unicode( inst ) )
            QMessageBox.critical( self, qApp.organizationName(),
                                   u"Hubo un error al intentar iniciar una"
                                   + u" nueva conciliación" )
        finally:
            if self.database.isOpen():
                self.database.close()

    def _ocultar_columnas( self ):
        for table in ( self.tablabancomas, self.tablalibromas, self.tablabancomenos, self.tablalibromenos):
            table.setColumnHidden( HABER, True )
            table.setColumnHidden( CONCILIADO, True )
            table.setColumnHidden( SALDO, True )
            table.setColumnHidden( IDTIPODOC, True )
            table.setColumnHidden( DELBANCO, True )

        self.tabledetails.setColumnHidden( IDTIPODOC, True )



    def save( self ):
        """
        Guardar el documento actual
        """
        if not self.valid:
            return None

        if QMessageBox.question( self,
                                 qApp.organizationName(),
                                  u"¿Desea guardar el documento?",
                                   QMessageBox.Yes | QMessageBox.No ) == QMessageBox.Yes:
            if self.editmodel.save():
                QMessageBox.information( self,
                                         qApp.organizationName(),
                     u"El documento se ha guardado con éxito" )
                self.editmodel = None
                self.updateModels()
                self.navigate( 'last' )
                self.status = True
            else:
                QMessageBox.critical( self,
                     qApp.organizationName(),
                    "Ha ocurrido un error al guardar el documento" )




    def cancel( self ):
        self.editmodel = None
        self.tablenavigation.setModel( self.navproxymodel )
        self.tabledetails.setModel( self.detailsmodel )
        self.proxymodel.setSourceModel( self.detailsmodel )
        self._ocultar_columnas()
        self.status = True


    @pyqtSlot( bool )
    @if_edit_model
    def on_btnremove_clicked( self, _checked ):

        filas = []
        for index in self.tabledetails.selectedIndexes():
            pos = index.row()
            if pos > 0 and  not  pos in filas and self.editmodel.lines[pos].idDoc == 0:
                filas.append( pos )

        if len( filas ) > 0:
            filas.sort( None, None, True )
            for pos in filas:
                self.editmodel.removeRows( pos )

            self.updateLabels()
Esempio n. 3
0
class CurrentPlaylistForm(QWidget, auxilia.Actions, CurrentListForm):
    '''List and controls for the currently loaded playlist'''
    editing = 0
    def __init__(self, modelManager, view, app, config):
        QWidget.__init__(self)
        self.app = app
        self.view = view
        self.config = config
        self._temp = {}
        self.playQueue = modelManager.playQueue
        self.playerState = modelManager.playerState
        self.modelManager = modelManager
        self.playQueueDelegate = PlayQueueDelegate(self.config)
        self.setupUi(self)

        self.connect(self.playerState, SIGNAL('repeatChanged'), self.repeatButton.setChecked)
        self.connect(self.playerState, SIGNAL('randomChanged'), self.randomButton.setChecked)
        self.connect(self.playerState, SIGNAL('xFadeChanged'), self.crossFade.setValue)
        self.connect(self.crossFade, SIGNAL('valueChanged(int)'), self.playerState.setXFade)
        self.connect(self.repeatButton, SIGNAL('toggled(bool)'), self.playerState.setRepeat)
        self.connect(self.randomButton, SIGNAL('toggled(bool)'), self.playerState.setRandom)

        self.playQueueProxy = QSortFilterProxyModel()
        self.playQueueProxy.setSourceModel(self.playQueue)
        self.playQueueProxy.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.playQueueProxy.setDynamicSortFilter(True)
        self.playQueueProxy.setFilterRole(Qt.AccessibleTextRole)
        self.currentList.setModel(self.playQueueProxy)
        self.currentList.setItemDelegateForColumn(0, self.playQueueDelegate)
        self.currentList.horizontalHeader().setResizeMode(1)

        if config.oneLinePlaylist:
            self.oneLinePlaylist.setChecked(True)
        self.keepPlayingVisible.setChecked(self.config.keepPlayingVisible)
        self._togglePlaylistTools(self.config.playlistControls)
        self.connect(self.playQueue, SIGNAL('aboutToUpdate'), self.prepareForUpdate)
        self.connect(self.playQueue, SIGNAL('updated'), self.updated)
        self.connect(self.playQueue, SIGNAL('currentSongChanged'), self._ensurePlayingVisable)


        # Connect to the view for double click action.
        self.connect(self.currentList, SIGNAL('doubleClicked(const QModelIndex &)'), self._playSong)

        self.connect(self.currentFilter,SIGNAL('textEdited(QString)'),self.playQueueProxy.setFilterFixedString)

        self.connect(self.currentRemove,SIGNAL('clicked()'),self._removeSelected)
        self.connect(self.currentClear,SIGNAL('clicked()'),self.playQueue.clear)
        self.connect(self.currentSave,SIGNAL('clicked()'),self._saveCurrent)
        self.connect(self.addStream,SIGNAL('clicked()'),self._addStream)

        self.connect(self.currentBottom, SIGNAL('clicked()'), self._togglePlaylistTools)
        self.connect(self.currentList,SIGNAL('selectionChanged()'),self._setEditing)
        self.connect(self.currentList.verticalScrollBar(), SIGNAL('valueChanged(int)'), self._setEditing)
        self.connect(self.keepPlayingVisible,SIGNAL('toggled(bool)'),self._toggleKeepPlayingVisible)
        self.connect(self.oneLinePlaylist,SIGNAL('toggled(bool)'),self._setOneLinePlaylist)
        self.connect(self.showNumbers,SIGNAL('toggled(bool)'),self._setNumbers)
        self.showNumbers.setChecked(self.config.showNumbers)

        # Menu for current playlist.
        # Create actions.
        self.currentMenuPlay = self.action(self.currentList, self._playSong,
                icon="media-playback-start", text='play', tooltip='Start playing the selected song.')
        self.currentMenuRemove = self.action(self.currentList, self._removeSelected,
                icon="list-remove", text='Remove', tooltip="Remove the selected songs from the playlist.")
        self.currentMenuClear = self.action(self.currentList, self.playQueue.clear,
                icon="document-new", text='Clear', tooltip="Remove all songs from the playlist.")
        self.currentMenuSave = self.action(self.currentList, self._saveCurrent,
                icon="document-save-as", text='Save', tooltip="Save the current playlist.")
        self.currentMenuCrop = self.action(self.currentList, self._cropCurrent,
                icon="project-development-close", text='Crop', tooltip="Remove all but the selected songs.")
        self.currentMenuShuffle = self.action(self.currentList, self.playQueue.shuffle,
                icon="media-playlist-shuffle", text='Shuffle', tooltip="Shuffle the songs in the playlist.")

        # Set the Off icon for the repeat and random buttons.
        icon = self.randomButton.icon()
        icon.addPixmap(
                icon.pixmap(32,32,QIcon.Normal),
                QIcon.Normal,
                QIcon.On)
        icon.addPixmap(
                icon.pixmap(32,32,QIcon.Disabled),
                QIcon.Normal,
                QIcon.Off)
        self.randomButton.setIcon(icon)
        icon = self.repeatButton.icon()
        icon.addPixmap(
                icon.pixmap(32,32,QIcon.Normal),
                QIcon.Normal,
                QIcon.On)
        icon.addPixmap(
                icon.pixmap(32,32,QIcon.Disabled),
                QIcon.Normal,
                QIcon.Off)
        self.repeatButton.setIcon(icon)

    def prepareForUpdate(self):
        '''Save some state prior to applying changes to the play queue.'''
        self._temp['oldLength'] = len(self.playQueue)
        scrollBar = self.currentList.verticalScrollBar()
        oldScroll = scrollBar.value()
        self._temp['setBottom'] = oldScroll == scrollBar.maximum()
        self._temp['oldScroll'] = oldScroll

    def updated(self):
        self._setEditing()
        self.view.numSongsLabel.setText(str(len(self.playQueue))+' Songs')
        self._setPlayTime(self.playQueue.totalTime())
        self._resize()
        self.app.processEvents()
        scrollBar = self.currentList.verticalScrollBar()
        if self._temp.get('oldLength') == 0:
            self._ensurePlayingVisable(force=True)
        elif self._temp.get('setBottom'):
            scrollBar.setValue(scrollBar.maximum())
        else:
            scrollBar.setValue(self._temp.get('oldScroll', 0))
        try:
            del self._temp['oldLength']
            del self._temp['setBottom']
            del self._temp['oldScroll']
        except KeyError:
            pass

    def keyPressEvent(self, event):
        if event.matches(QKeySequence.Delete):
            self._removeSelected()
        elif event.key() == Qt.Key_Escape:
            self.currentList.reset()
        else:
            QListView.keyPressEvent(self.currentList, event)

    def _getSelectedRows(self):
        return (self.playQueueProxy.mapToSource(index).row() for index in self.currentList.selectedIndexes())

    def _ensurePlayingVisable(self, force=False):
        if time() - self.playQueue.lastEdit <= 5 and not force == True:
            return
        if self.playQueue.playing is None:
            return
        playing = self.playQueue.id_index(self.playQueue.playing)
        if self.currentList.isRowHidden(playing):
            return
        playing = self.playQueueProxy.mapFromSource(self.playQueue.createIndex(playing, 0))
        self.currentList.scrollTo(playing, 1) # PositionAtTop
        height = self.currentList.viewport().height()
        scrollBar = self.currentList.verticalScrollBar()
        correction = (height / 8) - self.currentList.rowViewportPosition(playing.row())
        new_pos = scrollBar.value() - correction
        scrollBar.setValue(new_pos)

    def _saveCurrent(self):
        '''Save the current playlist'''
        playlistModel = self.modelManager.playlists
        (name, ok) = QInputDialog.getItem(self,
                'Save Playlist',
                'Enter or select the playlist name',
                [name for name in playlistModel],
                0,
                True)
        if ok == True:
            playlistModel.saveCurrent(name)

    def _removeSelected(self):
        '''Remove the selected item(s) from the current playlist'''
        self._removeSongs(self._getSelectedRows())
        self.currentList.reset()

    def _cropCurrent(self):
        selection = set(self._getSelectedRows())
        rows = set(xrange(len(self.playQueue)))
        self._removeSongs(list(rows - selection))

    def _removeSongs(self, rowList):
        start = rowList.next()
        end = start + 1
        for row in rowList:
            if row != end:
                del self.playQueue[start:end]
                start = row
            end = row + 1
        del self.playQueue[start:end]

    def _playSong(self, index=None):
        try:
            row = self._getSelectedRows().next()
        except StopIteration:
            return
        self.playerState.currentSong = row
        self.playerState.play()


    def _setPlayTime(self, playTime=0):
        self.view.playTimeLabel.setText('Total play time: %s' % mpdlibrary.Time(playTime).human)

    def _setNumbers(self, value):
        self.config.showNumbers = value
        self.currentList.verticalHeader().setVisible(value)

    def _toggleKeepPlayingVisible(self, value):
        self.config.keepPlayingVisible = value
        if value:
            self._ensurePlayingVisable(force=True)

    def _setOneLinePlaylist(self, value):
        self.config.oneLinePlaylist = value
        self.playQueueDelegate.setOneLine(value)
        self._resize()

    def _resize(self):
        metrics = QFontMetrics(QFont())
        length = 0
        for song in self.playQueue:
            artist = metrics.width(song.artist)
            title = metrics.width(song.title)
            if self.config.oneLinePlaylist:
                length = max(artist + title, length)
            else:
                length = max(artist, title, length)
        width = length + self.playQueueDelegate.height + 4
        header = self.currentList.horizontalHeader()
        header.setMinimumSectionSize(width)
        self.currentList.verticalHeader().setDefaultSectionSize(self.playQueueDelegate.height)

    def _togglePlaylistTools(self, value=None):
        text = ('Show Playlist Tools', 'Hide Playlist Tools')
        if value == None:
            value = not self.playlistTools.isVisible()
        scrollBar = self.currentList.verticalScrollBar()
        scrollValue = scrollBar.value()
        scrollMax = scrollBar.maximum()
        self.playlistTools.setVisible(value)
        self.currentBottom.setArrowType(int(value)+1)
        self.currentBottom.setText(text[value])
        self.config.playlistControls = bool(self.playlistTools.isVisible())
        if scrollValue == scrollMax:
            scrollBar.setValue(scrollBar.maximum())

    def _addStream(self):
        '''Ask the user for the url of the stream to add.'''
        (url,ok) = QInputDialog.getText(self
                , 'Add Stream'
                , 'Please enter the url of the stream you like to add to the playlist.'
                , 0
                , 'Add Stream')
        url = str(url)
        if ok == True and url:
            try:
                streamList = streamTools.getStreamList(url)
            except streamTools.ParseError:
                print 'error: Could not parse stream address.'
                return
            self.playQueue.extend(streamList)

    def _setEditing(self):
        self.playQueue.lastEdit = time()