|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2001 by Harald Fernengel *
|
|
|
|
* harry@kdevelop.org *
|
|
|
|
* *
|
|
|
|
* 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 "diffpart.h"
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kdevgenericfactory.h>
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <kfiledialog.h>
|
|
|
|
#include <kprocess.h>
|
|
|
|
#include <kio/jobclasses.h>
|
|
|
|
#include <kio/job.h>
|
|
|
|
#include <kparts/part.h>
|
|
|
|
#include <ktexteditor/editinterface.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
|
|
|
|
#include "kdevcore.h"
|
|
|
|
#include "kdevmainwindow.h"
|
|
|
|
#include "kdevpartcontroller.h"
|
|
|
|
#include "kdevplugininfo.h"
|
|
|
|
|
|
|
|
#include "diffdlg.h"
|
|
|
|
#include "diffwidget.h"
|
|
|
|
|
|
|
|
static const KDevPluginInfo data("kdevdiff");
|
|
|
|
|
|
|
|
typedef KDevGenericFactory<DiffPart> DiffFactory;
|
|
|
|
K_EXPORT_COMPONENT_FACTORY( libkdevdiff, DiffFactory( data ) )
|
|
|
|
|
|
|
|
DiffPart::DiffPart(TQObject *tqparent, const char *name, const TQStringList &)
|
|
|
|
: KDevDiffFrontend(&data, tqparent, name ? name : "DiffPart"), proc(0)
|
|
|
|
{
|
|
|
|
setInstance(DiffFactory::instance());
|
|
|
|
setXMLFile("kdevdiff.rc");
|
|
|
|
|
|
|
|
diffWidget = new DiffWidget(this, 0, "diffWidget");
|
|
|
|
diffWidget->setIcon( SmallIcon("editcopy") );
|
|
|
|
TQString nm( i18n( "Diff" ) );
|
|
|
|
diffWidget->setCaption( i18n( "Diff Output" ) );
|
|
|
|
TQWhatsThis::add(diffWidget, i18n("<b>Difference viewer</b><p>Shows output of the diff format. "
|
|
|
|
"Can utilize every installed component that is able to show diff output. "
|
|
|
|
"For example if you have Kompare installed, Difference Viewer can use its graphical diff view."));
|
|
|
|
mainWindow()->embedOutputView( diffWidget, nm, i18n("Output of the diff command") );
|
|
|
|
mainWindow()->setViewAvailable( diffWidget, false );
|
|
|
|
|
|
|
|
KAction *action = new KAction( i18n("Difference Viewer..."), 0,
|
|
|
|
this, TQT_SLOT(slotExecDiff()),
|
|
|
|
actionCollection(), "tools_diff" );
|
|
|
|
action->setToolTip(i18n("Difference viewer"));
|
|
|
|
action->setWhatsThis(i18n("<b>Difference viewer</b><p>Shows the contents of a patch file."));
|
|
|
|
|
|
|
|
connect( core(), TQT_SIGNAL(contextMenu(TQPopupMenu *, const Context *)),
|
|
|
|
this, TQT_SLOT(contextMenu(TQPopupMenu *, const Context *)) );
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool urlIsEqual(const KURL &a, const KURL &b)
|
|
|
|
{
|
|
|
|
if (a.isLocalFile() && b.isLocalFile())
|
|
|
|
{
|
|
|
|
struct stat aStat, bStat;
|
|
|
|
|
|
|
|
if ((::stat(TQFile::encodeName(a.fileName()), &aStat) == 0)
|
|
|
|
&& (::stat(TQFile::encodeName(b.fileName()), &bStat) == 0))
|
|
|
|
{
|
|
|
|
return (aStat.st_dev == bStat.st_dev) && (aStat.st_ino == bStat.st_ino);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static KParts::ReadWritePart* partForURL(const KURL &url, KDevPartController* pc)
|
|
|
|
{
|
|
|
|
if ( !pc )
|
|
|
|
return 0;
|
|
|
|
TQPtrListIterator<KParts::Part> it(*(pc->parts()));
|
|
|
|
for ( ; it.current(); ++it)
|
|
|
|
{
|
|
|
|
KParts::ReadWritePart *rw_part = dynamic_cast<KParts::ReadWritePart*>(it.current());
|
|
|
|
if ( rw_part && dynamic_cast<KTextEditor::EditInterface*>(it.current()) && urlIsEqual(url, rw_part->url()) )
|
|
|
|
return rw_part;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::contextMenu( TQPopupMenu* popup, const Context* context )
|
|
|
|
{
|
|
|
|
if ( context->hasType( Context::EditorContext ) )
|
|
|
|
{
|
|
|
|
const EditorContext *eContext = static_cast<const EditorContext*>(context);
|
|
|
|
popupFile = eContext->url();
|
|
|
|
}
|
|
|
|
else if ( context->hasType( Context::FileContext ) )
|
|
|
|
{
|
|
|
|
const FileContext * fContext = static_cast<const FileContext*>( context );
|
|
|
|
popupFile.setPath( fContext->urls().first().fileName() ); //@fixme - assuming absolute path. is this correct?
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KParts::ReadWritePart* rw_part = partForURL( popupFile, partController() );
|
|
|
|
if ( !rw_part ) return;
|
|
|
|
|
|
|
|
if ( partController()->documentState( rw_part->url() ) != Clean )
|
|
|
|
{
|
|
|
|
int id = popup->insertItem( i18n( "Difference to Disk File" ),
|
|
|
|
this, TQT_SLOT(localDiff()) );
|
|
|
|
popup->TQMenuData::setWhatsThis(id, i18n("<b>Difference to disk file</b><p>Shows the difference between "
|
|
|
|
"the file contents in this editor and the file contents on disk."));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DiffPart::~DiffPart()
|
|
|
|
{
|
|
|
|
if ( diffWidget )
|
|
|
|
mainWindow()->removeView( diffWidget );
|
|
|
|
|
|
|
|
delete proc;
|
|
|
|
delete (DiffWidget*) diffWidget;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::localDiff()
|
|
|
|
{
|
|
|
|
KParts::ReadWritePart* rw_part = partForURL( popupFile, partController() );
|
|
|
|
if ( !rw_part )
|
|
|
|
return;
|
|
|
|
|
|
|
|
KTextEditor::EditInterface* editIface = dynamic_cast<KTextEditor::EditInterface*>(rw_part);
|
|
|
|
if ( !editIface )
|
|
|
|
return;
|
|
|
|
buffer = editIface->text().local8Bit();
|
|
|
|
resultBuffer = resultErr = TQString();
|
|
|
|
|
|
|
|
delete proc;
|
|
|
|
proc = new KProcess();
|
|
|
|
|
|
|
|
*proc << "diff";
|
|
|
|
*proc << "-u" << popupFile.path() << "-";
|
|
|
|
proc->setWorkingDirectory( popupFile.directory() );
|
|
|
|
|
|
|
|
connect( proc, TQT_SIGNAL(processExited( KProcess* )),
|
|
|
|
this, TQT_SLOT(processExited( KProcess* )) );
|
|
|
|
connect( proc, TQT_SIGNAL(receivedStdout( KProcess*, char*, int )),
|
|
|
|
this, TQT_SLOT(receivedStdout( KProcess*, char*, int )) );
|
|
|
|
connect( proc, TQT_SIGNAL(receivedStderr( KProcess*, char*, int )),
|
|
|
|
this, TQT_SLOT(receivedStderr( KProcess*, char*, int )) );
|
|
|
|
connect( proc, TQT_SIGNAL(wroteStdin( KProcess* )),
|
|
|
|
this, TQT_SLOT(wroteStdin( KProcess* )) );
|
|
|
|
|
|
|
|
if ( !proc->start( KProcess::NotifyOnExit, KProcess::All ) ) {
|
|
|
|
KMessageBox::error( 0, i18n( "Could not invoke the \"diff\" command." ) );
|
|
|
|
delete proc;
|
|
|
|
proc = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
proc->writeStdin( buffer.data(), buffer.length() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::processExited( KProcess* p )
|
|
|
|
{
|
|
|
|
// diff has exit status 0 and 1 for success
|
|
|
|
if ( p->normalExit() && ( p->exitStatus() == 0 || p->exitStatus() == 1 ) ) {
|
|
|
|
if ( resultBuffer.isEmpty() )
|
|
|
|
KMessageBox::information( 0, i18n("DiffPart: No differences found.") );
|
|
|
|
else
|
|
|
|
showDiff( resultBuffer );
|
|
|
|
} else {
|
|
|
|
KMessageBox::error( 0, i18n("Diff command failed (%1):\n").tqarg( p->exitStatus() ) + resultErr );
|
|
|
|
}
|
|
|
|
resultBuffer = resultErr = TQString();
|
|
|
|
delete proc;
|
|
|
|
proc = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::receivedStdout( KProcess* /* p */, char* buf, int buflen )
|
|
|
|
{
|
|
|
|
resultBuffer += TQString::fromLocal8Bit( buf, buflen );
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::receivedStderr( KProcess* /* p */, char* buf, int buflen )
|
|
|
|
{
|
|
|
|
kdDebug(9033) << "received Stderr: " << TQString(TQString::fromLocal8Bit( buf, buflen )).ascii() << endl;
|
|
|
|
resultErr += TQString::fromLocal8Bit( buf, buflen );
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::wroteStdin( KProcess* p )
|
|
|
|
{
|
|
|
|
buffer = 0L;
|
|
|
|
p->closeStdin();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::openURL( const KURL& url )
|
|
|
|
{
|
|
|
|
diffWidget->slotClear();
|
|
|
|
diffWidget->openURL( url );
|
|
|
|
mainWindow()->raiseView( diffWidget );
|
|
|
|
/*
|
|
|
|
DiffDlg* diffDlg = new DiffDlg( 0, "diffDlg" );
|
|
|
|
|
|
|
|
diffDlg->openURL( url );
|
|
|
|
diffDlg->exec();
|
|
|
|
delete diffDlg;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::showDiff( const TQString& diff )
|
|
|
|
{
|
|
|
|
diffWidget->slotClear();
|
|
|
|
diffWidget->setDiff( diff );
|
|
|
|
mainWindow()->setViewAvailable( diffWidget, true );
|
|
|
|
mainWindow()->raiseView( diffWidget );
|
|
|
|
/*
|
|
|
|
DiffDlg* diffDlg = new DiffDlg( 0, "diffDlg" );
|
|
|
|
|
|
|
|
diffDlg->setDiff( diff );
|
|
|
|
diffDlg->exec();
|
|
|
|
delete diffDlg;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiffPart::slotExecDiff()
|
|
|
|
{
|
|
|
|
KURL url = KFileDialog::getOpenURL( TQString(), TQString(), 0, i18n("Please Select Patch File") );
|
|
|
|
|
|
|
|
if ( url.isEmpty() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
openURL( url );
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "diffpart.moc"
|