diff --git a/plugins/patchreview/patchhighlighter.cpp b/plugins/patchreview/patchhighlighter.cpp index 371df08667..7bbe44cf58 100644 --- a/plugins/patchreview/patchhighlighter.cpp +++ b/plugins/patchreview/patchhighlighter.cpp @@ -1,600 +1,600 @@ /*************************************************************************** Copyright 2006 David Nolden ***************************************************************************/ /*************************************************************************** * * * 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 "patchhighlighter.h" #include "libdiff2/difference.h" #include "patchreview.h" #include #include #include #include #include #include #include #include #include #include #include #include -#include -#include +#include +#include #include #include #include #include using namespace KDevelop; namespace { QPointer currentTooltip; KTextEditor::MovingRange* currentTooltipMark; QSize sizeHintForHtml( QString html, QSize maxSize ) { QTextDocument doc; doc.setHtml( html ); QSize ret; if( doc.idealWidth() > maxSize.width() ) { doc.setPageSize( QSize( maxSize.width(), 30 ) ); ret.setWidth( maxSize.width() ); }else{ ret.setWidth( doc.idealWidth() ); } ret.setHeight( doc.size().height() ); if( ret.height() > maxSize.height() ) ret.setHeight( maxSize.height() ); return ret; } } void PatchHighlighter::showToolTipForMark( QPoint pos, KTextEditor::MovingRange* markRange, QPair highlightMark ) { if( currentTooltipMark == markRange && currentTooltip ) return; delete currentTooltip; //Got the difference Diff2::Difference* diff = m_differencesForRanges[markRange]; QString html; #if 0 if( diff->hasConflict() ) html += i18n( "Conflict
" ); #endif Diff2::DifferenceStringList lines; if( m_plugin->patch()->isAlreadyApplied() && !diff->applied() ) html += i18n( "Reverted.
" ); else if( !m_plugin->patch()->isAlreadyApplied() && diff->applied() ) html += i18n( "Applied.
" ); if( diff->applied() ) { if( isInsertion( diff ) ) { html += i18n( "Insertion
" ); }else{ if( isRemoval( diff ) ) html += i18n( "Removal
" ); html += i18n( "Previous:
" ); lines = diff->sourceLines(); } }else{ if( isRemoval( diff ) ) { html += i18n( "Removal
" ); }else{ if( isInsertion( diff ) ) html += i18n( "Insertion
" ); html += i18n( "Alternative:
" ); lines = diff->destinationLines(); } } for( int a = 0; a < lines.size(); ++a ) { Diff2::DifferenceString* line = lines[a]; uint currentPos = 0; QString string = line->string(); Diff2::MarkerList markers = line->markerList(); for( int b = 0; b < markers.size(); ++b ) { QString spanText = Qt::escape( string.mid( currentPos, markers[b]->offset() - currentPos ) ); if( markers[b]->type() == Diff2::Marker::End && ( currentPos != 0 || markers[b]->offset() != static_cast( string.size() ) ) ) { if( a == highlightMark.first && b == highlightMark.second ) html += "" + spanText + ""; else html += "" + spanText + ""; }else{ html += spanText; } currentPos = markers[b]->offset(); } html += Qt::escape( string.mid( currentPos, string.length()-currentPos ) ); html += "
"; } KTextBrowser* browser = new KTextBrowser; browser->setPalette( QApplication::palette() ); browser->setHtml( html ); int maxHeight = 500; browser->setMinimumSize( sizeHintForHtml( html, QSize( ( ICore::self()->uiController()->activeMainWindow()->width()*2 )/3, maxHeight ) ) ); browser->setMaximumSize( browser->minimumSize() + QSize( 10, 10 ) ); if( browser->minimumHeight() != maxHeight ) browser->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); QVBoxLayout* layout = new QVBoxLayout; layout->setMargin( 0 ); layout->addWidget( browser ); KDevelop::ActiveToolTip* tooltip = new KDevelop::ActiveToolTip( ICore::self()->uiController()->activeMainWindow(), pos + QPoint( 5, -browser->sizeHint().height() - 30 ) ); tooltip->setLayout( layout ); tooltip->resize( tooltip->sizeHint() + QSize( 10, 10 ) ); tooltip->move( pos - QPoint( 0, 20 + tooltip->height() ) ); tooltip->addExtendRect( QRect( pos - QPoint( 15, 15 ), pos + QPoint( 15, 15 ) ) ); currentTooltip = tooltip; currentTooltipMark = markRange; ActiveToolTip::showToolTip( tooltip ); } void PatchHighlighter::markClicked( KTextEditor::Document* doc, KTextEditor::Mark mark, bool& handled ) { m_applying = true; if( handled ) return; handled = true; if( doc->activeView() ) ///This is a workaround, if the cursor is somewhere else, the editor will always jump there when a mark was clicked doc->activeView()->setCursorPosition( KTextEditor::Cursor( mark.line, 0 ) ); KTextEditor::MovingRange* range = rangeForMark( mark ); if( range ) { QString currentText = doc->text( range->toRange() ); Diff2::Difference* diff = m_differencesForRanges[range]; removeLineMarker( range ); QString sourceText; QString targetText; for( int a = 0; a < diff->sourceLineCount(); ++a ) { sourceText += diff->sourceLineAt( a )->string(); if( !sourceText.endsWith( "\n" ) ) sourceText += "\n"; } for( int a = 0; a < diff->destinationLineCount(); ++a ) { targetText += diff->destinationLineAt( a )->string(); if( !targetText.endsWith( "\n" ) ) targetText += "\n"; } QString replace; QString replaceWith; if( !diff->applied() ) { replace = sourceText; replaceWith = targetText; }else { replace = targetText; replaceWith = sourceText; } if( currentText.simplified() != replace.simplified() ) { KMessageBox::error( ICore::self()->uiController()->activeMainWindow(), i18n( "Could not apply the change: Text should be \"%1\", but is \"%2\".", replace, currentText ) ); return; } diff->apply( !diff->applied() ); KTextEditor::Cursor start = range->start().toCursor(); range->document()->replaceText( range->toRange(), replaceWith ); KTextEditor::Range newRange( start, start ); uint replaceWithLines = replaceWith.count( '\n' ); newRange.end().setLine( newRange.end().line() + replaceWithLines ); range->setRange( newRange ); addLineMarker( range, diff ); } { // After applying the change, show the tooltip again, mainly to update an old tooltip delete currentTooltip; bool h = false; markToolTipRequested( doc, mark, QCursor::pos(), h ); } m_applying = false; } KTextEditor::MovingRange* PatchHighlighter::rangeForMark( KTextEditor::Mark mark ) { for( QMap::const_iterator it = m_differencesForRanges.constBegin(); it != m_differencesForRanges.constEnd(); ++it ) { if( it.key()->start().line() == mark.line ) { return it.key(); } } return 0; } void PatchHighlighter::markToolTipRequested( KTextEditor::Document*, KTextEditor::Mark mark, QPoint pos, bool& handled ) { if( handled ) return; handled = true; int myMarksPattern = KTextEditor::MarkInterface::markType22 | KTextEditor::MarkInterface::markType23 | KTextEditor::MarkInterface::markType24 | KTextEditor::MarkInterface::markType25 | KTextEditor::MarkInterface::markType26 | KTextEditor::MarkInterface::markType27; if( mark.type & myMarksPattern ) { //There is a mark in this line. Show the old text. KTextEditor::MovingRange* range = rangeForMark( mark ); if( range ) showToolTipForMark( pos, range ); } } bool PatchHighlighter::isInsertion( Diff2::Difference* diff ) { return diff->sourceLineCount() == 0; } bool PatchHighlighter::isRemoval( Diff2::Difference* diff ) { return diff->destinationLineCount() == 0; } QStringList PatchHighlighter::splitAndAddNewlines( const QString& text ) const { QStringList result = text.split( '\n', QString::KeepEmptyParts ); for( QStringList::iterator iter = result.begin(); iter != result.end(); ++iter ) { iter->append( '\n' ); } if ( !result.isEmpty() ) { QString & last = result.last(); last.remove( last.size() - 1, 1 ); } return result; } void PatchHighlighter::performContentChange( KTextEditor::Document* doc, const QStringList& oldLines, const QStringList& newLines, int editLineNumber ) { QPair, QList > diffChange = m_model->linesChanged( oldLines, newLines, editLineNumber ); QList inserted = diffChange.first; QList removed = diffChange.second; // Remove all ranges that are in the same line (the line markers) foreach( KTextEditor::MovingRange* r, m_differencesForRanges.keys() ) { Diff2::Difference* diff = m_differencesForRanges[r]; if ( removed.contains( diff ) ) { removeLineMarker( r ); m_ranges.remove( r ); m_differencesForRanges.remove( r ); delete r; delete diff; } } KTextEditor::MovingInterface* moving = dynamic_cast( doc ); if ( !moving ) return; foreach( Diff2::Difference* diff, inserted ) { int lineStart = diff->destinationLineNumber(); if ( lineStart > 0 ) { --lineStart; } int lineEnd = diff->destinationLineEnd(); if ( lineEnd > 0 ) { --lineEnd; } KTextEditor::Range newRange( lineStart, 0, lineEnd, 0 ); KTextEditor::MovingRange * r = moving->newMovingRange( newRange ); m_differencesForRanges[r] = diff; m_ranges.insert( r ); addLineMarker( r, diff ); } } void PatchHighlighter::textRemoved( KTextEditor::Document* doc, const KTextEditor::Range& range, const QString& oldText ) { if ( m_applying ) { // Do not interfere with patch application return; } kDebug() << "removal range" << range; kDebug() << "removed text" << oldText; QStringList removedLines = splitAndAddNewlines( oldText ); int startLine = range.start().line(); QString remainingLine = doc->line( startLine ); remainingLine += '\n'; QString prefix = remainingLine.mid( 0, range.start().column() ); QString suffix = remainingLine.mid( range.start().column() ); if ( !removedLines.empty() ) { removedLines.first() = prefix + removedLines.first(); removedLines.last() = removedLines.last() + suffix; } performContentChange( doc, removedLines, QStringList() << remainingLine, startLine + 1 ); } void PatchHighlighter::textInserted( KTextEditor::Document* doc, const KTextEditor::Range& range ) { if( range == doc->documentRange() ) { kDebug() << "re-doing"; //The document was loaded / reloaded if ( !m_model->differences() ) return; KTextEditor::MovingInterface* moving = dynamic_cast( doc ); if ( !moving ) return; KTextEditor::MarkInterface* markIface = dynamic_cast( doc ); if( !markIface ) return; clear(); KColorScheme scheme( QPalette::Active ); QImage tintedInsertion = KIcon( "insert-text" ).pixmap( 16, 16 ).toImage(); KIconEffect::colorize( tintedInsertion, scheme.foreground( KColorScheme::NegativeText ).color(), 1.0 ); QImage tintedRemoval = KIcon( "edit-delete" ).pixmap( 16, 16 ).toImage(); KIconEffect::colorize( tintedRemoval, scheme.foreground( KColorScheme::NegativeText ).color(), 1.0 ); QImage tintedChange = KIcon( "text-field" ).pixmap( 16, 16 ).toImage(); KIconEffect::colorize( tintedChange, scheme.foreground( KColorScheme::NegativeText ).color(), 1.0 ); markIface->setMarkDescription( KTextEditor::MarkInterface::markType22, i18n( "Insertion" ) ); markIface->setMarkPixmap( KTextEditor::MarkInterface::markType22, QPixmap::fromImage( tintedInsertion ) ); markIface->setMarkDescription( KTextEditor::MarkInterface::markType23, i18n( "Removal" ) ); markIface->setMarkPixmap( KTextEditor::MarkInterface::markType23, QPixmap::fromImage( tintedRemoval ) ); markIface->setMarkDescription( KTextEditor::MarkInterface::markType24, i18n( "Change" ) ); markIface->setMarkPixmap( KTextEditor::MarkInterface::markType24, QPixmap::fromImage( tintedChange ) ); markIface->setMarkDescription( KTextEditor::MarkInterface::markType25, i18n( "Insertion" ) ); markIface->setMarkPixmap( KTextEditor::MarkInterface::markType25, KIcon( "insert-text" ).pixmap( 16, 16 ) ); markIface->setMarkDescription( KTextEditor::MarkInterface::markType26, i18n( "Removal" ) ); markIface->setMarkPixmap( KTextEditor::MarkInterface::markType26, KIcon( "edit-delete" ).pixmap( 16, 16 ) ); markIface->setMarkDescription( KTextEditor::MarkInterface::markType27, i18n( "Change" ) ); markIface->setMarkPixmap( KTextEditor::MarkInterface::markType27, KIcon( "text-field" ).pixmap( 16, 16 ) ); for ( Diff2::DifferenceList::const_iterator it = m_model->differences()->constBegin(); it != m_model->differences()->constEnd(); ++it ) { Diff2::Difference* diff = *it; int line, lineCount; Diff2::DifferenceStringList lines; if( diff->applied() ) { line = diff->destinationLineNumber(); lineCount = diff->destinationLineCount(); lines = diff->destinationLines(); } else { line = diff->sourceLineNumber(); lineCount = diff->sourceLineCount(); lines = diff->sourceLines(); } if ( line > 0 ) line -= 1; KTextEditor::Cursor c( line, 0 ); KTextEditor::Cursor endC( line + lineCount, 0 ); if ( doc->lines() <= c.line() ) c.setLine( doc->lines() - 1 ); if ( doc->lines() <= endC.line() ) endC.setLine( doc->lines() ); if ( endC.isValid() && c.isValid() ) { KTextEditor::MovingRange * r = moving->newMovingRange( KTextEditor::Range( c, endC ) ); m_ranges << r; m_differencesForRanges[r] = *it; addLineMarker( r, diff ); } } } else { if ( m_applying ) { // Do not interfere with patch application return; } kDebug() << "insertion range" << range; QString text = doc->text( range ); kDebug() << "inserted text" << text; QStringList insertedLines = splitAndAddNewlines( text ); int startLine = range.start().line(); int endLine = range.end().line(); QString prefix = doc->line( startLine ).mid( 0, range.start().column() ); QString suffix = doc->line( endLine ).mid( range.end().column() ); suffix += '\n'; QString removedLine = prefix + suffix; if ( !insertedLines.empty() ) { insertedLines.first() = prefix + insertedLines.first(); insertedLines.last() = insertedLines.last() + suffix; } performContentChange( doc, QStringList() << removedLine, insertedLines, startLine + 1 ); } } PatchHighlighter::PatchHighlighter( Diff2::DiffModel* model, IDocument* kdoc, PatchReviewPlugin* plugin ) throw( QString ) : m_doc( kdoc ), m_plugin( plugin ), m_model( model ), m_applying( false ) { // connect( kdoc, SIGNAL(destroyed(QObject*)), this, SLOT(documentDestroyed()) ); connect( kdoc->textDocument(), SIGNAL( textInserted( KTextEditor::Document*, KTextEditor::Range ) ), this, SLOT( textInserted( KTextEditor::Document*, KTextEditor::Range ) ) ); connect( kdoc->textDocument(), SIGNAL( textChanged( KTextEditor::Document*, KTextEditor::Range, KTextEditor::Range ) ), this, SLOT( textChanged( KTextEditor::Document*, KTextEditor::Range, KTextEditor::Range ) ) ); connect( kdoc->textDocument(), SIGNAL( textRemoved( KTextEditor::Document*, KTextEditor::Range, QString ) ), this, SLOT( textRemoved( KTextEditor::Document*, KTextEditor::Range, QString ) ) ); connect( kdoc->textDocument(), SIGNAL( destroyed( QObject* ) ), this, SLOT( documentDestroyed() ) ); KTextEditor::Document* doc = kdoc->textDocument(); if ( doc->lines() == 0 ) return; connect( doc, SIGNAL( markToolTipRequested( KTextEditor::Document*, KTextEditor::Mark, QPoint, bool & ) ), this, SLOT( markToolTipRequested( KTextEditor::Document*, KTextEditor::Mark, QPoint, bool & ) ) ); connect( doc, SIGNAL( markClicked( KTextEditor::Document*, KTextEditor::Mark, bool & ) ), this, SLOT( markClicked( KTextEditor::Document*, KTextEditor::Mark, bool & ) ) ); connect( doc, SIGNAL( aboutToDeleteMovingInterfaceContent( KTextEditor::Document* ) ), this, SLOT( aboutToDeleteMovingInterfaceContent( KTextEditor::Document* ) ) ); textInserted( kdoc->textDocument(), kdoc->textDocument()->documentRange() ); } void PatchHighlighter::removeLineMarker( KTextEditor::MovingRange* range ) { KTextEditor::MovingInterface* moving = dynamic_cast( range->document() ); if ( !moving ) return; KTextEditor::MarkInterface* markIface = dynamic_cast( range->document() ); if( !markIface ) return; markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType22 ); markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType23 ); markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType24 ); markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType25 ); markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType26 ); markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType27 ); // Remove all ranges that are in the same line (the line markers) foreach( KTextEditor::MovingRange* r, m_ranges ) { if( r != range && range->contains( r->toRange() ) ) { delete r; m_ranges.remove( r ); m_differencesForRanges.remove( r ); } } } void PatchHighlighter::addLineMarker( KTextEditor::MovingRange* range, Diff2::Difference* diff ) { KTextEditor::MovingInterface* moving = dynamic_cast( range->document() ); if ( !moving ) return; KTextEditor::MarkInterface* markIface = dynamic_cast( range->document() ); if( !markIface ) return; KSharedPtr t( new KTextEditor::Attribute() ); bool isOriginalState = diff->applied() == m_plugin->patch()->isAlreadyApplied(); if( isOriginalState ) { t->setProperty( QTextFormat::BackgroundBrush, QBrush( ColorCache::self()->blendBackground( QColor( 0, 255, 255 ), 20 ) ) ); }else{ t->setProperty( QTextFormat::BackgroundBrush, QBrush( ColorCache::self()->blendBackground( QColor( 255, 0, 255 ), 20 ) ) ); } range->setAttribute( t ); range->setZDepth( -500 ); KTextEditor::MarkInterface::MarkTypes mark; if( isOriginalState ) { mark = KTextEditor::MarkInterface::markType27; if( isInsertion( diff ) ) mark = KTextEditor::MarkInterface::markType25; if( isRemoval( diff ) ) mark = KTextEditor::MarkInterface::markType26; }else{ mark = KTextEditor::MarkInterface::markType24; if( isInsertion( diff ) ) mark = KTextEditor::MarkInterface::markType22; if( isRemoval( diff ) ) mark = KTextEditor::MarkInterface::markType23; } markIface->addMark( range->start().line(), mark ); Diff2::DifferenceStringList lines; if( diff->applied() ) lines = diff->destinationLines(); else lines = diff->sourceLines(); for( int a = 0; a < lines.size(); ++a ) { Diff2::DifferenceString* line = lines[a]; int currentPos = 0; QString string = line->string(); Diff2::MarkerList markers = line->markerList(); for( int b = 0; b < markers.size(); ++b ) { if( markers[b]->type() == Diff2::Marker::End ) { if( currentPos != 0 || markers[b]->offset() != static_cast( string.size() ) ) { KTextEditor::MovingRange * r2 = moving->newMovingRange( KTextEditor::Range( KTextEditor::Cursor( a + range->start().line(), currentPos ), KTextEditor::Cursor( a + range->start().line(), markers[b]->offset() ) ) ); m_ranges << r2; KSharedPtr t( new KTextEditor::Attribute() ); t->setProperty( QTextFormat::BackgroundBrush, QBrush( ColorCache::self()->blendBackground( QColor( 255, 0, 0 ), 70 ) ) ); r2->setAttribute( t ); r2->setZDepth( -600 ); } } currentPos = markers[b]->offset(); } } } void PatchHighlighter::clear() { if( m_ranges.empty() ) return; KTextEditor::MovingInterface* moving = dynamic_cast( m_doc->textDocument() ); if ( !moving ) return; KTextEditor::MarkInterface* markIface = dynamic_cast( m_doc->textDocument() ); if( !markIface ) return; QHash marks = markIface->marks(); foreach( int line, marks.keys() ) { markIface->removeMark( line, KTextEditor::MarkInterface::markType22 ); markIface->removeMark( line, KTextEditor::MarkInterface::markType23 ); markIface->removeMark( line, KTextEditor::MarkInterface::markType24 ); markIface->removeMark( line, KTextEditor::MarkInterface::markType25 ); markIface->removeMark( line, KTextEditor::MarkInterface::markType26 ); markIface->removeMark( line, KTextEditor::MarkInterface::markType27 ); } qDeleteAll( m_ranges ); m_ranges.clear(); m_differencesForRanges.clear(); } PatchHighlighter::~PatchHighlighter() { clear(); } IDocument* PatchHighlighter::doc() { return m_doc; } void PatchHighlighter::documentDestroyed() { kDebug() << "document destroyed"; m_ranges.clear(); m_differencesForRanges.clear(); } void PatchHighlighter::aboutToDeleteMovingInterfaceContent( KTextEditor::Document* ) { kDebug() << "about to delete"; clear(); } QList< KTextEditor::MovingRange* > PatchHighlighter::ranges() const { return m_differencesForRanges.keys(); } diff --git a/plugins/patchreview/patchreviewtoolview.cpp b/plugins/patchreview/patchreviewtoolview.cpp index 78123a0966..ddb895de0f 100644 --- a/plugins/patchreview/patchreviewtoolview.cpp +++ b/plugins/patchreview/patchreviewtoolview.cpp @@ -1,332 +1,332 @@ /*************************************************************************** Copyright 2006-2009 David Nolden ***************************************************************************/ /*************************************************************************** * * * 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 "patchreviewtoolview.h" #include "localpatchsource.h" #include "patchreview.h" #include "standardpatchexport.h" #include "libdiff2/diffmodellist.h" #include "libdiff2/komparemodellist.h" #include #include #include -#include +#include #include #include using namespace KDevelop; class PatchFilesModel : public VcsFileChangesModel { public: PatchFilesModel( QObject *parent, bool allowSelection ) : VcsFileChangesModel( parent, allowSelection ) { }; enum ItemRoles { HunksNumberRole = VcsStatusInfoRole+1 }; public slots: void updateState( const KDevelop::VcsStatusInfo &status, unsigned hunksNum ) { int row = VcsFileChangesModel::updateState( invisibleRootItem(), status ); if ( row == -1 ) return; QStandardItem *item = invisibleRootItem()->child( row, 0 ); setFileInfo( item, hunksNum ); item->setData( QVariant( hunksNum ), HunksNumberRole ); } void updateState( const KDevelop::VcsStatusInfo &status ) { int row = VcsFileChangesModel::updateState( invisibleRootItem(), status ); if ( row == -1 ) return; QStandardItem *item = invisibleRootItem()->child( row, 0 ); setFileInfo( invisibleRootItem()->child( row, 0 ), item->data( HunksNumberRole ).toUInt() ); } private: void setFileInfo( QStandardItem *item, unsigned int hunksNum ) { QString newText = i18ncp( "%1: number of changed hunks, %2: file name", "%2 (1 hunk)", "%2 (%1 hunks)", hunksNum, item->data(VcsFileChangesModel::VcsStatusInfoRole).value().url().pathOrUrl() ); item->setText( newText ); } }; PatchReviewToolView::PatchReviewToolView( QWidget* parent, PatchReviewPlugin* plugin ) : QWidget( parent ), m_reversed( false ), m_plugin( plugin ) { connect( plugin, SIGNAL( patchChanged() ), SLOT( patchChanged() ) ); connect( ICore::self()->documentController(), SIGNAL( documentActivated( KDevelop::IDocument* ) ), this, SLOT( documentActivated( KDevelop::IDocument* ) ) ); showEditDialog(); patchChanged(); } void PatchReviewToolView::patchChanged() { fillEditFromPatch(); kompareModelChanged(); } PatchReviewToolView::~PatchReviewToolView() { } LocalPatchSource* PatchReviewToolView::GetLocalPatchSource() { IPatchSource::Ptr ips = m_plugin->patch(); if ( !ips ) return 0; return dynamic_cast( ips.data() ); } void PatchReviewToolView::updatePatchFromEdit() { LocalPatchSource* lpatch = GetLocalPatchSource(); if( !lpatch ) return; lpatch->setCommand(m_editPatch.command->text()); lpatch->setFilename(m_editPatch.filename->url()); lpatch->setBaseDir(m_editPatch.baseDir->url()); lpatch->setAlreadyApplied( m_editPatch.applied->checkState() == Qt::Checked ); m_plugin->notifyPatchChanged(); } void PatchReviewToolView::fillEditFromPatch() { IPatchSource::Ptr ipatch = m_plugin->patch(); if ( !ipatch ) return; disconnect( m_editPatch.patchSelection, SIGNAL( currentIndexChanged( int ) ), this, SLOT( patchSelectionChanged( int ) ) ); m_editPatch.patchSelection->clear(); foreach( IPatchSource::Ptr patch, m_plugin->knownPatches() ) { if( !patch ) continue; m_editPatch.patchSelection->addItem( patch->icon(), patch->name() ); if( patch == ipatch ) m_editPatch.patchSelection->setCurrentIndex( m_editPatch.patchSelection->count()-1 ); } connect( m_editPatch.patchSelection, SIGNAL( currentIndexChanged( int ) ), this, SLOT( patchSelectionChanged( int ) ) ); m_editPatch.cancelReview->setVisible( ipatch->canCancel() ); QString finishText = i18n( "Finish Review" ); if( !ipatch->finishReviewCustomText().isEmpty() ) finishText = ipatch->finishReviewCustomText(); kDebug() << "finish-text: " << finishText; m_editPatch.finishReview->setText( finishText ); m_fileModel->setIsCheckbable( m_plugin->patch()->canSelectFiles() ); if( m_customWidget ) { kDebug() << "removing custom widget"; m_customWidget->hide(); m_editPatch.customWidgetsLayout->removeWidget( m_customWidget ); } m_customWidget = ipatch->customWidget(); if( m_customWidget ) { m_editPatch.customWidgetsLayout->insertWidget( 0, m_customWidget ); m_customWidget->show(); kDebug() << "got custom widget"; } LocalPatchSource* lpatch = dynamic_cast( ipatch.data() ); m_editPatch.tabWidget->setVisible( lpatch ); m_editPatch.baseDir->setVisible( lpatch ); m_editPatch.label->setVisible( lpatch ); m_editPatch.applied->setVisible( lpatch ); if( !lpatch ) return; m_editPatch.command->setText( lpatch->command()); m_editPatch.filename->setUrl( lpatch->file() ); m_editPatch.baseDir->setUrl( lpatch->baseDir() ); m_editPatch.applied->setCheckState( lpatch->isAlreadyApplied() ? Qt::Checked : Qt::Unchecked ); if ( lpatch->command().isEmpty() ) m_editPatch.tabWidget->setCurrentIndex( m_editPatch.tabWidget->indexOf( m_editPatch.fileTab ) ); else m_editPatch.tabWidget->setCurrentIndex( m_editPatch.tabWidget->indexOf( m_editPatch.commandTab ) ); } void PatchReviewToolView::patchSelectionChanged( int selection ) { m_fileModel->removeRows( 0, m_fileModel->rowCount() ); if( selection >= 0 && selection < m_plugin->knownPatches().size() ) { m_plugin->setPatch( m_plugin->knownPatches()[selection] ); } } void PatchReviewToolView::slotAppliedChanged( int newState ) { if ( LocalPatchSource* lpatch = GetLocalPatchSource() ) { lpatch->setAlreadyApplied( newState == Qt::Checked ); m_plugin->notifyPatchChanged(); } } void PatchReviewToolView::slotEditCommandChanged() { // m_editPatch.filename->lineEdit()->setText( "" ); updatePatchFromEdit(); } void PatchReviewToolView::slotEditFileNameChanged() { // m_editPatch.command->setText( "" ); updatePatchFromEdit(); } void PatchReviewToolView::showEditDialog() { m_editPatch.setupUi( this ); m_fileModel = new PatchFilesModel( this, m_plugin->patch()->canSelectFiles() ); m_editPatch.filesList->setModel( m_fileModel ); m_editPatch.filesList->header()->hide(); m_editPatch.filesList->setRootIsDecorated( false ); m_editPatch.previousHunk->setIcon( KIcon( "arrow-up" ) ); m_editPatch.nextHunk->setIcon( KIcon( "arrow-down" ) ); m_editPatch.cancelReview->setIcon( KIcon( "dialog-cancel" ) ); m_editPatch.finishReview->setIcon( KIcon( "dialog-ok" ) ); QMenu* exportMenu = new QMenu( m_editPatch.exportReview ); StandardPatchExport* stdactions = new StandardPatchExport( m_plugin, this ); stdactions->addActions( exportMenu ); connect( exportMenu, SIGNAL( triggered( QAction* ) ), m_plugin, SLOT( exporterSelected( QAction* ) ) ); IPluginController* pluginManager = ICore::self()->pluginController(); foreach( IPlugin* p, pluginManager->allPluginsForExtension( "org.kdevelop.IPatchExporter" ) ) { KPluginInfo info = pluginManager->pluginInfo( p ); QAction* action = exportMenu->addAction( KIcon( info.icon() ), info.name() ); action->setData( qVariantFromValue( p ) ); } m_editPatch.exportReview->setMenu( exportMenu ); connect( m_editPatch.previousHunk, SIGNAL( clicked( bool ) ), this, SLOT( prevHunk() ) ); connect( m_editPatch.nextHunk, SIGNAL( clicked( bool ) ), this, SLOT( nextHunk() ) ); connect( m_editPatch.filesList, SIGNAL( activated ( QModelIndex ) ), this, SLOT( fileDoubleClicked( QModelIndex ) ) ); connect( m_editPatch.cancelReview, SIGNAL( clicked( bool ) ), m_plugin, SLOT( cancelReview() ) ); connect( m_editPatch.finishReview, SIGNAL( clicked( bool ) ), this, SLOT( finishReview() ) ); //connect( m_editPatch.cancelButton, SIGNAL(pressed()), this, SLOT(slotEditCancel()) ); //connect( this, SIGNAL(finished(int)), this, SLOT(slotEditDialogFinished(int)) ); connect( m_editPatch.applied, SIGNAL( stateChanged( int ) ), SLOT( slotAppliedChanged( int ) ) ); connect( m_editPatch.filename, SIGNAL( textChanged( QString ) ), SLOT( slotEditFileNameChanged() ) ); m_editPatch.baseDir->setMode( KFile::Directory ); connect( m_editPatch.command, SIGNAL( textChanged( QString ) ), this, SLOT( slotEditCommandChanged() ) ); // connect( m_editPatch.commandToFile, SIGNAL(clicked(bool)), this, SLOT(slotToFile()) ); connect( m_editPatch.filename->lineEdit(), SIGNAL( returnPressed() ), this, SLOT( slotEditFileNameChanged() ) ); connect( m_editPatch.filename->lineEdit(), SIGNAL( editingFinished() ), this, SLOT( slotEditFileNameChanged() ) ); connect( m_editPatch.filename, SIGNAL( urlSelected( KUrl ) ), this, SLOT( slotEditFileNameChanged() ) ); connect( m_editPatch.command, SIGNAL( textChanged( QString ) ), this, SLOT( slotEditCommandChanged() ) ); // connect( m_editPatch.commandToFile, SIGNAL(clicked(bool)), m_plugin, SLOT(commandToFile()) ); connect( m_editPatch.patchSelection, SIGNAL( currentIndexChanged( int ) ), this, SLOT( patchSelectionChanged( int ) ) ); connect( m_editPatch.updateButton, SIGNAL( clicked( bool ) ), m_plugin, SLOT( forceUpdate() ) ); connect( m_editPatch.showButton, SIGNAL( clicked( bool ) ), m_plugin, SLOT( showPatch() ) ); } void PatchReviewToolView::nextHunk() { // updateKompareModel(); m_plugin->seekHunk( true ); } void PatchReviewToolView::prevHunk() { // updateKompareModel(); m_plugin->seekHunk( false ); } void PatchReviewToolView::finishReview() { QList selectedUrls = m_fileModel->checkedUrls(); kDebug() << "finishing review with" << selectedUrls; m_plugin->finishReview( selectedUrls ); } void PatchReviewToolView::fileDoubleClicked( const QModelIndex& idx ) { QModelIndex i = idx.sibling(idx.row(), 0); KUrl file = m_fileModel->statusInfo( i ).url(); kDebug() << "opening" << file.toLocalFile(); ICore::self()->documentController()->openDocument( file, KTextEditor::Cursor() ); m_plugin->seekHunk( true, file ); } KUrl PatchReviewPlugin::urlForFileModel( const Diff2::DiffModel* model ) { KUrl file = m_patch->baseDir(); file.addPath( model->destinationPath() ); file.addPath( model->destinationFile() ); return file; } void PatchReviewToolView::kompareModelChanged() { m_fileModel->clear(); if ( !m_plugin->modelList() ) return; QMap additionalUrls = m_plugin->patch()->additionalSelectableFiles(); const Diff2::DiffModelList* models = m_plugin->modelList()->models(); if( models ) { Diff2::DiffModelList::const_iterator it = models->constBegin(); for(; it != models->constEnd(); ++it ) { Diff2::DifferenceList * diffs = ( *it )->differences(); int cnt = 0; if ( diffs ) cnt = diffs->count(); KUrl file = m_plugin->urlForFileModel( *it ); if( !QFileInfo( file.toLocalFile() ).isReadable() ) continue; VcsStatusInfo status; status.setUrl( file ); status.setState( VcsStatusInfo::ItemModified ); m_fileModel->updateState( status, cnt ); } } for( QMap::const_iterator it = additionalUrls.constBegin(); it != additionalUrls.constEnd(); it++ ) { VcsStatusInfo status; status.setUrl( it.key() ); status.setState( it.value() ); m_fileModel->updateState( status ); } m_editPatch.filesList->resizeColumnToContents( 0 ); } void PatchReviewToolView::documentActivated( IDocument* doc ) { if ( !m_plugin->modelList() ) return; QStandardItem *fileItem = m_fileModel->fileItemForUrl( doc->url() ); if ( fileItem ) { m_editPatch.filesList->setCurrentIndex( fileItem->index() ); } else { m_editPatch.filesList->setCurrentIndex( QModelIndex() ); } }