00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <qlayout.h>
00013 #include <qtextedit.h>
00014 #include <qpopupmenu.h>
00015 #include <qcursor.h>
00016 #include <qfile.h>
00017
00018 #include <kconfig.h>
00019 #include <kapplication.h>
00020 #include <klocale.h>
00021 #include <kservice.h>
00022 #include <ktempfile.h>
00023 #include <kpopupmenu.h>
00024 #include <kiconloader.h>
00025 #include <kfiledialog.h>
00026 #include <kmessagebox.h>
00027
00028 #include <kparts/componentfactory.h>
00029 #include <kparts/part.h>
00030
00031 #include <kio/jobclasses.h>
00032 #include <kio/job.h>
00033
00034 #include "diffwidget.h"
00035
00036
00037 static const int POPUP_BASE = 130977;
00038
00039 QStringList KDiffTextEdit::extParts;
00040 QStringList KDiffTextEdit::extPartsTranslated;
00041
00042 KDiffTextEdit::KDiffTextEdit( QWidget* parent, const char* name ): QTextEdit( parent, name )
00043 {
00044 KConfig* config = kapp->config();
00045 config->setGroup( "Diff" );
00046 _highlight = config->readBoolEntry( "Highlight", true );
00047
00048 searchExtParts();
00049 }
00050
00051 KDiffTextEdit::~KDiffTextEdit()
00052 {
00053 KConfig* config = kapp->config();
00054
00055 config->setGroup( "Diff" );
00056 config->writeEntry( "Highlight", _highlight );
00057 }
00058
00059 QPopupMenu* KDiffTextEdit::createPopupMenu()
00060 {
00061 return createPopupMenu( QPoint() );
00062 }
00063
00064 QPopupMenu* KDiffTextEdit::createPopupMenu( const QPoint& p )
00065 {
00066 QPopupMenu* popup = QTextEdit::createPopupMenu( p );
00067 if ( !popup )
00068 popup = new QPopupMenu( this );
00069
00070 int i = 0;
00071
00072 for ( QStringList::Iterator it = extPartsTranslated.begin(); it != extPartsTranslated.end(); ++it ) {
00073 popup->insertItem( i18n( "Show in %1" ).arg( *it ), i + POPUP_BASE, i );
00074 i++;
00075 }
00076 if ( !extPartsTranslated.isEmpty() )
00077 popup->insertSeparator( i );
00078 connect( popup, SIGNAL(activated(int)), this, SLOT(popupActivated(int)) );
00079
00080 popup->insertItem( SmallIconSet( "filesaveas" ), i18n( "&Save As..." ), this, SLOT(saveAs()), CTRL + Key_S, POPUP_BASE - 2, 0 );
00081 popup->setItemEnabled( POPUP_BASE - 2, length() > 0 );
00082
00083 popup->insertSeparator( 1 );
00084
00085 popup->insertItem( i18n( "Highlight Syntax" ), this, SLOT(toggleSyntaxHighlight()), 0, POPUP_BASE - 1, 2 );
00086 popup->setItemChecked( POPUP_BASE - 1, _highlight );
00087 popup->insertSeparator( 3 );
00088
00089 return popup;
00090 }
00091
00092 void KDiffTextEdit::saveAs()
00093 {
00094 QString fName = KFileDialog::getSaveFileName();
00095 if ( fName.isEmpty() )
00096 return;
00097
00098 QFile f( fName );
00099 if ( f.open( IO_WriteOnly ) ) {
00100 QTextStream stream( &f );
00101 int pCount = paragraphs();
00102 for ( int i = 0; i < pCount; ++i )
00103 stream << text( i ) << "\n";
00104 f.close();
00105 } else {
00106 KMessageBox::sorry( 0, i18n("Unable to open file."), i18n("Diff Frontend") );
00107 }
00108 }
00109
00110 void KDiffTextEdit::toggleSyntaxHighlight()
00111 {
00112 _highlight = !_highlight;
00113 if ( _highlight )
00114 applySyntaxHighlight();
00115 else
00116 clearSyntaxHighlight();
00117 }
00118
00119 void KDiffTextEdit::applySyntaxHighlight()
00120 {
00121
00122 static QColor cAdded( 190, 190, 237);
00123 static QColor cRemoved( 190, 237, 190 );
00124
00125 if ( !_highlight )
00126 return;
00127
00128 int paragCount = paragraphs();
00129 for ( int i = 0; i < paragCount; ++i ) {
00130 QString txt = text( i );
00131 if ( txt.length() > 0 ) {
00132 if ( txt.startsWith( "+" ) || txt.startsWith( ">" ) ) {
00133 setParagraphBackgroundColor( i, cAdded );
00134 } else if ( txt.startsWith( "-" ) || txt.startsWith( "<" ) ) {
00135 setParagraphBackgroundColor( i, cRemoved );
00136 }
00137 }
00138 }
00139 }
00140
00141 void KDiffTextEdit::clearSyntaxHighlight()
00142 {
00143 int paragCount = paragraphs();
00144 for ( int i = 0; i < paragCount; ++i ) {
00145 clearParagraphBackground( i );
00146 }
00147 }
00148
00149 void KDiffTextEdit::searchExtParts()
00150 {
00151
00152 static bool init = false;
00153 if ( init )
00154 return;
00155 init = true;
00156
00157
00158 KTrader::OfferList offers = KTrader::self()->query("text/x-diff", "('KParts/ReadOnlyPart' in ServiceTypes) and ('text/x-diff' in ServiceTypes)");
00159 KTrader::OfferList::const_iterator it;
00160 for ( it = offers.begin(); it != offers.end(); ++it ) {
00161 KService::Ptr ptr = (*it);
00162 extPartsTranslated << ptr->name();
00163 extParts << ptr->desktopEntryName();
00164 }
00165 return;
00166 }
00167
00168 void KDiffTextEdit::popupActivated( int id )
00169 {
00170 id -= POPUP_BASE;
00171 if ( id < 0 || id > (int)extParts.count() )
00172 return;
00173
00174 emit externalPartRequested( extParts[ id ] );
00175 }
00176
00177 DiffWidget::DiffWidget( QWidget *parent, const char *name, WFlags f ):
00178 QWidget( parent, name, f ), tempFile( 0 )
00179 {
00180 job = 0;
00181 extPart = 0;
00182
00183 te = new KDiffTextEdit( this, "Main Diff Viewer" );
00184 te->setReadOnly( true );
00185 te->setTextFormat( QTextEdit::PlainText );
00186
00187 connect( te, SIGNAL(externalPartRequested(const QString&)), this, SLOT(loadExtPart(const QString&)) );
00188
00189 QVBoxLayout* layout = new QVBoxLayout( this );
00190 layout->addWidget( te );
00191 }
00192
00193 DiffWidget::~DiffWidget()
00194 {
00195 delete tempFile;
00196 }
00197
00198 void DiffWidget::setExtPartVisible( bool visible )
00199 {
00200 if ( !extPart || !extPart->widget() ) {
00201 te->show();
00202 return;
00203 }
00204 if ( visible ) {
00205 te->hide();
00206 extPart->widget()->show();
00207 } else {
00208 te->show();
00209 extPart->widget()->hide();
00210 }
00211 }
00212
00213 void DiffWidget::loadExtPart( const QString& partName )
00214 {
00215 if ( extPart ) {
00216 setExtPartVisible( false );
00217 delete extPart;
00218 extPart = 0;
00219 }
00220
00221 KService::Ptr extService = KService::serviceByDesktopName( partName );
00222 if ( !extService )
00223 return;
00224
00225 extPart = KParts::ComponentFactory::createPartInstanceFromService<KParts::ReadOnlyPart>( extService, this, 0, this, 0 );
00226 if ( !extPart || !extPart->widget() )
00227 return;
00228
00229 layout()->add( extPart->widget() );
00230
00231 setExtPartVisible( true );
00232
00233 if ( te->paragraphs() > 0 )
00234 populateExtPart();
00235 }
00236
00237 void DiffWidget::slotClear()
00238 {
00239 te->clear();
00240 if ( extPart )
00241 extPart->closeURL();
00242 }
00243
00244
00245 void DiffWidget::slotAppend( const QString& str )
00246 {
00247 te->append( str );
00248 }
00249
00250
00251 void DiffWidget::slotAppend( KIO::Job*, const QByteArray& ba )
00252 {
00253 slotAppend( QString( ba ) );
00254 }
00255
00256 void DiffWidget::populateExtPart()
00257 {
00258 if ( !extPart )
00259 return;
00260
00261 bool ok = false;
00262 int paragCount = te->paragraphs();
00263 if ( extPart->openStream( "text/plain", KURL() ) ) {
00264 for ( int i = 0; i < paragCount; ++i )
00265 extPart->writeStream( te->text( i ).local8Bit() );
00266 ok = extPart->closeStream();
00267 } else {
00268
00269 delete tempFile;
00270 tempFile = new KTempFile();
00271 tempFile->setAutoDelete( true );
00272 for ( int i = 0; i < paragCount; ++i )
00273 *(tempFile->textStream()) << te->text( i ) << endl;
00274 tempFile->close();
00275 ok = extPart->openURL( KURL( tempFile->name() ) );
00276 }
00277 if ( !ok )
00278 setExtPartVisible( false );
00279 }
00280
00281
00282 void DiffWidget::slotFinished()
00283 {
00284 te->applySyntaxHighlight();
00285 populateExtPart();
00286 }
00287
00288 void DiffWidget::setDiff( const QString& diff )
00289 {
00290 slotClear();
00291 slotAppend( diff );
00292 slotFinished();
00293 }
00294
00295 void DiffWidget::openURL( const KURL& url )
00296 {
00297 if ( job )
00298 job->kill();
00299
00300 KIO::TransferJob* job = KIO::get( url );
00301 if ( !job )
00302 return;
00303
00304 connect( job, SIGNAL(data( KIO::Job *, const QByteArray & )),
00305 this, SLOT(slotAppend( KIO::Job*, const QByteArray& )) );
00306 connect( job, SIGNAL(result( KIO::Job * )),
00307 this, SLOT(slotFinished()) );
00308 }
00309
00310 void DiffWidget::contextMenuEvent( QContextMenuEvent* )
00311 {
00312 QPopupMenu* popup = new QPopupMenu( this );
00313
00314 if ( !te->isVisible() )
00315 popup->insertItem( i18n("Display &Raw Output"), this, SLOT(showTextEdit()) );
00316
00317 popup->exec( QCursor::pos() );
00318 delete popup;
00319 }
00320
00321 void DiffWidget::showExtPart()
00322 {
00323 setExtPartVisible( true );
00324 }
00325
00326 void DiffWidget::showTextEdit()
00327 {
00328 setExtPartVisible( false );
00329 }
00330
00331 #include "diffwidget.moc"