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.
tdevelop/parts/diff/diffpart.cpp

249 lines
7.6 KiB

/***************************************************************************
* 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"