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(
"Difference Viewer" ) );
00052 diffWidget->setCaption( nm );
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 it's 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
return;
00103
00104
const EditorContext *eContext = static_cast<const EditorContext*>(context);
00105
popupFile = eContext->
url();
00106
00107
if ( !
popupFile.
isLocalFile() )
00108
return;
00109
00110
KParts::ReadWritePart* rw_part =
partForURL(
popupFile,
partController() );
00111
if ( !rw_part || !rw_part->
isModified() )
00112
return;
00113
00114
int id = popup->insertItem( i18n(
"Difference to Saved File" ),
00115
this, SLOT(
localDiff()) );
00116 popup->setWhatsThis(
id, i18n(
"<b>Difference to saved file</b><p>Shows the difference between "
00117
"the file contents in editor and file contents saved on a disk."));
00118 }
00119
00120 DiffPart::~DiffPart()
00121 {
00122
if (
diffWidget )
00123
mainWindow()->
removeView(
diffWidget );
00124
00125
delete proc;
00126
delete (
DiffWidget*)
diffWidget;
00127 }
00128
00129 void DiffPart::localDiff()
00130 {
00131
KParts::ReadWritePart* rw_part =
partForURL(
popupFile,
partController() );
00132
if ( !rw_part )
00133
return;
00134
00135
KTextEditor::EditInterface* editIface = dynamic_cast<KTextEditor::EditInterface*>(rw_part);
00136
if ( !editIface )
00137
return;
00138
buffer = editIface->
text().local8Bit();
00139
resultBuffer =
resultErr = QString::null;
00140
00141
delete proc;
00142
proc =
new KProcess();
00143
00144 *
proc <<
"diff";
00145 *
proc <<
"-u" <<
popupFile.
path() <<
"-";
00146
proc->
setWorkingDirectory(
popupFile.
directory() );
00147
00148 connect(
proc, SIGNAL(
processExited( KProcess* )),
00149
this, SLOT(
processExited( KProcess* )) );
00150 connect(
proc, SIGNAL(
receivedStdout( KProcess*,
char*,
int )),
00151
this, SLOT(
receivedStdout( KProcess*,
char*,
int )) );
00152 connect(
proc, SIGNAL(
receivedStderr( KProcess*,
char*,
int )),
00153
this, SLOT(
receivedStderr( KProcess*,
char*,
int )) );
00154 connect(
proc, SIGNAL(
wroteStdin( KProcess* )),
00155
this, SLOT(
wroteStdin( KProcess* )) );
00156
00157
if ( !
proc->
start( KProcess::NotifyOnExit, KProcess::All ) ) {
00158 KMessageBox::error( 0, i18n(
"Could not invoke the \"diff\" command." ) );
00159
delete proc;
00160
proc = 0;
00161
return;
00162 }
00163
proc->
writeStdin(
buffer.data(),
buffer.length() );
00164 }
00165
00166 void DiffPart::processExited(
KProcess* p )
00167 {
00168
00169
if ( p->
normalExit() && ( p->
exitStatus() == 0 || p->
exitStatus() == 1 ) ) {
00170
if (
resultBuffer.isEmpty() )
00171 KMessageBox::information( 0, i18n(
"DiffPart: No differences found.") );
00172
else
00173
showDiff(
resultBuffer );
00174 }
else {
00175 KMessageBox::error( 0, i18n(
"Diff command failed (%1):\n").arg( p->
exitStatus() ) +
resultErr );
00176 }
00177
resultBuffer =
resultErr = QString::null;
00178
delete proc;
00179
proc = 0;
00180 }
00181
00182 void DiffPart::receivedStdout(
KProcess* ,
char* buf,
int buflen )
00183 {
00184
resultBuffer += QString::fromLocal8Bit( buf, buflen );
00185 }
00186
00187 void DiffPart::receivedStderr(
KProcess* ,
char* buf,
int buflen )
00188 {
00189
kdDebug(9033) <<
"received Stderr: " << QString::fromLocal8Bit( buf, buflen ) <<
endl;
00190
resultErr += QString::fromLocal8Bit( buf, buflen );
00191 }
00192
00193 void DiffPart::wroteStdin(
KProcess* p )
00194 {
00195
buffer = 0L;
00196 p->
closeStdin();
00197 }
00198
00199 void DiffPart::openURL(
const KURL& url )
00200 {
00201
diffWidget->slotClear();
00202
diffWidget->openURL( url );
00203
mainWindow()->
raiseView(
diffWidget );
00204
00205
00206
00207
00208
00209
00210
00211 }
00212
00213 void DiffPart::showDiff(
const QString& diff )
00214 {
00215
diffWidget->slotClear();
00216
diffWidget->setDiff( diff );
00217
mainWindow()->
raiseView(
diffWidget );
00218
00219
00220
00221
00222
00223
00224
00225 }
00226
00227 void DiffPart::slotExecDiff()
00228 {
00229
KURL url = KFileDialog::getOpenURL( QString::null, QString::null, 0, i18n(
"Please Select Patch File") );
00230
00231
if ( url.
isEmpty() )
00232
return;
00233
00234
openURL( url );
00235 }
00236
00237
#include "diffpart.moc"