You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/kompare/libdiff2/komparemodellist.cpp

1422 lines
41 KiB

/***************************************************************************
komparemodellist.cpp - description
-------------------
begin : Tue Jun 26 2001
copyright : (C) 2001-2004 Otto Bruggeman
(C) 2001-2003 John Firebaugh
(C) 2007 Kevin Kofler
email : jfirebaugh@kde.org
otto.bruggeman@home.nl
kevin.kofler@chello.at
***************************************************************************/
/***************************************************************************
* *
* 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 <tqfile.h>
#include <tqdir.h>
#include <tqregexp.h>
#include <tqtextcodec.h>
#include <tqvaluelist.h>
#include <tdeaction.h>
#include <kcharsets.h>
#include <kdebug.h>
#include <kdirwatch.h>
#include <tdeio/netaccess.h>
#include <tdelocale.h>
#include <kmimetype.h>
#include <tdetempfile.h>
#include "difference.h"
#include "diffhunk.h"
#include "diffmodel.h"
#include "diffmodellist.h"
#include "kompareprocess.h"
#include "komparemodellist.h"
#include "parser.h"
#include "kompare_part.h"
using namespace Diff2;
KompareModelList::KompareModelList( DiffSettings* diffSettings, struct Kompare::Info& info, TQObject* parent, const char* name )
: TQObject( parent, name ),
m_diffProcess( 0 ),
m_diffSettings( diffSettings ),
m_models( 0 ),
m_selectedModel( 0 ),
m_selectedDifference( 0 ),
m_noOfModified( 0 ),
m_modelIndex( 0 ),
m_info( info ),
m_textCodec( 0 )
{
m_applyDifference = new TDEAction( i18n("&Apply Difference"), "1rightarrow", TQt::Key_Space,
this, TQT_SLOT(slotActionApplyDifference()),
(( KomparePart* )parent)->actionCollection(), "difference_apply" );
m_unApplyDifference = new TDEAction( i18n("Un&apply Difference"), "1leftarrow", TQt::Key_BackSpace,
this, TQT_SLOT(slotActionUnApplyDifference()),
(( KomparePart* )parent)->actionCollection(), "difference_unapply" );
m_applyAll = new TDEAction( i18n("App&ly All"), "2rightarrow", TQt::CTRL + TQt::Key_A,
this, TQT_SLOT(slotActionApplyAllDifferences()),
(( KomparePart* )parent)->actionCollection(), "difference_applyall" );
m_unapplyAll = new TDEAction( i18n("&Unapply All"), "2leftarrow", TQt::CTRL + TQt::Key_U,
this, TQT_SLOT(slotActionUnapplyAllDifferences()),
(( KomparePart* )parent)->actionCollection(), "difference_unapplyall" );
m_previousFile = new TDEAction( i18n("P&revious File"), "2uparrow", TQt::CTRL + TQt::Key_PageUp,
this, TQT_SLOT(slotPreviousModel()),
(( KomparePart* )parent)->actionCollection(), "difference_previousfile" );
m_nextFile = new TDEAction( i18n("N&ext File"), "2downarrow", TQt::CTRL + TQt::Key_PageDown,
this, TQT_SLOT(slotNextModel()),
(( KomparePart* )parent)->actionCollection(), "difference_nextfile" );
m_previousDifference = new TDEAction( i18n("&Previous Difference"), "1uparrow", TQt::CTRL + TQt::Key_Up,
this, TQT_SLOT(slotPreviousDifference()),
(( KomparePart* )parent)->actionCollection(), "difference_previous" );
m_nextDifference = new TDEAction( i18n("&Next Difference"), "1downarrow", TQt::CTRL + TQt::Key_Down,
this, TQT_SLOT(slotNextDifference()),
(( KomparePart* )parent)->actionCollection(), "difference_next" );
m_previousDifference->setEnabled( false );
m_nextDifference->setEnabled( false );
m_save = KStdAction::save( this, TQT_SLOT(slotSaveDestination()), ((KomparePart*)parent)->actionCollection() );
m_save->setEnabled( false );
updateModelListActions();
}
KompareModelList::~KompareModelList()
{
}
bool KompareModelList::isDirectory( const TQString& url ) const
{
TQFileInfo fi( url );
if ( fi.isDir() )
return true;
else
return false;
}
bool KompareModelList::isDiff( const TQString& mimeType ) const
{
if ( mimeType == "text/x-diff" )
return true;
else
return false;
}
bool KompareModelList::compare( const TQString& source, const TQString& destination )
{
bool result = false;
bool sourceIsDirectory = isDirectory( source );
bool destinationIsDirectory = isDirectory( source );
if ( sourceIsDirectory && destinationIsDirectory )
{
m_info.mode = Kompare::ComparingDirs;
result = compareDirs( source, destination );
}
else if ( !sourceIsDirectory && !destinationIsDirectory )
{
TQFile sourceFile( source );
sourceFile.open( IO_ReadOnly );
TQString sourceMimeType = ( KMimeType::findByContent( sourceFile.readAll() ) )->name();
sourceFile.close();
kdDebug(8101) << "Mimetype source : " << sourceMimeType << endl;
TQFile destinationFile( destination );
destinationFile.open( IO_ReadOnly );
TQString destinationMimeType = ( KMimeType::findByContent( destinationFile.readAll() ) )->name();
destinationFile.close();
kdDebug(8101) << "Mimetype destination: " << destinationMimeType << endl;
// Not checking if it is a text file/something diff can even compare, we'll let diff handle that
if ( !isDiff( sourceMimeType ) && isDiff( destinationMimeType ) )
{
kdDebug(8101) << "Blending destination into source..." << endl;
m_info.mode = Kompare::BlendingFile;
result = openFileAndDiff( source, destination );
}
else if ( isDiff( sourceMimeType ) && !isDiff( destinationMimeType ) )
{
kdDebug(8101) << "Blending source into destination..." << endl;
m_info.mode = Kompare::BlendingFile;
result = openFileAndDiff( destination, source );
}
else
{
kdDebug(8101) << "Comparing source with destination" << endl;
m_info.mode = Kompare::ComparingFiles;
result = compareFiles( source, destination );
}
}
else if ( sourceIsDirectory && !destinationIsDirectory )
{
m_info.mode = Kompare::BlendingDir;
result = openDirAndDiff( source, destination );
}
else
{
m_info.mode = Kompare::BlendingDir;
result = openDirAndDiff( destination, source );
}
return result;
}
bool KompareModelList::compareFiles( const TQString& source, const TQString& destination )
{
m_source = source;
m_destination = destination;
clear(); // Destroy the old models...
// m_fileWatch = new KDirWatch( this, "filewatch" );
// m_fileWatch->addFile( m_source );
// m_fileWatch->addFile( m_destination );
// connect( m_fileWatch, TQT_SIGNAL( dirty( const TQString& ) ), this, TQT_SLOT( slotFileChanged( const TQString& ) ) );
// connect( m_fileWatch, TQT_SIGNAL( created( const TQString& ) ), this, TQT_SLOT( slotFileChanged( const TQString& ) ) );
// connect( m_fileWatch, TQT_SIGNAL( deleted( const TQString& ) ), this, TQT_SLOT( slotFileChanged( const TQString& ) ) );
// m_fileWatch->startScan();
m_diffProcess = new KompareProcess( m_diffSettings, Kompare::Custom, m_source, m_destination );
m_diffProcess->setEncoding( m_encoding );
connect( m_diffProcess, TQT_SIGNAL(diffHasFinished( bool )),
this, TQT_SLOT(slotDiffProcessFinished( bool )) );
emit status( Kompare::RunningDiff );
m_diffProcess->start();
return true;
}
bool KompareModelList::compareDirs( const TQString& source, const TQString& destination )
{
m_source = source;
m_destination = destination;
clear(); // Destroy the old models...
// m_dirWatch = new KDirWatch( this, "dirwatch" );
// Watch files in the dirs and watch the dirs recursively
// m_dirWatch->addDir( m_source, true, true );
// m_dirWatch->addDir( m_destination, true, true );
// connect( m_dirWatch, TQT_SIGNAL( dirty ( const TQString& ) ), this, TQT_SLOT( slotDirectoryChanged( const TQString& ) ) );
// connect( m_dirWatch, TQT_SIGNAL( created( const TQString& ) ), this, TQT_SLOT( slotDirectoryChanged( const TQString& ) ) );
// connect( m_dirWatch, TQT_SIGNAL( deleted( const TQString& ) ), this, TQT_SLOT( slotDirectoryChanged( const TQString& ) ) );
// m_dirWatch->startScan();
m_diffProcess = new KompareProcess( m_diffSettings, Kompare::Custom, m_source, m_destination );
m_diffProcess->setEncoding( m_encoding );
connect( m_diffProcess, TQT_SIGNAL(diffHasFinished( bool )),
this, TQT_SLOT(slotDiffProcessFinished( bool )) );
emit status( Kompare::RunningDiff );
m_diffProcess->start();
return true;
}
bool KompareModelList::openFileAndDiff( const TQString& file, const TQString& diff )
{
clear();
if ( parseDiffOutput( readFile( diff ) ) != 0 )
{
emit error( i18n( "<qt>No models or no differences, this file: <b>%1</b>, is not a valid diff file.</qt>" ).arg( diff ) );
return false;
}
// Do our thing :)
if ( !blendOriginalIntoModelList( file ) )
{
kdDebug(8101) << "Oops cant blend original file into modellist : " << file << endl;
emit( i18n( "<qt>There were problems applying the diff <b>%1</b> to the file <b>%2</b>.</qt>" ).arg( diff ).arg( file ) );
return false;
}
updateModelListActions();
show();
return true;
}
bool KompareModelList::openDirAndDiff( const TQString& dir, const TQString& diff )
{
clear();
if ( parseDiffOutput( readFile( diff ) ) != 0 )
{
emit error( i18n( "<qt>No models or no differences, this file: <b>%1</b>, is not a valid diff file.</qt>" ).arg( diff ) );
return false;
}
// Do our thing :)
if ( !blendOriginalIntoModelList( dir ) )
{
// Trouble blending the original into the model
kdDebug(8101) << "Oops cant blend original dir into modellist : " << dir << endl;
emit error( i18n( "<qt>There were problems applying the diff <b>%1</b> to the folder <b>%2</b>.</qt>" ).arg( diff ).arg( dir ) );
return false;
}
updateModelListActions();
show();
return true;
}
void KompareModelList::slotSaveDestination()
{
if ( m_selectedModel )
{
saveDestination( m_selectedModel );
}
}
bool KompareModelList::saveDestination( DiffModel* model )
{
kdDebug() << "KompareModelList::saveDestination: " << endl;
if( !model->isModified() )
return true;
KTempFile* temp = new KTempFile();
if( temp->status() != 0 ) {
emit error( i18n( "Could not open a temporary file." ) );
temp->unlink();
delete temp;
return false;
}
TQTextStream* stream = temp->textStream();
TQStringList list;
DiffHunkListConstIterator hunkIt = model->hunks()->begin();
DiffHunkListConstIterator hEnd = model->hunks()->end();
for( ; hunkIt != hEnd; ++hunkIt )
{
DiffHunk* hunk = *hunkIt;
DifferenceListConstIterator diffIt = hunk->differences().begin();
DifferenceListConstIterator dEnd = hunk->differences().end();
Difference* diff;
for( ; diffIt != dEnd; ++diffIt )
{
diff = *diffIt;
if( !diff->applied() )
{
DifferenceStringListConstIterator stringIt = diff->destinationLines().begin();
DifferenceStringListConstIterator sEnd = diff->destinationLines().end();
for ( ; stringIt != sEnd; ++stringIt )
{
list.append( ( *stringIt )->string() );
}
}
else
{
DifferenceStringListConstIterator stringIt = diff->sourceLines().begin();
DifferenceStringListConstIterator sEnd = diff->sourceLines().end();
for ( ; stringIt != sEnd; ++stringIt )
{
list.append( ( *stringIt )->string() );
}
}
}
}
// kdDebug( 8101 ) << "Everything: " << endl << list.join( "\n" ) << endl;
if( list.count() > 0 )
*stream << list.join( "" );
temp->close();
if( temp->status() != 0 ) {
emit error( i18n( "<qt>Could not write to the temporary file <b>%1</b>, deleting it.</qt>" ).arg( temp->name() ) );
temp->unlink();
delete temp;
return false;
}
bool result = false;
if ( m_info.mode == Kompare::ComparingDirs )
{
TQString destination = model->destinationPath() + model->destinationFile();
kdDebug(8101) << "Tempfilename : " << temp->name() << endl;
kdDebug(8101) << "DestinationURL : " << destination << endl;
TDEIO::UDSEntry entry;
if ( !TDEIO::NetAccess::stat( KURL( destination ).path(), entry, (TQWidget*)parent() ) )
{
if ( !TDEIO::NetAccess::mkdir( KURL( destination ).path(), (TQWidget*)parent() ) )
{
emit error( i18n( "<qt>Could not create destination directory <b>%1</b>.\nThe file has not been saved.</qt>" ) );
return false;
}
}
result = TDEIO::NetAccess::upload( temp->name(), KURL( destination ), (TQWidget*)parent() );
}
else
{
kdDebug(8101) << "Tempfilename : " << temp->name() << endl;
kdDebug(8101) << "DestinationURL : " << m_destination << endl;
result = TDEIO::NetAccess::upload( temp->name(), KURL( m_destination ), (TQWidget*)parent() );
}
if ( !result )
{
emit error( i18n( "<qt>Could not upload the temporary file to the destination location <b>%1</b>. The temporary file is still available under: <b>%2</b>. You can manually copy it to the right place.</qt>" ).arg( m_destination ).arg( temp->name() ) );
}
else
{
//model->slotSetModified( false );
temp->unlink();
delete temp;
}
return true;
}
bool KompareModelList::saveAll()
{
if ( !m_models )
return false;
DiffModelListIterator it = m_models->begin();
DiffModelListIterator end = m_models->end();
for ( ; it != end; ++it )
{
if( !saveDestination( *it ) )
return false;
}
return true;
}
void KompareModelList::setEncoding( const TQString& encoding )
{
m_encoding = encoding;
if ( encoding.lower() == "default" )
{
m_textCodec = TQTextCodec::codecForLocale();
}
else
{
kdDebug() << "Encoding : " << encoding << endl;
m_textCodec = TDEGlobal::charsets()->codecForName( encoding.latin1() );
kdDebug() << "TextCodec: " << m_textCodec << endl;
if ( !m_textCodec )
m_textCodec = TQTextCodec::codecForLocale();
}
kdDebug() << "TextCodec: " << m_textCodec << endl;
}
void KompareModelList::slotDiffProcessFinished( bool success )
{
if ( success )
{
emit status( Kompare::Parsing );
if ( parseDiffOutput( m_diffProcess->diffOutput() ) != 0 )
{
emit error( i18n( "Could not parse diff output." ) );
}
else
{
if ( m_info.mode != Kompare::ShowingDiff )
{
kdDebug() << "Blend this crap please and dont gimme any conflicts..." << endl;
blendOriginalIntoModelList( m_info.localSource );
}
updateModelListActions();
show();
}
emit status( Kompare::FinishedParsing );
}
else if ( m_diffProcess->exitStatus() == 0 )
{
emit error( i18n( "The files are identical." ) );
}
else
{
emit error( m_diffProcess->stdErr() );
}
delete m_diffProcess;
m_diffProcess = 0;
}
void KompareModelList::slotDirectoryChanged( const TQString& /*dir*/ )
{
// some debug output to see if watching works properly
kdDebug(8101) << "Yippie directories are being watched !!! :)" << endl;
if ( m_diffProcess )
{
emit status( Kompare::ReRunningDiff );
m_diffProcess->start();
}
}
void KompareModelList::slotFileChanged( const TQString& /*file*/ )
{
// some debug output to see if watching works properly
kdDebug(8101) << "Yippie files are being watched !!! :)" << endl;
if ( m_diffProcess )
{
emit status( Kompare::ReRunningDiff );
m_diffProcess->start();
}
}
TQStringList KompareModelList::split( const TQString& fileContents )
{
TQString contents = fileContents;
TQStringList list;
int pos = 0;
unsigned int oldpos = 0;
// split that does not strip the split char
#ifdef TQT_OS_MAC
const char split = '\r';
#else
const char split = '\n';
#endif
while ( ( pos = contents.find( split, oldpos ) ) >= 0 )
{
list.append( contents.mid( oldpos, pos - oldpos + 1 ) );
oldpos = pos + 1;
}
if ( contents.length() > oldpos )
{
list.append( contents.right( contents.length() - oldpos ) );
}
return list;
}
TQString KompareModelList::readFile( const TQString& fileName )
{
TQStringList list;
TQFile file( fileName );
file.open( IO_ReadOnly );
TQTextStream stream( &file );
kdDebug() << "Codec = " << m_textCodec << endl;
if ( !m_textCodec )
m_textCodec = TQTextCodec::codecForLocale();
stream.setCodec( m_textCodec );
TQString contents = stream.read();
file.close();
return contents;
}
bool KompareModelList::openDiff( const TQString& diffFile )
{
kdDebug(8101) << "Stupid :) Url = " << diffFile << endl;
if ( diffFile.isEmpty() )
return false;
TQString diff = readFile( diffFile );
clear(); // Clear the current models
emit status( Kompare::Parsing );
if ( parseDiffOutput( diff ) != 0 )
{
emit error( i18n( "Could not parse diff output." ) );
return false;
}
updateModelListActions();
show();
emit status( Kompare::FinishedParsing );
return true;
}
TQString KompareModelList::recreateDiff() const
{
TQString diff;
DiffModelListConstIterator modelIt = m_models->begin();
DiffModelListConstIterator mEnd = m_models->end();
for ( ; modelIt != mEnd; ++modelIt )
{
diff += (*modelIt)->recreateDiff();
}
return diff;
}
bool KompareModelList::saveDiff( const TQString& url, TQString directory, DiffSettings* diffSettings )
{
kdDebug() << "KompareModelList::saveDiff: " << endl;
m_diffTemp = new KTempFile();
m_diffURL = url;
if( m_diffTemp->status() != 0 ) {
emit error( i18n( "Could not open a temporary file." ) );
m_diffTemp->unlink();
delete m_diffTemp;
m_diffTemp = 0;
return false;
}
m_diffProcess = new KompareProcess( diffSettings, Kompare::Custom, m_source, m_destination, directory );
m_diffProcess->setEncoding( m_encoding );
connect( m_diffProcess, TQT_SIGNAL(diffHasFinished( bool )),
this, TQT_SLOT(slotWriteDiffOutput( bool )) );
emit status( Kompare::RunningDiff );
return m_diffProcess->start();
}
void KompareModelList::slotWriteDiffOutput( bool success )
{
kdDebug(8101) << "Success = " << success << endl;
if( success )
{
TQTextStream* stream = m_diffTemp->textStream();
*stream << m_diffProcess->diffOutput();
m_diffTemp->close();
if( m_diffTemp->status() != 0 )
{
emit error( i18n( "Could not write to the temporary file." ) );
}
TDEIO::NetAccess::upload( m_diffTemp->name(), KURL( m_diffURL ), (TQWidget*)parent() );
emit status( Kompare::FinishedWritingDiff );
}
m_diffURL.truncate( 0 );
m_diffTemp->unlink();
delete m_diffTemp;
m_diffTemp = 0;
delete m_diffProcess;
m_diffProcess = 0;
}
void KompareModelList::slotSelectionChanged( const Diff2::DiffModel* model, const Diff2::Difference* diff )
{
// This method will signal all the other objects about a change in selection,
// it will emit setSelection( const DiffModel*, const Difference* ) to all who are connected
kdDebug(8101) << "KompareModelList::slotSelectionChanged( " << model << ", " << diff << " )" << endl;
kdDebug(8101) << "Sender is : " << sender()->className() << endl;
// kdDebug(8101) << kdBacktrace() << endl;
m_selectedModel = const_cast<DiffModel*>(model);
m_modelIndex = m_models->findIndex( m_selectedModel );
kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
m_selectedDifference = const_cast<Difference*>(diff);
m_selectedModel->setSelectedDifference( m_selectedDifference );
// setSelected* search for the argument in the lists and return false if not found
// if found they return true and set the m_selected*
if ( !setSelectedModel( m_selectedModel ) )
{
// Backup plan
m_selectedModel = firstModel();
m_selectedDifference = m_selectedModel->firstDifference();
}
else if ( !m_selectedModel->setSelectedDifference( m_selectedDifference ) )
{
// Another backup plan
m_selectedDifference = m_selectedModel->firstDifference();
}
emit setSelection( model, diff );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
}
void KompareModelList::slotSelectionChanged( const Diff2::Difference* diff )
{
// This method will emit setSelection( const Difference* ) to whomever is listening
// when for instance in kompareview the selection has changed
kdDebug(8101) << "KompareModelList::slotSelectionChanged( " << diff << " )" << endl;
kdDebug(8101) << "Sender is : " << sender()->className() << endl;
m_selectedDifference = const_cast<Difference*>(diff);
if ( !m_selectedModel->setSelectedDifference( m_selectedDifference ) )
{
// Backup plan
m_selectedDifference = m_selectedModel->firstDifference();
}
emit setSelection( diff );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
}
void KompareModelList::slotPreviousModel()
{
if ( ( m_selectedModel = prevModel() ) != 0 )
{
m_selectedDifference = m_selectedModel->firstDifference();
}
else
{
m_selectedModel = firstModel();
m_selectedDifference = m_selectedModel->firstDifference();
}
emit setSelection( m_selectedModel, m_selectedDifference );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
}
void KompareModelList::slotNextModel()
{
if ( ( m_selectedModel = nextModel() ) != 0 )
{
m_selectedDifference = m_selectedModel->firstDifference();
}
else
{
m_selectedModel = lastModel();
m_selectedDifference = m_selectedModel->firstDifference();
}
emit setSelection( m_selectedModel, m_selectedDifference );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
}
DiffModel* KompareModelList::firstModel()
{
kdDebug( 8101 ) << "KompareModelList::firstModel()" << endl;
m_modelIndex = 0;
kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
m_selectedModel = m_models->first();
return m_selectedModel;
}
DiffModel* KompareModelList::lastModel()
{
kdDebug( 8101 ) << "KompareModelList::lastModel()" << endl;
m_modelIndex = m_models->count() - 1;
kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
m_selectedModel = m_models->last();
return m_selectedModel;
}
DiffModel* KompareModelList::prevModel()
{
kdDebug( 8101 ) << "KompareModelList::prevModel()" << endl;
if ( --m_modelIndex < m_models->count() )
{
kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
m_selectedModel = (*m_models)[ m_modelIndex ];
}
else
{
m_selectedModel = 0;
m_modelIndex = 0;
kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
}
return m_selectedModel;
}
DiffModel* KompareModelList::nextModel()
{
kdDebug( 8101 ) << "KompareModelList::nextModel()" << endl;
if ( ++m_modelIndex < m_models->count() )
{
kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
m_selectedModel = (*m_models)[ m_modelIndex ];
}
else
{
m_selectedModel = 0;
m_modelIndex = 0;
kdDebug( 8101 ) << "m_modelIndex = " << m_modelIndex << endl;
}
return m_selectedModel;
}
void KompareModelList::slotPreviousDifference()
{
kdDebug(8101) << "slotPreviousDifference called" << endl;
if ( ( m_selectedDifference = m_selectedModel->prevDifference() ) != 0 )
{
emit setSelection( m_selectedDifference );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
return;
}
kdDebug(8101) << "**** no previous difference... ok lets find the previous model..." << endl;
if ( ( m_selectedModel = prevModel() ) != 0 )
{
m_selectedDifference = m_selectedModel->lastDifference();
emit setSelection( m_selectedModel, m_selectedDifference );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
return;
}
kdDebug(8101) << "**** !!! No previous model, ok backup plan activated..." << endl;
// Backup plan
m_selectedModel = firstModel();
m_selectedDifference = m_selectedModel->firstDifference();
emit setSelection( m_selectedModel, m_selectedDifference );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
}
void KompareModelList::slotNextDifference()
{
kdDebug(8101) << "slotNextDifference called" << endl;
if ( ( m_selectedDifference = m_selectedModel->nextDifference() ) != 0 )
{
emit setSelection( m_selectedDifference );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
return;
}
kdDebug(8101) << "**** no next difference... ok lets find the next model..." << endl;
if ( ( m_selectedModel = nextModel() ) != 0 )
{
m_selectedDifference = m_selectedModel->firstDifference();
emit setSelection( m_selectedModel, m_selectedDifference );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
return;
}
kdDebug(8101) << "**** !!! No next model, ok backup plan activated..." << endl;
// Backup plan
m_selectedModel = lastModel();
m_selectedDifference = m_selectedModel->lastDifference();
emit setSelection( m_selectedModel, m_selectedDifference );
emit setStatusBarModelInfo( findModel( m_selectedModel ), m_selectedModel->findDifference( m_selectedDifference ), modelCount(), differenceCount(), m_selectedModel->appliedCount() );
updateModelListActions();
}
void KompareModelList::slotApplyDifference( bool apply )
{
m_selectedModel->applyDifference( apply );
emit applyDifference( apply );
}
void KompareModelList::slotApplyAllDifferences( bool apply )
{
m_selectedModel->applyAllDifferences( apply );
emit applyAllDifferences( apply );
}
int KompareModelList::parseDiffOutput( const TQString& diff )
{
kdDebug(8101) << "KompareModelList::parseDiffOutput" << endl;
TQStringList diffLines = split( diff );
Parser* parser = new Parser( this );
m_models = parser->parse( diffLines );
m_info.generator = parser->generator();
m_info.format = parser->format();
delete parser;
if ( m_models )
{
m_selectedModel = firstModel();
kdDebug(8101) << "Ok there are differences..." << endl;
m_selectedDifference = m_selectedModel->firstDifference();
emit setStatusBarModelInfo( 0, 0, modelCount(), differenceCount(), 0);
}
else
{
// Wow trouble, no models, so no differences...
kdDebug(8101) << "Now i'll be damned, there should be models here !!!" << endl;
return -1;
}
return 0;
}
bool KompareModelList::blendOriginalIntoModelList( const TQString& localURL )
{
kdDebug() << "Hurrah we are blending..." << endl;
TQFileInfo fi( localURL );
bool result = false;
DiffModel* model;
TQString fileContents;
if ( fi.isDir() )
{ // is a dir
kdDebug() << "Blend Dir" << endl;
// TQDir dir( localURL, TQString(), TQDir::Name|TQDir::DirsFirst, TQDir::All );
DiffModelListIterator modelIt = m_models->begin();
DiffModelListIterator mEnd = m_models->end();
for ( ; modelIt != mEnd; ++modelIt )
{
model = *modelIt;
kdDebug(8101) << "Model : " << model << endl;
TQString filename = model->sourcePath() + model->sourceFile();
if ( !filename.startsWith( localURL ) )
filename.prepend( localURL );
TQFileInfo fi2( filename );
if ( fi2.exists() )
{
kdDebug(8101) << "Reading from: " << filename << endl;
fileContents = readFile( filename );
result = blendFile( model, fileContents );
}
else
{
kdDebug(8101) << "File " << filename << " does not exist !" << endl;
kdDebug(8101) << "Assume empty file !" << endl;
fileContents.truncate( 0 );
result = blendFile( model, fileContents );
}
}
kdDebug() << "End of Blend Dir" << endl;
}
else if ( fi.isFile() )
{ // is a file
kdDebug() << "Blend File" << endl;
kdDebug(8101) << "Reading from: " << localURL << endl;
fileContents = readFile( localURL );
result = blendFile( (*m_models)[ 0 ], fileContents );
kdDebug() << "End of Blend File" << endl;
}
return result;
}
bool KompareModelList::blendFile( DiffModel* model, const TQString& fileContents )
{
if ( !model )
{
kdDebug() << "**** model is null :(" << endl;
return false;
}
model->setBlended( true );
int srcLineNo = 1, destLineNo = 1;
TQStringList lines = split( fileContents );
TQStringList::ConstIterator linesIt = lines.begin();
TQStringList::ConstIterator lEnd = lines.end();
DiffHunkList* hunks = model->hunks();
kdDebug(8101) << "Hunks in hunklist: " << hunks->count() << endl;
DiffHunkListIterator hunkIt = hunks->begin();
DiffHunk* newHunk = 0;
Difference* newDiff = 0;
// FIXME: this approach is not very good, we should first check if the hunk applies cleanly
// and without offset and if not use that new linenumber with offset to compare against
// This will only work for files we just diffed with kompare but not for blending where
// file(s) to patch has/have potentially changed
for ( ; hunkIt != hunks->end(); ++hunkIt )
{
// Do we need to insert a new hunk before this one ?
DiffHunk* hunk = *hunkIt;
if ( srcLineNo < hunk->sourceLineNumber() )
{
newHunk = new DiffHunk( srcLineNo, destLineNo, "", DiffHunk::AddedByBlend );
hunks->insert( hunkIt, newHunk );
newDiff = new Difference( srcLineNo, destLineNo,
Difference::Unchanged );
newHunk->add( newDiff );
while ( srcLineNo < hunk->sourceLineNumber() && linesIt != lEnd )
{
newDiff->addSourceLine( *linesIt );
newDiff->addDestinationLine( *linesIt );
srcLineNo++;
destLineNo++;
++linesIt;
}
}
// Now we add the linecount difference for the hunk that follows
int size = hunk->sourceLineCount();
for ( int i = 0; i < size; ++i )
{
++linesIt;
}
srcLineNo += size;
destLineNo += (*hunkIt)->destinationLineCount();
}
if ( linesIt != lEnd )
{
newHunk = new DiffHunk( srcLineNo, destLineNo, "", DiffHunk::AddedByBlend );
model->addHunk( newHunk );
newDiff = new Difference( srcLineNo, destLineNo, Difference::Unchanged );
newHunk->add( newDiff );
while ( linesIt != lEnd )
{
newDiff->addSourceLine( *linesIt );
newDiff->addDestinationLine( *linesIt );
++linesIt;
}
}
#if 0
DifferenceList hunkDiffList = (*hunkIt)->differences();
DifferenceListIterator diffIt = hunkDiffList.begin();
DifferenceListIterator dEnd = hunkDiffList.end();
kdDebug() << "Number of differences in hunkDiffList = " << diffList.count() << endl;
DifferenceListIterator tempIt;
Difference* diff;
for ( ; diffIt != dEnd; ++diffIt )
{
diff = *diffIt;
kdDebug() << "*(Diff it) = " << diff << endl;
// Check if there are lines in the original file before the difference
// that are not yet in the diff. If so create new Unchanged diff
if ( srcLineNo < diff->sourceLineNumber() )
{
newDiff = new Difference( srcLineNo, destLineNo,
Difference::Unchanged | Difference::AddedByBlend );
newHunk->add( newDiff );
while ( srcLineNo < diff->sourceLineNumber() && linesIt != lEnd )
{
// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *linesIt << endl;
newDiff->addSourceLine( *linesIt );
newDiff->addDestinationLine( *linesIt );
srcLineNo++;
destLineNo++;
++linesIt;
}
}
// Now i've got to add that diff
switch ( diff->type() )
{
case Difference::Unchanged:
kdDebug(8101) << "Unchanged" << endl;
for ( int i = 0; i < diff->sourceLineCount(); i++ )
{
if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
{
kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
// Do conflict resolution (well sort of)
diff->sourceLineAt( i )->setConflictString( *linesIt );
diff->setConflict( true );
}
// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *linesIt << endl;
// kdDebug(8101) << "DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
srcLineNo++;
destLineNo++;
++linesIt;
}
tempIt = diffIt;
--diffIt;
diffList.remove( tempIt );
newHunk->add( diff );
break;
case Difference::Change:
kdDebug(8101) << "Change" << endl;
//TQStringListConstIterator saveIt = linesIt;
for ( int i = 0; i < diff->sourceLineCount(); i++ )
{
if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
{
kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
// Do conflict resolution (well sort of)
diff->sourceLineAt( i )->setConflictString( *linesIt );
diff->setConflict( true );
}
srcLineNo++;
destLineNo++;
++linesIt;
}
destLineNo += diff->destinationLineCount();
tempIt = diffIt;
--diffIt;
diffList.remove( tempIt );
newHunk->add( diff );
newModel->addDiff( diff );
break;
case Difference::Insert:
kdDebug(8101) << "Insert" << endl;
destLineNo += diff->destinationLineCount();
tempIt = diffIt;
--diffIt;
diffList.remove( tempIt );
newHunk->add( diff );
newModel->addDiff( diff );
break;
case Difference::Delete:
kdDebug(8101) << "Delete" << endl;
kdDebug(8101) << "Number of lines in Delete: " << diff->sourceLineCount() << endl;
for ( int i = 0; i < diff->sourceLineCount(); i++ )
{
if ( linesIt != lEnd && *linesIt != diff->sourceLineAt( i )->string() )
{
kdDebug(8101) << "Conflict: SourceLine = " << srcLineNo << ": " << *linesIt << endl;
kdDebug(8101) << "Conflict: DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
// Do conflict resolution (well sort of)
diff->sourceLineAt( i )->setConflictString( *linesIt );
diff->setConflict( true );
}
// kdDebug(8101) << "SourceLine = " << srcLineNo << ": " << *it << endl;
// kdDebug(8101) << "DiffLine = " << diff->sourceLineNumber() + i << ": " << diff->sourceLineAt( i )->string() << endl;
srcLineNo++;
++linesIt;
}
tempIt = diffIt;
--diffIt;
diffList.remove( tempIt );
newHunk->add( diff );
newModel->addDiff( diff );
break;
default:
kdDebug(8101) << "****, some diff type we dont know about ???" << endl;
}
}
}
#endif
/*
diffList = newModel->differences();
diff = diffList.first();
kdDebug(8101) << "Count = " << diffList.count() << endl;
for ( diff = diffList.first(); diff; diff = diffList.next() )
{
kdDebug(8101) << "sourcelinenumber = " << diff->sourceLineNumber() << endl;
}
*/
m_selectedModel = firstModel();
m_selectedDifference = m_selectedModel->firstDifference();
return true;
}
void KompareModelList::show()
{
kdDebug() << "KompareModelList::Show Number of models = " << m_models->count() << endl;
emit modelsChanged( m_models );
emit setSelection( m_selectedModel, m_selectedDifference );
}
void KompareModelList::clear()
{
if ( m_models )
m_models->clear();
emit modelsChanged( m_models );
}
void KompareModelList::swap()
{
TQString source = m_source;
TQString destination = m_destination;
if ( m_info.mode == Kompare::ComparingFiles )
compareFiles( destination, source );
else if ( m_info.mode == Kompare::ComparingDirs )
compareDirs( destination, source );
}
bool KompareModelList::isModified() const
{
if ( m_noOfModified > 0 )
return true;
return false;
}
int KompareModelList::modelCount() const
{
return m_models ? m_models->count() : 0;
}
int KompareModelList::differenceCount() const
{
return m_selectedModel ? m_selectedModel->differenceCount() : -1;
}
int KompareModelList::appliedCount() const
{
return m_selectedModel ? m_selectedModel->appliedCount() : -1;
}
void KompareModelList::slotSetModified( bool modified )
{
kdDebug(8101) << "KompareModelList::slotSetModified( " << modified << " );" << endl;
kdDebug(8101) << "Before: m_noOfModified = " << m_noOfModified << endl;
// If selectedModel emits its signal setModified it does not set the model
// internal m_modified bool yet, it only does that after the emit.
if ( modified && !m_selectedModel->isModified() )
m_noOfModified++;
else if ( !modified && m_selectedModel->isModified() )
m_noOfModified--;
kdDebug(8101) << "After : m_noOfModified = " << m_noOfModified << endl;
if ( m_noOfModified < 0 )
{
kdDebug(8101) << "Wow something is ****ed up..." << endl;
}
else if ( m_noOfModified == 0 )
{
emit setModified( false );
}
else // > 0 :-)
{
emit setModified( true );
}
}
bool KompareModelList::setSelectedModel( DiffModel* model )
{
kdDebug(8101) << "KompareModelList::setSelectedModel( " << model << " )" << endl;
if ( model != m_selectedModel )
{
if ( m_models->findIndex( model ) == -1 )
return false;
kdDebug(8101) << "m_selectedModel (was) = " << m_selectedModel << endl;
m_modelIndex = m_models->findIndex( model );
kdDebug(8101) << "m_selectedModel (is) = " << m_selectedModel << endl;
m_selectedModel = model;
}
updateModelListActions();
return true;
}
void KompareModelList::updateModelListActions()
{
if ( m_models && m_selectedModel && m_selectedDifference )
{
if ( ( ( KomparePart* )parent() )->isReadWrite() )
{
if ( m_selectedModel->appliedCount() != m_selectedModel->differenceCount() )
m_applyAll->setEnabled( true );
else
m_applyAll->setEnabled( false );
if ( m_selectedModel->appliedCount() != 0 )
m_unapplyAll->setEnabled( true );
else
m_unapplyAll->setEnabled( false );
m_applyDifference->setEnabled( true );
m_unApplyDifference->setEnabled( true );
m_save->setEnabled( m_selectedModel->isModified() );
}
else
{
m_applyDifference->setEnabled ( false );
m_unApplyDifference->setEnabled( false );
m_applyAll->setEnabled ( false );
m_unapplyAll->setEnabled ( false );
m_save->setEnabled ( false );
}
m_previousFile->setEnabled ( hasPrevModel() );
m_nextFile->setEnabled ( hasNextModel() );
m_previousDifference->setEnabled( hasPrevDiff() );
m_nextDifference->setEnabled ( hasNextDiff() );
}
else
{
m_applyDifference->setEnabled ( false );
m_unApplyDifference->setEnabled ( false );
m_applyAll->setEnabled ( false );
m_unapplyAll->setEnabled ( false );
m_previousFile->setEnabled ( false );
m_nextFile->setEnabled ( false );
m_previousDifference->setEnabled( false );
m_nextDifference->setEnabled ( false );
m_save->setEnabled ( false );
}
}
bool KompareModelList::hasPrevModel() const
{
kdDebug(8101) << "KompareModelList::hasPrevModel()" << endl;
if ( m_modelIndex > 0 )
{
// kdDebug(8101) << "has prev model" << endl;
return true;
}
// kdDebug(8101) << "doesn't have a prev model, this is the first one..." << endl;
return false;
}
bool KompareModelList::hasNextModel() const
{
kdDebug(8101) << "KompareModelList::hasNextModel()" << endl;
if ( ( unsigned int )m_modelIndex < ( m_models->count() - 1 ) )
{
// kdDebug(8101) << "has next model" << endl;
return true;
}
// kdDebug(8101) << "doesn't have a next model, this is the last one..." << endl;
return false;
}
bool KompareModelList::hasPrevDiff() const
{
// kdDebug(8101) << "KompareModelList::hasPrevDiff()" << endl;
int index = m_selectedModel->diffIndex();
if ( index > 0 )
{
// kdDebug(8101) << "has prev difference in same model" << endl;
return true;
}
if ( hasPrevModel() )
{
// kdDebug(8101) << "has prev difference but in prev model" << endl;
return true;
}
// kdDebug(8101) << "doesn't have a prev difference, not even in the previous model because there is no previous model" << endl;
return false;
}
bool KompareModelList::hasNextDiff() const
{
// kdDebug(8101) << "KompareModelList::hasNextDiff()" << endl;
int index = m_selectedModel->diffIndex();
if ( index < ( m_selectedModel->differenceCount() - 1 ) )
{
// kdDebug(8101) << "has next difference in same model" << endl;
return true;
}
if ( hasNextModel() )
{
// kdDebug(8101) << "has next difference but in next model" << endl;
return true;
}
// kdDebug(8101) << "doesn't have a next difference, not even in next model because there is no next model" << endl;
return false;
}
void KompareModelList::slotActionApplyDifference()
{
if ( !m_selectedDifference->applied() )
slotApplyDifference( true );
slotNextDifference();
updateModelListActions();
}
void KompareModelList::slotActionUnApplyDifference()
{
if ( m_selectedDifference->applied() )
slotApplyDifference( false );
slotPreviousDifference();
updateModelListActions();
}
void KompareModelList::slotActionApplyAllDifferences()
{
slotApplyAllDifferences( true );
updateModelListActions();
}
void KompareModelList::slotActionUnapplyAllDifferences()
{
slotApplyAllDifferences( false );
updateModelListActions();
}
#include "komparemodellist.moc"