00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <sys/stat.h>
00013
00014 #include <qwhatsthis.h>
00015 #include <qpopupmenu.h>
00016
00017 #include <klocale.h>
00018 #include <kdevgenericfactory.h>
00019 #include <kaction.h>
00020 #include <kfiledialog.h>
00021 #include <kprocess.h>
00022 #include <kio/jobclasses.h>
00023 #include <kio/job.h>
00024 #include <kparts/part.h>
00025 #include <ktexteditor/editinterface.h>
00026 #include <kmessagebox.h>
00027 #include <kdebug.h>
00028 #include <kiconloader.h>
00029
00030 #include "kdevcore.h"
00031 #include "kdevmainwindow.h"
00032 #include "kdevpartcontroller.h"
00033
00034 #include "diffpart.h"
00035 #include "diffdlg.h"
00036 #include "diffwidget.h"
00037
00038 static const KAboutData data("kdevdiff", I18N_NOOP("Difference Viewer"), "1.0");
00039
00040 typedef KDevGenericFactory<DiffPart> DiffFactory;
00041 K_EXPORT_COMPONENT_FACTORY( libkdevdiff, DiffFactory( &data ) )
00042
00043 DiffPart::DiffPart(QObject *parent, const char *name, const QStringList &)
00044 : KDevDiffFrontend("Diff", "diff", parent, name ? name : "DiffPart"), proc(0)
00045 {
00046 setInstance(DiffFactory::instance());
00047 setXMLFile("kdevdiff.rc");
00048
00049 diffWidget = new DiffWidget();
00050 diffWidget->setIcon( SmallIcon("editcopy") );
00051 QString nm( i18n( "Diff" ) );
00052 diffWidget->setCaption( i18n( "Diff Output" ) );
00053 QWhatsThis::add(diffWidget, i18n("<b>Difference viewer</b><p>Shows output of the diff format. "
00054 "Can utilize every installed component that is able to show diff output. "
00055 "For example if you have Kompare installed, Difference Viewer can use its graphical diff view."));
00056 mainWindow()->embedOutputView( diffWidget, nm, i18n("Output of the diff command") );
00057
00058 KAction *action = new KAction( i18n("Difference Viewer..."), 0,
00059 this, SLOT(slotExecDiff()),
00060 actionCollection(), "tools_diff" );
00061 action->setToolTip(i18n("Difference viewer"));
00062 action->setWhatsThis(i18n("<b>Difference viewer</b><p>Shows the contents of a patch file."));
00063
00064 connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
00065 this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
00066 }
00067
00068 static bool urlIsEqual(const KURL &a, const KURL &b)
00069 {
00070 if (a.isLocalFile() && b.isLocalFile())
00071 {
00072 struct stat aStat, bStat;
00073
00074 if ((::stat(QFile::encodeName(a.fileName()), &aStat) == 0)
00075 && (::stat(QFile::encodeName(b.fileName()), &bStat) == 0))
00076 {
00077 return (aStat.st_dev == bStat.st_dev) && (aStat.st_ino == bStat.st_ino);
00078 }
00079 }
00080
00081 return a == b;
00082 }
00083
00084 static KParts::ReadWritePart* partForURL(const KURL &url, KDevPartController* pc)
00085 {
00086 if ( !pc )
00087 return 0;
00088 QPtrListIterator<KParts::Part> it(*(pc->parts()));
00089 for ( ; it.current(); ++it)
00090 {
00091 KParts::ReadWritePart *rw_part = dynamic_cast<KParts::ReadWritePart*>(it.current());
00092 if ( rw_part && dynamic_cast<KTextEditor::EditInterface*>(it.current()) && urlIsEqual(url, rw_part->url()) )
00093 return rw_part;
00094 }
00095
00096 return 0;
00097 }
00098
00099 void DiffPart::contextMenu( QPopupMenu* popup, const Context* context )
00100 {
00101 if ( context->hasType( Context::EditorContext ) )
00102 {
00103 const EditorContext *eContext = static_cast<const EditorContext*>(context);
00104 popupFile = eContext->url();
00105 }
00106 else if ( context->hasType( Context::FileContext ) )
00107 {
00108 const FileContext * fContext = static_cast<const FileContext*>( context );
00109 popupFile.setPath( fContext->fileName() );
00110 }
00111 else
00112 {
00113 return;
00114 }
00115
00116 KParts::ReadWritePart* rw_part = partForURL( popupFile, partController() );
00117 if ( !rw_part ) return;
00118
00119 if ( partController()->documentState( rw_part->url() ) != Clean )
00120 {
00121 int id = popup->insertItem( i18n( "Difference to Disk File" ),
00122 this, SLOT(localDiff()) );
00123 popup->setWhatsThis(id, i18n("<b>Difference to disk file</b><p>Shows the difference between "
00124 "the file contents in this editor and the file contents on disk."));
00125 }
00126 }
00127
00128 DiffPart::~DiffPart()
00129 {
00130 if ( diffWidget )
00131 mainWindow()->removeView( diffWidget );
00132
00133 delete proc;
00134 delete (DiffWidget*) diffWidget;
00135 }
00136
00137 void DiffPart::localDiff()
00138 {
00139 KParts::ReadWritePart* rw_part = partForURL( popupFile, partController() );
00140 if ( !rw_part )
00141 return;
00142
00143 KTextEditor::EditInterface* editIface = dynamic_cast<KTextEditor::EditInterface*>(rw_part);
00144 if ( !editIface )
00145 return;
00146 buffer = editIface->text().local8Bit();
00147 resultBuffer = resultErr = QString::null;
00148
00149 delete proc;
00150 proc = new KProcess();
00151
00152 *proc << "diff";
00153 *proc << "-u" << popupFile.path() << "-";
00154 proc->setWorkingDirectory( popupFile.directory() );
00155
00156 connect( proc, SIGNAL(processExited( KProcess* )),
00157 this, SLOT(processExited( KProcess* )) );
00158 connect( proc, SIGNAL(receivedStdout( KProcess*, char*, int )),
00159 this, SLOT(receivedStdout( KProcess*, char*, int )) );
00160 connect( proc, SIGNAL(receivedStderr( KProcess*, char*, int )),
00161 this, SLOT(receivedStderr( KProcess*, char*, int )) );
00162 connect( proc, SIGNAL(wroteStdin( KProcess* )),
00163 this, SLOT(wroteStdin( KProcess* )) );
00164
00165 if ( !proc->start( KProcess::NotifyOnExit, KProcess::All ) ) {
00166 KMessageBox::error( 0, i18n( "Could not invoke the \"diff\" command." ) );
00167 delete proc;
00168 proc = 0;
00169 return;
00170 }
00171 proc->writeStdin( buffer.data(), buffer.length() );
00172 }
00173
00174 void DiffPart::processExited( KProcess* p )
00175 {
00176
00177 if ( p->normalExit() && ( p->exitStatus() == 0 || p->exitStatus() == 1 ) ) {
00178 if ( resultBuffer.isEmpty() )
00179 KMessageBox::information( 0, i18n("DiffPart: No differences found.") );
00180 else
00181 showDiff( resultBuffer );
00182 } else {
00183 KMessageBox::error( 0, i18n("Diff command failed (%1):\n").arg( p->exitStatus() ) + resultErr );
00184 }
00185 resultBuffer = resultErr = QString::null;
00186 delete proc;
00187 proc = 0;
00188 }
00189
00190 void DiffPart::receivedStdout( KProcess* , char* buf, int buflen )
00191 {
00192 resultBuffer += QString::fromLocal8Bit( buf, buflen );
00193 }
00194
00195 void DiffPart::receivedStderr( KProcess* , char* buf, int buflen )
00196 {
00197 kdDebug(9033) << "received Stderr: " << QString::fromLocal8Bit( buf, buflen ) << endl;
00198 resultErr += QString::fromLocal8Bit( buf, buflen );
00199 }
00200
00201 void DiffPart::wroteStdin( KProcess* p )
00202 {
00203 buffer = 0L;
00204 p->closeStdin();
00205 }
00206
00207 void DiffPart::openURL( const KURL& url )
00208 {
00209 diffWidget->slotClear();
00210 diffWidget->openURL( url );
00211 mainWindow()->raiseView( diffWidget );
00212
00213
00214
00215
00216
00217
00218
00219 }
00220
00221 void DiffPart::showDiff( const QString& diff )
00222 {
00223 diffWidget->slotClear();
00224 diffWidget->setDiff( diff );
00225 mainWindow()->raiseView( diffWidget );
00226
00227
00228
00229
00230
00231
00232
00233 }
00234
00235 void DiffPart::slotExecDiff()
00236 {
00237 KURL url = KFileDialog::getOpenURL( QString::null, QString::null, 0, i18n("Please Select Patch File") );
00238
00239 if ( url.isEmpty() )
00240 return;
00241
00242 openURL( url );
00243 }
00244
00245 #include "diffpart.moc"