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/vcs/cvsservice/diffwidget.cpp

332 lines
8.3 KiB

/***************************************************************************
* Copyright (C) 2001 by Harald Fernengel *
* harry@tdevelop.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 <tqlayout.h>
#include <tqtextedit.h>
#include <tqpopupmenu.h>
#include <tqcursor.h>
#include <tqfile.h>
#include <kconfig.h>
#include <kapplication.h>
#include <klocale.h>
#include <kservice.h>
#include <ktempfile.h>
#include <kpopupmenu.h>
#include <kiconloader.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <kparts/componentfactory.h>
#include <kparts/part.h>
#include <kio/jobclasses.h>
#include <kio/job.h>
#include "diffwidget.h"
// yup, magic value for the popupmenu-id
static const int POPUP_BASE = 130977;
TQStringList KDiffTextEdit::extParts;
TQStringList KDiffTextEdit::extPartsTranslated;
KDiffTextEdit::KDiffTextEdit( TQWidget* parent, const char* name ): TQTextEdit( parent, name )
{
KConfig* config = kapp->config();
config->setGroup( "Diff" );
_highlight = config->readBoolEntry( "Highlight", true );
searchExtParts();
}
KDiffTextEdit::~KDiffTextEdit()
{
KConfig* config = kapp->config();
config->setGroup( "Diff" );
config->writeEntry( "Highlight", _highlight );
}
TQPopupMenu* KDiffTextEdit::createPopupMenu()
{
return createPopupMenu( TQPoint() );
}
TQPopupMenu* KDiffTextEdit::createPopupMenu( const TQPoint& p )
{
TQPopupMenu* popup = TQTextEdit::createPopupMenu( p );
if ( !popup )
popup = new TQPopupMenu( this );
int i = 0;
for ( TQStringList::Iterator it = extPartsTranslated.begin(); it != extPartsTranslated.end(); ++it ) {
popup->insertItem( i18n( "Show in %1" ).arg( *it ), i + POPUP_BASE, i );
i++;
}
if ( !extPartsTranslated.isEmpty() )
popup->insertSeparator( i );
connect( popup, TQT_SIGNAL(activated(int)), this, TQT_SLOT(popupActivated(int)) );
popup->insertItem( SmallIconSet( "filesaveas" ), i18n( "&Save As..." ), this, TQT_SLOT(saveAs()), CTRL + Key_S, POPUP_BASE - 2, 0 );
popup->setItemEnabled( POPUP_BASE - 2, length() > 0 );
popup->insertSeparator( 1 );
popup->insertItem( i18n( "Highlight Syntax" ), this, TQT_SLOT(toggleSyntaxHighlight()), 0, POPUP_BASE - 1, 2 );
popup->setItemChecked( POPUP_BASE - 1, _highlight );
popup->insertSeparator( 3 );
return popup;
}
void KDiffTextEdit::saveAs()
{
TQString fName = KFileDialog::getSaveFileName();
if ( fName.isEmpty() )
return;
TQFile f( fName );
if ( f.open( IO_WriteOnly ) ) {
TQTextStream stream( &f );
int pCount = paragraphs();
for ( int i = 0; i < pCount; ++i )
stream << text( i ) << "\n";
f.close();
} else {
KMessageBox::sorry( this, i18n("Unable to open file."), i18n("Diff Frontend") );
}
}
void KDiffTextEdit::toggleSyntaxHighlight()
{
_highlight = !_highlight;
if ( _highlight )
applySyntaxHighlight();
else
clearSyntaxHighlight();
}
void KDiffTextEdit::applySyntaxHighlight()
{
// the diff has been loaded so we apply a simple highlighting
static TQColor cAdded( 190, 190, 237);
static TQColor cRemoved( 190, 237, 190 );
if ( !_highlight )
return;
int paragCount = paragraphs();
for ( int i = 0; i < paragCount; ++i ) {
TQString txt = text( i );
if ( txt.length() > 0 ) {
if ( txt.startsWith( "+" ) || txt.startsWith( ">" ) ) {
setParagraphBackgroundColor( i, cAdded );
} else if ( txt.startsWith( "-" ) || txt.startsWith( "<" ) ) {
setParagraphBackgroundColor( i, cRemoved );
}
}
}
}
void KDiffTextEdit::clearSyntaxHighlight()
{
int paragCount = paragraphs();
for ( int i = 0; i < paragCount; ++i ) {
clearParagraphBackground( i );
}
}
void KDiffTextEdit::searchExtParts()
{
// only execute once
static bool init = false;
if ( init )
return;
init = true;
// search all parts that can handle text/x-diff
KTrader::OfferList offers = KTrader::self()->query("text/x-diff", "('KParts/ReadOnlyPart' in ServiceTypes) and ('text/x-diff' in ServiceTypes)");
KTrader::OfferList::const_iterator it;
for ( it = offers.begin(); it != offers.end(); ++it ) {
KService::Ptr ptr = (*it);
extPartsTranslated << ptr->name();
extParts << ptr->desktopEntryName();
}
return;
}
void KDiffTextEdit::popupActivated( int id )
{
id -= POPUP_BASE;
if ( id < 0 || id > (int)extParts.count() )
return;
emit externalPartRequested( extParts[ id ] );
}
DiffWidget::DiffWidget( TQWidget *parent, const char *name, WFlags f ):
TQWidget( parent, name, f ), tempFile( 0 )
{
job = 0;
extPart = 0;
te = new KDiffTextEdit( this, "Main Diff Viewer" );
te->setReadOnly( true );
te->setTextFormat( TQTextEdit::PlainText );
// te->setMinimumSize( 300, 200 );
connect( te, TQT_SIGNAL(externalPartRequested(const TQString&)), this, TQT_SLOT(loadExtPart(const TQString&)) );
TQVBoxLayout* layout = new TQVBoxLayout( this );
layout->addWidget( te );
}
DiffWidget::~DiffWidget()
{
delete tempFile;
}
void DiffWidget::setExtPartVisible( bool visible )
{
if ( !extPart || !extPart->widget() ) {
te->show();
return;
}
if ( visible ) {
te->hide();
extPart->widget()->show();
} else {
te->show();
extPart->widget()->hide();
}
}
void DiffWidget::loadExtPart( const TQString& partName )
{
if ( extPart ) {
setExtPartVisible( false );
delete extPart;
extPart = 0;
}
KService::Ptr extService = KService::serviceByDesktopName( partName );
if ( !extService )
return;
extPart = KParts::ComponentFactory::createPartInstanceFromService<KParts::ReadOnlyPart>( extService, this, 0, TQT_TQOBJECT(this), 0 );
if ( !extPart || !extPart->widget() )
return;
layout()->add( extPart->widget() );
setExtPartVisible( true );
if ( te->paragraphs() > 0 )
populateExtPart();
}
void DiffWidget::slotClear()
{
te->clear();
if ( extPart )
extPart->closeURL();
}
// internally for the TextEdit only!
void DiffWidget::slotAppend( const TQString& str )
{
te->append( str );
}
// internally for the TextEdit only!
void DiffWidget::slotAppend( KIO::Job*, const TQByteArray& ba )
{
slotAppend( TQString( ba ) );
}
void DiffWidget::populateExtPart()
{
if ( !extPart )
return;
bool ok = false;
int paragCount = te->paragraphs();
if ( extPart->openStream( "text/plain", KURL() ) ) {
for ( int i = 0; i < paragCount; ++i )
extPart->writeStream( te->text( i ).local8Bit() );
ok = extPart->closeStream();
} else {
// workaround for parts that cannot handle streams
delete tempFile;
tempFile = new KTempFile();
tempFile->setAutoDelete( true );
for ( int i = 0; i < paragCount; ++i )
*(tempFile->textStream()) << te->text( i ) << endl;
tempFile->close();
ok = extPart->openURL( KURL( tempFile->name() ) );
}
if ( !ok )
setExtPartVisible( false );
}
// internally for the TextEdit only!
void DiffWidget::slotFinished()
{
te->applySyntaxHighlight();
populateExtPart();
}
void DiffWidget::setDiff( const TQString& diff )
{
slotClear();
slotAppend( diff );
slotFinished();
}
void DiffWidget::openURL( const KURL& url )
{
if ( job )
job->kill();
KIO::TransferJob* job = KIO::get( url );
if ( !job )
return;
connect( job, TQT_SIGNAL(data( KIO::Job *, const TQByteArray & )),
this, TQT_SLOT(slotAppend( KIO::Job*, const TQByteArray& )) );
connect( job, TQT_SIGNAL(result( KIO::Job * )),
this, TQT_SLOT(slotFinished()) );
}
void DiffWidget::contextMenuEvent( TQContextMenuEvent* /* e */ )
{
TQPopupMenu* popup = new TQPopupMenu( this );
if ( !te->isVisible() )
popup->insertItem( i18n("Display &Raw Output"), this, TQT_SLOT(showTextEdit()) );
popup->exec( TQCursor::pos() );
delete popup;
}
void DiffWidget::showExtPart()
{
setExtPartVisible( true );
}
void DiffWidget::showTextEdit()
{
setExtPartVisible( false );
}
#include "diffwidget.moc"