/*************************************************************************** kompare_part.cpp ---------------- begin : Sun Mar 4 2001 Copyright 2001-2005,2009 Otto Bruggeman Copyright 2001-2003 John Firebaugh Copyright 2004 Jeff Snyder Copyright 2007-2011 Kevin Kofler Copyright 2012 Jean-Nicolas Artaud ****************************************************************************/ /*************************************************************************** ** ** 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 "kompare_part.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "diffmodel.h" #include "komparelistview.h" #include "kompareconnectwidget.h" #include "diffsettings.h" #include "viewsettings.h" #include "kompareprefdlg.h" #include "komparesaveoptionswidget.h" #include "komparesplitter.h" #include "kompareview.h" K_PLUGIN_FACTORY( KomparePartFactory, registerPlugin(); ) K_EXPORT_PLUGIN( KomparePartFactory ) ViewSettings* KomparePart::m_viewSettings = 0L; DiffSettings* KomparePart::m_diffSettings = 0L; KomparePart::KomparePart( QWidget *parentWidget, QObject *parent, const QVariantList & /*args*/ ) : KParts::ReadWritePart(parent), m_tempDiff( 0 ), m_info() { if( !m_viewSettings ) { m_viewSettings = new ViewSettings( 0 ); } if( !m_diffSettings ) { m_diffSettings = new DiffSettings( 0 ); } readProperties( KGlobal::config().data() ); m_view = new KompareView ( m_viewSettings, parentWidget ); setWidget( m_view ); m_splitter = m_view->splitter(); // This creates the "Model creator" and connects the signals and slots m_modelList = new Diff2::KompareModelList( m_diffSettings, m_splitter, this, "komparemodellist" , KParts::ReadWritePart::isReadWrite()); Q_FOREACH(QAction* action, m_modelList->actionCollection()->actions()) { actionCollection()->addAction(action->objectName(), action); } connect( m_modelList, SIGNAL(status( Kompare::Status )), this, SLOT(slotSetStatus( Kompare::Status )) ); connect( m_modelList, SIGNAL(setStatusBarModelInfo( int, int, int, int, int )), this, SIGNAL(setStatusBarModelInfo( int, int, int, int, int )) ); connect( m_modelList, SIGNAL(error( QString )), this, SLOT(slotShowError( QString )) ); connect( m_modelList, SIGNAL(applyAllDifferences( bool )), this, SLOT(updateActions()) ); connect( m_modelList, SIGNAL(applyDifference( bool )), this, SLOT(updateActions()) ); connect( m_modelList, SIGNAL(applyAllDifferences( bool )), this, SIGNAL(appliedChanged()) ); connect( m_modelList, SIGNAL(applyDifference( bool )), this, SIGNAL(appliedChanged()) ); connect( m_modelList, SIGNAL(updateActions()), this, SLOT(updateActions()) ); // This is the stuff to connect the "interface" of the kompare part to the model inside connect( m_modelList, SIGNAL(modelsChanged(const Diff2::DiffModelList*)), this, SIGNAL(modelsChanged(const Diff2::DiffModelList*)) ); connect( m_modelList, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)), this, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)) ); connect( this, SIGNAL(selectionChanged(const Diff2::DiffModel*, const Diff2::Difference*)), m_modelList, SLOT(slotSelectionChanged(const Diff2::DiffModel*, const Diff2::Difference*)) ); connect( m_modelList, SIGNAL(setSelection(const Diff2::Difference*)), this, SIGNAL(setSelection(const Diff2::Difference*)) ); connect( this, SIGNAL(selectionChanged(const Diff2::Difference*)), m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*)) ); connect( m_modelList, SIGNAL(applyDifference(bool)), this, SIGNAL(applyDifference(bool)) ); connect( m_modelList, SIGNAL(applyAllDifferences(bool)), this, SIGNAL(applyAllDifferences(bool)) ); connect( m_modelList, SIGNAL(applyDifference(const Diff2::Difference*, bool)), this, SIGNAL(applyDifference(const Diff2::Difference*, bool)) ); connect( m_modelList, SIGNAL(diffString(const QString&)), this, SIGNAL(diffString(const QString&)) ); connect( this, SIGNAL(kompareInfo(Kompare::Info*)), m_modelList, SLOT(slotKompareInfo(Kompare::Info*)) ); // Here we connect the splitter to the modellist connect( m_modelList, SIGNAL(setSelection(const Diff2::DiffModel*, const Diff2::Difference*)), m_splitter, SLOT(slotSetSelection(const Diff2::DiffModel*, const Diff2::Difference*)) ); // connect( m_splitter, SIGNAL(selectionChanged(const Diff2::Difference*, const Diff2::Difference*)), // m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*, const Diff2::Difference*)) ); connect( m_modelList, SIGNAL(setSelection(const Diff2::Difference*)), m_splitter, SLOT(slotSetSelection(const Diff2::Difference*)) ); connect( m_splitter, SIGNAL(selectionChanged(const Diff2::Difference*)), m_modelList, SLOT(slotSelectionChanged(const Diff2::Difference*)) ); connect( m_modelList, SIGNAL(applyDifference(bool)), m_splitter, SLOT(slotApplyDifference(bool)) ); connect( m_modelList, SIGNAL(applyAllDifferences(bool)), m_splitter, SLOT(slotApplyAllDifferences(bool)) ); connect( m_modelList, SIGNAL(applyDifference(const Diff2::Difference*, bool)), m_splitter, SLOT(slotApplyDifference(const Diff2::Difference*, bool)) ); connect( this, SIGNAL(configChanged()), m_splitter, SIGNAL(configChanged()) ); setupActions(); // set our XML-UI resource file setXMLFile( "komparepartui.rc" ); // we are read-write by default -> uhm what if we are opened by lets say konq in RO mode ? // Then we should not be doing this... setReadWrite( true ); // we are not modified since we haven't done anything yet setModified( false ); } KomparePart::~KomparePart() { // This is the only place allowed to call cleanUpTemporaryFiles // because before there might still be a use for them (when swapping) cleanUpTemporaryFiles(); } void KomparePart::setupActions() { // create our actions m_saveAll = actionCollection()->addAction("file_save_all", this, SLOT(saveAll())); m_saveAll->setIcon(KIcon("document-save-all")); m_saveAll->setText(i18n("Save &All")); m_saveDiff = actionCollection()->addAction("file_save_diff", this, SLOT(saveDiff())); m_saveDiff->setText(i18n("Save &Diff...")); m_swap = actionCollection()->addAction("file_swap", this, SLOT(slotSwap())); m_swap->setText(i18n("Swap Source with Destination")); m_diffStats = actionCollection()->addAction("file_diffstats", this, SLOT(slotShowDiffstats())); m_diffStats->setText(i18n("Show Statistics")); m_diffRefresh = actionCollection()->addAction("file_refreshdiff", this, SLOT(slotRefreshDiff())); m_diffRefresh->setIcon(KIcon("view-refresh")); m_diffRefresh->setText(i18n("Refresh Diff")); m_diffRefresh->setShortcut(KStandardShortcut::reload()); m_print = actionCollection()->addAction(KStandardAction::Print, this, SLOT( slotFilePrint() )); m_printPreview = actionCollection()->addAction(KStandardAction::PrintPreview, this, SLOT( slotFilePrintPreview() )); KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection()); } void KomparePart::updateActions() { m_saveAll->setEnabled ( m_modelList->hasUnsavedChanges() ); m_saveDiff->setEnabled ( m_modelList->mode() == Kompare::ComparingFiles || m_modelList->mode() == Kompare::ComparingDirs ); m_swap->setEnabled ( m_modelList->mode() == Kompare::ComparingFiles || m_modelList->mode() == Kompare::ComparingDirs ); m_diffRefresh->setEnabled ( m_modelList->mode() == Kompare::ComparingFiles || m_modelList->mode() == Kompare::ComparingDirs ); m_diffStats->setEnabled ( m_modelList->modelCount() > 0 ); m_print->setEnabled ( m_modelList->modelCount() > 0 ); // If modellist has models then we have something to print, it's that simple. m_printPreview->setEnabled( m_modelList ); } void KomparePart::setEncoding( const QString& encoding ) { kDebug(8103) << "Encoding: " << encoding << endl; m_modelList->setEncoding( encoding ); } bool KomparePart::openDiff( const KUrl& url ) { kDebug(8103) << "Url = " << url.url() << endl; m_info.mode = Kompare::ShowingDiff; m_info.source = url; bool result = false; fetchURL( url, true ); emit kompareInfo( &m_info ); if ( !m_info.localSource.isEmpty() ) { kDebug(8103) << "Download succeeded " << endl; result = m_modelList->openDiff( m_info.localSource ); updateActions(); updateCaption(); updateStatus(); } else { kDebug(8103) << "Download failed !" << endl; } return result; } bool KomparePart::openDiff( const QString& diffOutput ) { bool value = false; m_info.mode = Kompare::ShowingDiff; emit kompareInfo( &m_info ); if ( m_modelList->parseAndOpenDiff( diffOutput ) == 0 ) { value = true; updateActions(); updateCaption(); updateStatus(); } return value; } bool KomparePart::openDiff3( const KUrl& diff3Url ) { // FIXME: Implement this !!! kDebug(8103) << "Not implemented yet. Filename is: " << diff3Url.prettyUrl() << endl; return false; } bool KomparePart::openDiff3( const QString& diff3Output ) { // FIXME: Implement this !!! kDebug(8103) << "Not implemented yet. diff3 output is: " << endl; kDebug(8103) << diff3Output << endl; return false; } bool KomparePart::exists( const QString& url ) { QFileInfo fi( url ); return fi.exists(); } bool KomparePart::fetchURL( const KUrl& url, bool addToSource ) { // Default value if there is an error is "", we rely on it! QString tempFileName( "" ); // Only in case of error do we set result to false, don't forget!! bool result = true; KTempDir* tmpDir = 0; if ( !url.isLocalFile() ) { KIO::UDSEntry node; KIO::NetAccess::stat( url, node, widget() ); if ( !node.isDir() ) { if ( ! KIO::NetAccess::download( url, tempFileName, widget() ) ) { slotShowError( i18n( "The URL %1 cannot be downloaded.", url.prettyUrl() ) ); tempFileName = ""; // Not sure if download has already touched this tempFileName when there is an error result = false; } } else { tmpDir = new KTempDir(KStandardDirs::locateLocal("tmp", "kompare")); tmpDir->setAutoRemove( true ); // Yes this is the default but just to make sure if ( ! KIO::NetAccess::dircopy( url, KUrl( tmpDir->name() ), widget() ) ) { slotShowError( i18n( "The URL %1 cannot be downloaded.", url.prettyUrl() ) ); delete tmpDir; tmpDir = 0; result = false; } else { tempFileName = tmpDir->name(); kDebug(8101) << "tempFileName = " << tempFileName << endl; // If a directory is copied into KTempDir then the directory in // here is what I need to add to tempFileName QDir dir( tempFileName ); QStringList entries = dir.entryList( QDir::Dirs | QDir::NoDotAndDotDot ); if ( entries.size() == 1 ) // More than 1 entry in here means big problems!!! { if ( !tempFileName.endsWith( '/' ) ) tempFileName += '/'; tempFileName += entries.at( 0 ); tempFileName += '/'; } else { kDebug(8101) << "Yikes, nothing downloaded?" << endl; delete tmpDir; tmpDir = 0; tempFileName = ""; result = false; } } } } else { // is Local already, check if exists if ( exists( url.toLocalFile() ) ) tempFileName = url.toLocalFile(); else { slotShowError( i18n( "The URL %1 does not exist on your system.", url.prettyUrl() ) ); result = false; } } if ( addToSource ) { m_info.localSource = tempFileName; m_info.sourceKTempDir = tmpDir; } else { m_info.localDestination = tempFileName; m_info.destinationKTempDir = tmpDir; } return result; } void KomparePart::cleanUpTemporaryFiles() { kDebug(8101) << "Cleaning temporary files." << endl; if ( !m_info.localSource.isEmpty() ) { if ( m_info.sourceKTempDir == 0 ) KIO::NetAccess::removeTempFile( m_info.localSource ); else { delete m_info.sourceKTempDir; m_info.sourceKTempDir = 0; } m_info.localSource = ""; } if ( !m_info.localDestination.isEmpty() ) { if ( m_info.destinationKTempDir == 0 ) KIO::NetAccess::removeTempFile( m_info.localDestination ); else { delete m_info.destinationKTempDir; m_info.destinationKTempDir = 0; } m_info.localDestination = ""; } } void KomparePart::compare( const KUrl& source, const KUrl& destination ) { // FIXME: This is silly, i can use NetAccess::stat to figure out what it is and not // wait until i am in the modellist to determine the mode we're supposed to be in. // That should make the code more readable // I should store the KTempDir(s)/File(s) in the Info struct as well and delete it at the right time m_info.source = source; m_info.destination = destination; // FIXME: (Not urgent) But turn this into an enum, for now i cant find a nice name for the enum that has Source and Destination as values // For now we do not do error checking, user has already been notified and if the localString is empty then we dont diff fetchURL( source, true ); fetchURL( destination, false ); emit kompareInfo( &m_info ); compareAndUpdateAll(); } void KomparePart::compareFileString( const KUrl & sourceFile, const QString & destination) { //Set the modeto specify that the source is a file, and the destination is a string m_info.mode = Kompare::ComparingFileString; m_info.source = sourceFile; m_info.localDestination = destination; fetchURL(sourceFile, true); emit kompareInfo( &m_info ); compareAndUpdateAll(); } void KomparePart::compareStringFile( const QString & source, const KUrl & destinationFile) { //Set the modeto specify that the source is a file, and the destination is a string m_info.mode = Kompare::ComparingStringFile; m_info.localSource = source; m_info.destination = destinationFile; fetchURL(destinationFile, false); emit kompareInfo( &m_info ); compareAndUpdateAll(); } void KomparePart::compareFiles( const KUrl& sourceFile, const KUrl& destinationFile ) { m_info.mode = Kompare::ComparingFiles; m_info.source = sourceFile; m_info.destination = destinationFile; // FIXME: (Not urgent) But turn this into an enum, for now i cant find a nice name for the enum that has Source and Destination as values // For now we do not do error checking, user has already been notified and if the localString is empty then we dont diff fetchURL( sourceFile, true ); fetchURL( destinationFile, false ); emit kompareInfo( &m_info ); compareAndUpdateAll(); } void KomparePart::compareDirs( const KUrl& sourceDirectory, const KUrl& destinationDirectory ) { m_info.mode = Kompare::ComparingDirs; m_info.source = sourceDirectory; m_info.destination = destinationDirectory; fetchURL( sourceDirectory, true ); fetchURL( destinationDirectory, false ); emit kompareInfo( &m_info ); compareAndUpdateAll(); } void KomparePart::compare3Files( const KUrl& /*originalFile*/, const KUrl& /*changedFile1*/, const KUrl& /*changedFile2*/ ) { // FIXME: actually implement this some day :) updateActions(); updateCaption(); updateStatus(); } void KomparePart::openFileAndDiff( const KUrl& file, const KUrl& diffFile ) { m_info.source = file; m_info.destination = diffFile; fetchURL( file, true ); fetchURL( diffFile, false ); m_info.mode = Kompare::BlendingFile; emit kompareInfo( &m_info ); compareAndUpdateAll(); } void KomparePart::openDirAndDiff ( const KUrl& dir, const KUrl& diffFile ) { m_info.source = dir; m_info.destination = diffFile; fetchURL( dir, true ); fetchURL( diffFile, false ); m_info.mode = Kompare::BlendingDir; emit kompareInfo( &m_info ); if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() ) { m_modelList->openDirAndDiff(); //Must this be in here? couldn't we use compareAndUpdateAll as well? updateActions(); updateCaption(); updateStatus(); } } bool KomparePart::openFile() { // This is called from openURL // This is a little inefficient but i will do it anyway openDiff( url() ); return true; } bool KomparePart::saveAll() { bool result = m_modelList->saveAll(); updateActions(); updateCaption(); updateStatus(); return result; } void KomparePart::saveDiff() { KDialog dlg( widget() ); dlg.setObjectName( "save_options" ); dlg.setModal( true ); dlg.setWindowTitle( i18n("Diff Options") ); dlg.setButtons( KDialog::Ok|KDialog::Cancel ); KompareSaveOptionsWidget* w = new KompareSaveOptionsWidget( m_info.localSource, m_info.localDestination, m_diffSettings, &dlg ); dlg.setMainWidget( w ); dlg.setButtonGuiItem( KDialog::Ok, KStandardGuiItem::save() ); if( dlg.exec() ) { w->saveOptions(); KSharedConfig::Ptr config = componentData().config(); saveProperties( config.data() ); config->sync(); while ( 1 ) { KUrl url = KFileDialog::getSaveUrl( m_info.destination.url(), i18n("*.diff *.dif *.patch|Patch Files"), widget(), i18n( "Save .diff" ) ); if ( KIO::NetAccess::exists( url, KIO::NetAccess::DestinationSide, widget() ) ) { int result = KMessageBox::warningYesNoCancel( widget(), i18n("The file exists or is write-protected; do you want to overwrite it?"), i18n("File Exists"), KGuiItem(i18n("Overwrite")), KGuiItem(i18n("Do Not Overwrite")) ); if ( result == KMessageBox::Cancel ) { break; } else if ( result == KMessageBox::No ) { continue; } else { kDebug(8103) << "URL = " << url.prettyUrl() << endl; kDebug(8103) << "Directory = " << w->directory() << endl; kDebug(8103) << "DiffSettings = " << m_diffSettings << endl; m_modelList->saveDiff( url.url(), w->directory(), m_diffSettings ); break; } } else { kDebug(8103) << "URL = " << url.prettyUrl() << endl; kDebug(8103) << "Directory = " << w->directory() << endl; kDebug(8103) << "DiffSettings = " << m_diffSettings << endl; m_modelList->saveDiff( url.url(), w->directory(), m_diffSettings ); break; } } } } void KomparePart::slotFilePrint() { QPrinter printer; printer.setOrientation( QPrinter::Landscape ); QPrintDialog* dlg = KdePrint::createPrintDialog( &printer, m_splitter ); if ( dlg->exec() == QDialog::Accepted ) { // do some printing in qprinter slotPaintRequested( &printer ); } delete dlg; } void KomparePart::slotFilePrintPreview() { QPrinter printer; printer.setOrientation( QPrinter::Landscape ); QPrintPreviewDialog dlg( &printer ); connect( &dlg, SIGNAL(paintRequested(QPrinter*)), this, SLOT(slotPaintRequested(QPrinter*)) ); dlg.exec(); } void KomparePart::slotPaintRequested( QPrinter* printer ) { kDebug(8103) << "Now paint something..." << endl; QPainter p; p.begin( printer ); QSize widgetWidth = m_view->size(); kDebug(8103) << "printer.width() = " << printer->width() << endl; kDebug(8103) << "widgetWidth.width() = " << widgetWidth.width() << endl; qreal factor = ((qreal)printer->width())/((qreal)widgetWidth.width()); kDebug(8103) << "factor = " << factor << endl; p.scale( factor, factor ); m_view->render( &p ); p.end(); kDebug(8103) << "Done painting something..." << endl; } KAboutData* KomparePart::createAboutData() { KAboutData *about = new KAboutData("kompare", 0, ki18n("KomparePart"), "4.0"); about->addAuthor(ki18n("John Firebaugh"), ki18n("Author"), "jfirebaugh@kde.org"); about->addAuthor(ki18n("Otto Bruggeman"), ki18n("Author"), "bruggie@gmail.com" ); about->addAuthor(ki18n("Kevin Kofler"), ki18n("Author"), "kevin.kofler@chello.at" ); return about; } void KomparePart::slotSetStatus( enum Kompare::Status status ) { updateActions(); switch( status ) { case Kompare::RunningDiff: emit setStatusBarText( i18n( "Running diff..." ) ); break; case Kompare::Parsing: emit setStatusBarText( i18n( "Parsing diff output..." ) ); break; case Kompare::FinishedParsing: updateStatus(); break; case Kompare::FinishedWritingDiff: updateStatus(); emit diffURLChanged(); break; default: break; } } void KomparePart::updateCaption() { QString source = m_info.source.prettyUrl(); QString destination = m_info.destination.prettyUrl(); QString text; switch ( m_info.mode ) { case Kompare::ComparingFiles : case Kompare::ComparingDirs : case Kompare::BlendingFile : case Kompare::BlendingDir : text = source + " -- " + destination; // no need to translate this " -- " break; case Kompare::ShowingDiff : text = source; break; default: break; } emit setWindowCaption( text ); } void KomparePart::updateStatus() { QString source = m_info.source.prettyUrl(); QString destination = m_info.destination.prettyUrl(); QString text; switch ( m_info.mode ) { case Kompare::ComparingFiles : text = i18n( "Comparing file %1 with file %2" , source , destination ); break; case Kompare::ComparingDirs : text = i18n( "Comparing files in %1 with files in %2" , source , destination ); break; case Kompare::ShowingDiff : text = i18n( "Viewing diff output from %1", source ); break; case Kompare::BlendingFile : text = i18n( "Blending diff output from %1 into file %2" , source , destination ); break; case Kompare::BlendingDir : text = i18n( "Blending diff output from %1 into folder %2" , m_info.source.prettyUrl() , m_info.destination.prettyUrl() ); break; default: break; } emit setStatusBarText( text ); } void KomparePart::compareAndUpdateAll() { if ( !m_info.localSource.isEmpty() && !m_info.localDestination.isEmpty() ) { switch(m_info.mode) { default: case Kompare::UnknownMode: m_modelList->compare(); break; case Kompare::ComparingStringFile: case Kompare::ComparingFileString: case Kompare::ComparingFiles: case Kompare::ComparingDirs: m_modelList->compare(m_info.mode); break; case Kompare::BlendingFile: m_modelList->openFileAndDiff(); break; } updateCaption(); updateStatus(); } updateActions(); } void KomparePart::slotShowError( QString error ) { KMessageBox::error( widget(), error ); } void KomparePart::slotSwap() { if ( m_modelList->hasUnsavedChanges() ) { int query = KMessageBox::warningYesNoCancel ( widget(), i18n( "You have made changes to the destination file(s).\n" "Would you like to save them?" ), i18n( "Save Changes?" ), KStandardGuiItem::save(), KStandardGuiItem::discard() ); if ( query == KMessageBox::Yes ) m_modelList->saveAll(); if ( query == KMessageBox::Cancel ) return; // Abort prematurely so no swapping } // Swap the info in the Kompare::Info struct m_info.swapSourceWithDestination(); // Update window caption and statusbar text updateCaption(); updateStatus(); m_modelList->swap(); } void KomparePart::slotRefreshDiff() { if ( m_modelList->hasUnsavedChanges() ) { int query = KMessageBox::warningYesNoCancel ( widget(), i18n( "You have made changes to the destination file(s).\n" "Would you like to save them?" ), i18n( "Save Changes?" ), KStandardGuiItem::save(), KStandardGuiItem::discard() ); if ( query == KMessageBox::Cancel ) return; // Abort prematurely so no refreshing if ( query == KMessageBox::Yes ) m_modelList->saveAll(); } // For this to work properly you have to refetch the files from their (remote) locations cleanUpTemporaryFiles(); fetchURL( m_info.source, true ); fetchURL( m_info.destination, false ); m_modelList->refresh(); } void KomparePart::slotShowDiffstats( void ) { // Fetch all the args needed for komparestatsmessagebox // oldfile, newfile, diffformat, noofhunks, noofdiffs QString oldFile; QString newFile; QString diffFormat; int filesInDiff; int noOfHunks; int noOfDiffs; oldFile = m_modelList->selectedModel() ? m_modelList->selectedModel()->sourceFile() : QString( "" ); newFile = m_modelList->selectedModel() ? m_modelList->selectedModel()->destinationFile() : QString( "" ); if ( m_modelList->selectedModel() ) { switch( m_info.format ) { case Kompare::Unified : diffFormat = i18n( "Unified" ); break; case Kompare::Context : diffFormat = i18n( "Context" ); break; case Kompare::RCS : diffFormat = i18n( "RCS" ); break; case Kompare::Ed : diffFormat = i18n( "Ed" ); break; case Kompare::Normal : diffFormat = i18n( "Normal" ); break; case Kompare::UnknownFormat : default: diffFormat = i18n( "Unknown" ); break; } } else { diffFormat = ""; } filesInDiff = m_modelList->modelCount(); noOfHunks = m_modelList->selectedModel() ? m_modelList->selectedModel()->hunkCount() : 0; noOfDiffs = m_modelList->selectedModel() ? m_modelList->selectedModel()->differenceCount() : 0; if ( m_modelList->modelCount() == 0 ) { // no diff loaded yet KMessageBox::information( 0L, i18n( "No diff file, or no 2 files have been diffed. " "Therefore no stats are available."), i18n("Diff Statistics"), QString(), 0 ); } else if ( m_modelList->modelCount() == 1 ) { // 1 file in diff, or 2 files compared KMessageBox::information( 0L, i18n( "Statistics:\n" "\n" "Old file: %1\n" "New file: %2\n" "\n" "Format: %3\n" "Number of hunks: %4\n" "Number of differences: %5", oldFile, newFile, diffFormat, noOfHunks, noOfDiffs), i18n("Diff Statistics"), QString(), 0 ); } else { // more than 1 file in diff, or 2 directories compared KMessageBox::information( 0L, ki18n( "Statistics:\n" "\n" "Number of files in diff file: %1\n" "Format: %2\n" "\n" "Current old file: %3\n" "Current new file: %4\n" "\n" "Number of hunks: %5\n" "Number of differences: %6") .subs(filesInDiff).subs(diffFormat).subs(oldFile) .subs(newFile).subs(noOfHunks).subs(noOfDiffs) .toString(), i18n("Diff Statistics"), QString(), 0 ); } } bool KomparePart::queryClose() { if ( !m_modelList->hasUnsavedChanges() ) return true; int query = KMessageBox::warningYesNoCancel ( widget(), i18n("You have made changes to the destination file(s).\n" "Would you like to save them?" ), i18n( "Save Changes?" ), KStandardGuiItem::save(), KStandardGuiItem::discard() ); if( query == KMessageBox::Cancel ) return false; if( query == KMessageBox::Yes ) return m_modelList->saveAll(); return true; } int KomparePart::readProperties( KConfig *config ) { m_viewSettings->loadSettings( config ); m_diffSettings->loadSettings( config ); emit configChanged(); return 0; } int KomparePart::saveProperties( KConfig *config ) { m_viewSettings->saveSettings( config ); m_diffSettings->saveSettings( config ); return 0; } void KomparePart::optionsPreferences() { // show preferences KomparePrefDlg pref( m_viewSettings, m_diffSettings ); connect( &pref, SIGNAL(configChanged()), this, SIGNAL(configChanged()) ); if ( pref.exec() ) emit configChanged(); } #include "moc_kompare_part.cpp"