diff --git a/plugins/patchreview/patchhighlighter.cpp b/plugins/patchreview/patchhighlighter.cpp index 00cae2aa9a..0d63318226 100644 --- a/plugins/patchreview/patchhighlighter.cpp +++ b/plugins/patchreview/patchhighlighter.cpp @@ -1,626 +1,626 @@ /*************************************************************************** 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 #include #include "patchreview.h" #include "debug.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) { 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; html += QLatin1String(""); if( diff->applied() ) { if( !m_plugin->patch()->isAlreadyApplied() ) html += i18n( "Applied.
" ); if( isInsertion( diff ) ) { html += i18n( "Insertion
" ); } else { if( isRemoval( diff ) ) html += i18n( "Removal
" ); html += i18n( "Previous:
" ); lines = diff->sourceLines(); } } else { if( m_plugin->patch()->isAlreadyApplied() ) html += i18n( "Reverted.
" ); if( isRemoval( diff ) ) { html += i18n( "Removal
" ); } else { if( isInsertion( diff ) ) html += i18n( "Insertion
" ); html += i18n( "Alternative:
" ); lines = diff->destinationLines(); } } html += QLatin1String("
"); 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 = string.mid( currentPos, markers[b]->offset() - currentPos ).toHtmlEscaped(); if( markers[b]->type() == Diff2::Marker::End && ( currentPos != 0 || markers[b]->offset() != static_cast( string.size() ) ) ) { html += "" + spanText + ""; }else{ html += spanText; } currentPos = markers[b]->offset(); } html += string.mid( currentPos, string.length()-currentPos ).toHtmlEscaped(); html += QLatin1String("
"); } auto browser = new QTextBrowser; 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->setHandleRect( QRect( pos - QPoint( 15, 15 ), pos + QPoint( 15, 15 ) ) ); currentTooltip = tooltip; currentTooltipMark = markRange; ActiveToolTip::showToolTip( tooltip ); } void PatchHighlighter::markClicked( KTextEditor::Document* doc, const KTextEditor::Mark& mark, bool& handled ) { m_applying = true; if( handled ) return; handled = true; // TODO: reconsider workaround // 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 ); uint replaceWithLines = replaceWith.count( '\n' ); KTextEditor::Range newRange( start, KTextEditor::Cursor(start.line() + replaceWithLines, start.column()) ); 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( const 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 nullptr; } void PatchHighlighter::markToolTipRequested( KTextEditor::Document*, const 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; } qCDebug(PLUGIN_PATCHREVIEW) << "removal range" << range; qCDebug(PLUGIN_PATCHREVIEW) << "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::highlightFromScratch(KTextEditor::Document* doc) { qCDebug(PLUGIN_PATCHREVIEW) << "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 = QIcon::fromTheme( QStringLiteral("insert-text") ).pixmap( 16, 16 ).toImage(); KIconEffect::colorize( tintedInsertion, scheme.foreground( KColorScheme::NegativeText ).color(), 1.0 ); QImage tintedRemoval = QIcon::fromTheme( QStringLiteral("edit-delete") ).pixmap( 16, 16 ).toImage(); KIconEffect::colorize( tintedRemoval, scheme.foreground( KColorScheme::NegativeText ).color(), 1.0 ); QImage tintedChange = QIcon::fromTheme( QStringLiteral("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, QIcon::fromTheme( QStringLiteral("insert-text") ).pixmap( 16, 16 ) ); markIface->setMarkDescription( KTextEditor::MarkInterface::markType26, i18n( "Removal" ) ); markIface->setMarkPixmap( KTextEditor::MarkInterface::markType26, QIcon::fromTheme( QStringLiteral("edit-delete") ).pixmap( 16, 16 ) ); markIface->setMarkDescription( KTextEditor::MarkInterface::markType27, i18n( "Change" ) ); markIface->setMarkPixmap( KTextEditor::MarkInterface::markType27, QIcon::fromTheme( QStringLiteral("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 ); } } } void PatchHighlighter::textInserted(KTextEditor::Document* doc, const KTextEditor::Cursor& cursor, const QString& text) { KTextEditor::Range range(cursor, KTextEditor::Cursor(text.count('\n'), text.size()-text.lastIndexOf('\n')+1)); if( range == doc->documentRange() ) { highlightFromScratch(doc); } else { if ( m_applying ) { // Do not interfere with patch application return; } qCDebug(PLUGIN_PATCHREVIEW) << "insertion range" << range; QString text = doc->text( range ); qCDebug(PLUGIN_PATCHREVIEW) << "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, bool updatePatchFromEdits ) throw( QString ) +PatchHighlighter::PatchHighlighter( Diff2::DiffModel* model, IDocument* kdoc, PatchReviewPlugin* plugin, bool updatePatchFromEdits ) : m_doc( kdoc ), m_plugin( plugin ), m_model( model ), m_applying( false ) { KTextEditor::Document* doc = kdoc->textDocument(); // connect( kdoc, SIGNAL(destroyed(QObject*)), this, SLOT(documentDestroyed()) ); if (updatePatchFromEdits) { connect(doc, &KTextEditor::Document::textInserted, this, &PatchHighlighter::textInserted); connect(doc, &KTextEditor::Document::textRemoved, this, &PatchHighlighter::textRemoved); } connect(doc, &KTextEditor::Document::destroyed, this, &PatchHighlighter::documentDestroyed); if ( doc->lines() == 0 ) return; if (qobject_cast(doc)) { //can't use new signal/slot syntax here, MarkInterface is not a QObject 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&))); } if (qobject_cast(doc)) { //can't use new signal/slot syntax here, MovingInterface is not a QObject connect(doc, SIGNAL(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*)), this, SLOT( aboutToDeleteMovingInterfaceContent(KTextEditor::Document*))); connect(doc, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)), this, SLOT(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*))); } highlightFromScratch(doc); } 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; KTextEditor::Attribute::Ptr 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; KTextEditor::Attribute::Ptr 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() { qCDebug(PLUGIN_PATCHREVIEW) << "document destroyed"; m_ranges.clear(); m_differencesForRanges.clear(); } void PatchHighlighter::aboutToDeleteMovingInterfaceContent( KTextEditor::Document* ) { qCDebug(PLUGIN_PATCHREVIEW) << "about to delete"; clear(); } QList< KTextEditor::MovingRange* > PatchHighlighter::ranges() const { return m_differencesForRanges.keys(); } diff --git a/plugins/patchreview/patchhighlighter.h b/plugins/patchreview/patchhighlighter.h index 95adf3dc94..9782bcec3d 100644 --- a/plugins/patchreview/patchhighlighter.h +++ b/plugins/patchreview/patchhighlighter.h @@ -1,84 +1,84 @@ /*************************************************************************** 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. * * * ***************************************************************************/ #ifndef KDEVPLATFORM_PLUGIN_PATCHHIGHLIGHTER_H #define KDEVPLATFORM_PLUGIN_PATCHHIGHLIGHTER_H #include #include #include #include #include namespace Diff2 { class Difference; class DiffModel; } class PatchReviewPlugin; namespace KDevelop { class IDocument; } namespace KTextEditor { class Document; class Range; class Cursor; class Mark; class MovingRange; } ///Delete itself when the document(or textDocument), or Diff-Model is deleted. class PatchHighlighter : public QObject { Q_OBJECT public: - PatchHighlighter( Diff2::DiffModel* model, KDevelop::IDocument* doc, PatchReviewPlugin* plugin, bool updatePatchFromEdits ) throw( QString ); + PatchHighlighter( Diff2::DiffModel* model, KDevelop::IDocument* doc, PatchReviewPlugin* plugin, bool updatePatchFromEdits ); ~PatchHighlighter() override; KDevelop::IDocument* doc(); QList< KTextEditor::MovingRange* > ranges() const; private slots: void documentDestroyed(); void aboutToDeleteMovingInterfaceContent( KTextEditor::Document* ); private: void highlightFromScratch(KTextEditor::Document* doc); void addLineMarker( KTextEditor::MovingRange* arg1, Diff2::Difference* arg2 ); void removeLineMarker( KTextEditor::MovingRange* range ); QStringList splitAndAddNewlines( const QString& text ) const; void performContentChange( KTextEditor::Document* doc, const QStringList& oldLines, const QStringList& newLines, int editLineNumber ); KTextEditor::MovingRange* rangeForMark(const KTextEditor::Mark& mark); void clear(); QSet< KTextEditor::MovingRange* > m_ranges; QMap< KTextEditor::MovingRange*, Diff2::Difference* > m_differencesForRanges; KDevelop::IDocument* m_doc; PatchReviewPlugin* m_plugin; Diff2::DiffModel* m_model; bool m_applying; public slots: void markToolTipRequested( KTextEditor::Document*, const KTextEditor::Mark&, QPoint, bool & ); void showToolTipForMark( QPoint arg1, KTextEditor::MovingRange* arg2); bool isRemoval( Diff2::Difference* ); bool isInsertion( Diff2::Difference* ); void markClicked( KTextEditor::Document*, const KTextEditor::Mark&, bool& ); void textInserted(KTextEditor::Document* doc, const KTextEditor::Cursor& cursor, const QString& text); void textRemoved( KTextEditor::Document*, const KTextEditor::Range&, const QString& oldText ); }; #endif diff --git a/plugins/subversion/kdevsvncpp/client.hpp b/plugins/subversion/kdevsvncpp/client.hpp index a648cd57cd..7a0734ec24 100644 --- a/plugins/subversion/kdevsvncpp/client.hpp +++ b/plugins/subversion/kdevsvncpp/client.hpp @@ -1,739 +1,739 @@ /* * ==================================================================== * Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved. * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the file GPL.txt. * If not, see . * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://rapidsvn.tigris.org/. * ==================================================================== */ #ifndef _SVNCPP_CLIENT_H_ #define _SVNCPP_CLIENT_H_ // Ignore MSVC 6 compiler warning #if defined (_MSC_VER) && _MSC_VER <= 1200 // debug symbol truncated #pragma warning (disable: 4786) // C++ exception specification #pragma warning (disable: 4290) #endif // Ignore MSVC 7,8,9 compiler warnings #if defined (_MSC_VER) && _MSC_VER > 1200 && _MSC_VER <= 1500 // C++ exception specification #pragma warning (disable: 4290) #endif // stl #include "kdevsvncpp/vector_wrapper.hpp" #include "kdevsvncpp/utility_wrapper.hpp" #include "kdevsvncpp/map_wrapper.hpp" // svncpp #include "kdevsvncpp/context.hpp" #include "kdevsvncpp/exception.hpp" #include "kdevsvncpp/path.hpp" #include "kdevsvncpp/entry.hpp" #include "kdevsvncpp/revision.hpp" #include "kdevsvncpp/log_entry.hpp" #include "kdevsvncpp/annotate_line.hpp" namespace svn { // forward declarations class Context; class DirEntry; class Info; class Status; class Targets; typedef std::vector AnnotatedFile; typedef std::vector DirEntries; typedef std::vector InfoVector; typedef std::vector LogEntries; typedef std::vector StatusEntries; // map of property names to values typedef std::map PropertiesMap; // pair of path, PropertiesMap typedef std::pair PathPropertiesMapEntry; // vector of path, Properties pairs typedef std::vector PathPropertiesMapList; /** * These flags can be passed to the status function to filter * the files * * @see status */ struct StatusFilter { public: bool showUnversioned; bool showUnmodified; bool showModified; ///< this includes @a showConflicted as well bool showConflicted; bool showIgnored; bool showExternals; StatusFilter() : showUnversioned(false), showUnmodified(false), showModified(false), showConflicted(false), showExternals(false) { } }; /** * Subversion client API. */ class Client { public: /** * Initializes the primary memory pool. */ Client(Context * context = nullptr); virtual ~Client(); /** * @return returns the Client context */ const Context * getContext() const; /** * @return returns the Client context */ Context * getContext(); /** * sets the client context * you have to make sure the old context * is de-allocated * * @param context new context to use */ void setContext(Context * context = NULL); /** * Enumerates all files/dirs at a given path. * * Throws an exception if an error occurs * * @param path Path to explore. * @param descend Recurse into subdirectories if existant. * @param get_all Return all entries, not just the interesting ones. * @param update Query the repository for updates. * @param no_ignore Disregard default and svn:ignore property ignores. * @param ignore_externals Disregard external files. * @return vector with Status entries. */ StatusEntries status(const char * path, const bool descend = false, const bool get_all = true, const bool update = false, const bool no_ignore = false, - const bool ignore_externals = false) throw(ClientException); + const bool ignore_externals = false); /** * Enumerates all files/dirs matchin the parameter @a filter * at @a path and returns them in the vector @a statusEntries * * Throws an exception if an error occurs * * @since New in 0.9.7 * * @param path Path to explore. * @param filter use a combination of the @a SHOW_* values to filter the * output * @param descend Recurse into subdirectories if existant. * @param update Query the repository for updates. * @param entries vector with Status entries * * @return current revnum */ svn_revnum_t status(const char * path, const StatusFilter & filter, const bool descend, const bool update, - StatusEntries & entries) throw(ClientException); + StatusEntries & entries); /** * Executes a revision checkout. * @param moduleName name of the module to checkout. * @param destPath destination directory for checkout. * @param revision the revision number to checkout. If the number is -1 * then it will checkout the latest revision. * @param recurse whether you want it to checkout files recursively. * @param ignore_externals whether you want get external resources too. * @param peg_revision peg revision to checkout, by default current. * @exception ClientException */ svn_revnum_t checkout(const char * moduleName, const Path & destPath, const Revision & revision, bool recurse, bool ignore_externals = false, - const Revision & peg_revision = Revision::UNSPECIFIED) throw(ClientException); + const Revision & peg_revision = Revision::UNSPECIFIED); /** * relocate wc @a from to @a to * @exception ClientException */ void relocate(const Path & path, const char *from_url, - const char *to_url, bool recurse) throw(ClientException); + const char *to_url, bool recurse); /** * Sets a single file for deletion. * @exception ClientException */ void - remove(const Path & path, bool force) throw(ClientException); + remove(const Path & path, bool force); /** * Sets files for deletion. * * @param targets targets to delete * @param force force if files are locally modified * @exception ClientException */ void remove(const Targets & targets, - bool force) throw(ClientException); + bool force); /** * Sets files to lock. * * @param targets targets to lock * @param force force setting/stealing lock * @param comment writing comment about lock setting is necessary * @exception ClientException */ void lock(const Targets & targets, bool force, - const char * comment) throw(ClientException); + const char * comment); /** * Sets files to unlock. * * @param targets targets to unlock * @param force force unlock even if lock belongs to another user * @exception ClientException */ void - unlock(const Targets & targets, bool force) throw(ClientException); + unlock(const Targets & targets, bool force); /** * Reverts a couple of files to a pristiner state. * @exception ClientException */ void - revert(const Targets & targets, bool recurse) throw(ClientException); + revert(const Targets & targets, bool recurse); /** * Adds a file to the repository. * @exception ClientException */ void - add(const Path & path, bool recurse) throw(ClientException); + add(const Path & path, bool recurse); /** * Updates the file or directory. * @param targets target files. * @param revision the revision number to checkout. * Revision::HEAD will checkout the * latest revision. * @param recurse recursively update. * @param ignore_externals don't affect external destinations. * @exception ClientException * * @return a vector with resulting revisions */ std::vector update(const Targets & targets, const Revision & revision, bool recurse, - bool ignore_externals) throw(ClientException); + bool ignore_externals); svn_revnum_t update(const Path & path, const Revision & revision, bool recurse, - bool ignore_externals) throw(ClientException); + bool ignore_externals); /** * Retrieves the contents for a specific @a revision of * a @a path * * @param path path of file or directory * @param revision revision to retrieve * @param peg_revision peg revision to retrieve, * by default is the latest one * @return contents of the file */ std::string cat(const Path & path, const Revision & revision, - const Revision & peg_revision = Revision::UNSPECIFIED) throw(ClientException); + const Revision & peg_revision = Revision::UNSPECIFIED); /** * Retrieves the contents for a specific @a revision of * a @a path and saves it to the destination file @a dstPath. * * If @a dstPath is empty (""), then this path will be * constructed from the temporary directory on this system * and the filename in @a path. @a dstPath will still have * the file extension from @a path and uniqueness of the * temporary filename will be ensured. * * @param dstPath Filename in which the contents * of the file file will be safed. * @param path path or url * @param peg_revision peg revision to retrieve, by default is the latest one */ void get(Path & dstPath, const Path & path, const Revision & revision, - const Revision & peg_revision = Revision::UNSPECIFIED) throw(ClientException); + const Revision & peg_revision = Revision::UNSPECIFIED); /** * Retrieves the contents for a specific @a revision of * a @a path * * @param path path of file or directory * @param revisionStart revision to retrieve * @param revisionEnd revision to retrieve * @return contents of the file */ AnnotatedFile * annotate(const Path & path, const Revision & revisionStart, - const Revision & revisionEnd) throw(ClientException); + const Revision & revisionEnd); /** * Commits changes to the repository. This usually requires * authentication, see Auth. * @return Returns a long representing the revision. It returns a * -1 if the revision number is invalid. * @param targets files to commit. * @param message log message. * @param recurse whether the operation should be done recursively. * @param keep_locks whether to preserve locks or to release them after commit * @exception ClientException */ svn_revnum_t commit(const Targets & targets, const char * message, bool recurse, - bool keep_locks = false) throw(ClientException); + bool keep_locks = false); /** * Copies a versioned file with the history preserved. * @exception ClientException */ void copy(const Path & srcPath, const Revision & srcRevision, - const Path & destPath) throw(ClientException); + const Path & destPath); /** * Moves or renames a file. * @exception ClientException */ void move(const Path & srcPath, const Revision & srcRevision, const Path & destPath, - bool force) throw(ClientException); + bool force); /** * Creates a directory directly in a repository or creates a * directory on disk and schedules it for addition. If path * is a URL then authentication is usually required, see Auth. * * @exception ClientException */ void - mkdir(const Path & path) throw(ClientException); + mkdir(const Path & path); void - mkdir(const Targets & targets) throw(ClientException); + mkdir(const Targets & targets); /** * Recursively cleans up a local directory, finishing any * incomplete operations, removing lockfiles, etc. * @param path a local directory. * @exception ClientException */ void - cleanup(const Path & path) throw(ClientException); + cleanup(const Path & path); /** * Removes the 'conflicted' state on a file. * @exception ClientException */ void - resolved(const Path & path, bool recurse) throw(ClientException); + resolved(const Path & path, bool recurse); /** * Export into file or directory TO_PATH from local or remote FROM_PATH * @param from_path path to import * @param to_path where to import * @param revision revision of files in source repository or working copy * @param overwrite overwrite existing files in to_path * @param ignore_externals whether to ignore external sources in from_path * @param native_eol which EOL to use when exporting, usually different for * different OSs * @exception ClientException */ void doExport(const Path & from_path, const Path & to_path, const Revision & revision, bool overwrite = false, const Revision & peg_revision = Revision::UNSPECIFIED, bool ignore_externals = false, bool recurse = true, - const char * native_eol = NULL) throw(ClientException); + const char * native_eol = NULL); /** * Update local copy to mirror a new url. This excapsulates the * svn_client_switch() client method. * @exception ClientException */ svn_revnum_t doSwitch(const Path & path, const char * url, const Revision & revision, - bool recurse) throw(ClientException); + bool recurse); /** * Import file or directory PATH into repository directory URL at * head. This usually requires authentication, see Auth. * @param path path to import * @param message log message. * @exception ClientException */ void import(const Path & path, const char * url, const char * message, - bool recurse) throw(ClientException); + bool recurse); void import(const Path & path, const Path & url, const char * message, - bool recurse) throw(ClientException); + bool recurse); /** * Merge changes from two paths into a new local path. * @exception ClientException */ void merge(const Path & path1, const Revision & revision1, const Path & path2, const Revision & revision2, const Path & localPath, bool force, bool recurse, bool notice_ancestry = false, - bool dry_run = false) throw(ClientException); + bool dry_run = false); /** * retrieve information about the given path * or URL * * @see Client::status * @see Info */ InfoVector info(const Path & pathOrUrl, bool recurse=false, const Revision & revision = Revision::UNSPECIFIED, - const Revision & pegRevision = Revision::UNSPECIFIED) throw(ClientException); + const Revision & pegRevision = Revision::UNSPECIFIED); /** * Retrieve log information for the given path * Loads the log messages result set. The first * entry is the youngest revision. * * You can use the constants Revision::START and * Revision::HEAD * @return a vector with log entries */ const LogEntries * log(const char * path, const Revision & revisionStart, const Revision & revisionEnd, bool discoverChangedPaths = false, - bool strictNodeHistory = true) throw(ClientException); + bool strictNodeHistory = true); /** * Produce diff output which describes the delta between * @a path/@a revision1 and @a path/@a revision2. @a path * can be either a working-copy path or a URL. * * A ClientException will be thrown if either @a revision1 or * @a revision2 has an `unspecified' or unrecognized `kind'. * * @param tmpPath prefix for a temporary directory needed by diff. * Filenames will have ".tmp" and similar added to this prefix in * order to ensure uniqueness. * @param path path of the file. * @param revision1 one of the revisions to check. * @param revision2 the other revision. * @param recurse whether the operation should be done recursively. * @param ignoreAncestry whether the files will be checked for * relatedness. * @param noDiffDeleted if true, no diff output will be generated * on deleted files. * @return delta between the files * @exception ClientException */ std::string diff(const Path & tmpPath, const Path & path, const Revision & revision1, const Revision & revision2, const bool recurse, const bool ignoreAncestry, - const bool noDiffDeleted) throw(ClientException); + const bool noDiffDeleted); /** * Produce diff output which describes the delta between * @a path1/@a revision1 and @a path2/@a revision2. @a path1, * @a path2 can be either a working-copy path or a URL. * * A ClientException will be thrown if either @a revision1 or * @a revision2 has an `unspecified' or unrecognized `kind'. * * @param tmpPath prefix for a temporary directory needed by diff. * Filenames will have ".tmp" and similar added to this prefix in * order to ensure uniqueness. * @param path1 path of the first file corresponding to @a revision1. * @param path2 path of the first file corresponding to @a revision2. * @param revision1 one of the revisions to check. * @param revision2 the other revision. * @param recurse whether the operation should be done recursively. * @param ignoreAncestry whether the files will be checked for * relatedness. * @param noDiffDeleted if true, no diff output will be generated * on deleted files. * @return delta between the files * @exception ClientException */ std::string diff(const Path & tmpPath, const Path & path1, const Path & path2, const Revision & revision1, const Revision & revision2, const bool recurse, const bool ignoreAncestry, - const bool noDiffDeleted) throw(ClientException); + const bool noDiffDeleted); /** * Produce diff output which describes the delta of * @a path/@a pegRevision between @a revision1 and @a revision2. * @a path can be either a working-copy path or a URL. * * A ClientException will be thrown if either @a revision1 or * @a revision2 has an `unspecified' or unrecognized `kind'. * * @param tmpPath prefix for a temporary directory needed by diff. * Filenames will have ".tmp" and similar added to this prefix in * order to ensure uniqueness. * @param path path of the file. * @param pegRevision the peg revision to identify the path. * @param revision1 one of the revisions to check. * @param revision2 the other revision. * @param recurse whether the operation should be done recursively. * @param ignoreAncestry whether the files will be checked for * relatedness. * @param noDiffDeleted if true, no diff output will be generated * on deleted files. * @return delta between the files * @exception ClientException */ std::string diff(const Path & tmpPath, const Path & path, const Revision & pegRevision, const Revision & revision1, const Revision & revision2, const bool recurse, const bool ignoreAncestry, const bool noDiffDeleted) - throw(ClientException); + ; /** * lists entries in @a pathOrUrl no matter whether local or * repository * * @return a vector of directory entries, each with * a relative path (only filename) */ DirEntries list(const char * pathOrUrl, svn_opt_revision_t * revision, - bool recurse) throw(ClientException); + bool recurse); /** * lists properties in @a path no matter whether local or * repository * * @return PropertiesList */ PathPropertiesMapList proplist(const Path &path, const Revision &revision, bool recurse = false); /** * lists one property in @a path no matter whether local or * repository * * @return PathPropertiesMapList */ PathPropertiesMapList propget(const char * propName, const Path & path, const Revision & revision, bool recurse = false); /** * This method is deprecated, please use * @a Property.set * set property in @a path no matter whether local or * repository * * @deprecated */ void propset(const char * propName, const char * propValue, const Path & path, const Revision & revision, bool recurse = false, bool skip_checks = true); /** * delete property in @a path no matter whether local or * repository * */ void propdel(const char * propName, const Path & path, const Revision & revision, bool recurse = false); /** * lists revision properties in @a path no matter whether local or * repository * * @return PropertiesList */ std::pair revproplist(const Path & path, const Revision & revision); /** * lists one revision property in @a path no matter whether local or * repository * * @return PropertiesList */ std::pair revpropget(const char * propName, const Path & path, const Revision & revision); /** * set revision property in @a path no matter whether local or * repository * * @return Revision */ svn_revnum_t revpropset(const char * propName, const char * propValue, const Path & path, const Revision & revision, bool force = false); /** * delete revision property in @a path no matter whether local or * repository * * @return Revision */ svn_revnum_t revpropdel(const char * propName, const Path & path, const Revision & revision, bool force = false); /** * Add a single file into ignore list. * * @param path path to the file * @exception ClientException * @see svn:ignore property description */ void - ignore(const Path & path) throw(ClientException); + ignore(const Path & path); /** * Add files into ignore list. * * @param targets targets to treat as ignored * @exception ClientException * @see svn:ignore property description */ void - ignore(const Targets & targets) throw(ClientException); + ignore(const Targets & targets); private: Context * m_context; /** * disallow assignment operator */ Client & operator= (const Client &); /** * disallow copy constructor */ Client(const Client &); }; } #endif /* ----------------------------------------------------------------- * local variables: * eval: (load-file "../../rapidsvn-dev.el") * end: */ diff --git a/plugins/subversion/kdevsvncpp/client_annotate.cpp b/plugins/subversion/kdevsvncpp/client_annotate.cpp index 7e2e5f6193..4e3b242a6c 100644 --- a/plugins/subversion/kdevsvncpp/client_annotate.cpp +++ b/plugins/subversion/kdevsvncpp/client_annotate.cpp @@ -1,81 +1,81 @@ /* * ==================================================================== * Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved. * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the file GPL.txt. * If not, see . * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://rapidsvn.tigris.org/. * ==================================================================== */ #if defined( _MSC_VER) && _MSC_VER <= 1200 #pragma warning( disable: 4786 )// debug symbol truncated #endif // Subversion api #include "svn_client.h" // svncpp #include "kdevsvncpp/client.hpp" namespace svn { static svn_error_t * annotateReceiver(void *baton, apr_int64_t line_no, svn_revnum_t revision, const char *author, const char *date, const char *line, apr_pool_t * /*pool*/) { AnnotatedFile * entries = (AnnotatedFile *) baton; entries->push_back( AnnotateLine(line_no, revision, author?author:"unknown", date?date:"unknown date", line?line:"???")); return nullptr; } AnnotatedFile * Client::annotate(const Path & path, const Revision & revisionStart, - const Revision & revisionEnd) throw(ClientException) + const Revision & revisionEnd) { Pool pool; AnnotatedFile * entries = new AnnotatedFile; svn_error_t *error; error = svn_client_blame( path.c_str(), revisionStart.revision(), revisionEnd.revision(), annotateReceiver, entries, *m_context, // client ctx pool); if (error != nullptr) { delete entries; throw ClientException(error); } return entries; } } diff --git a/plugins/subversion/kdevsvncpp/client_cat.cpp b/plugins/subversion/kdevsvncpp/client_cat.cpp index 08ca6e487f..356b213d7e 100644 --- a/plugins/subversion/kdevsvncpp/client_cat.cpp +++ b/plugins/subversion/kdevsvncpp/client_cat.cpp @@ -1,178 +1,177 @@ /* * ==================================================================== * Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved. * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the file GPL.txt. * If not, see . * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://rapidsvn.tigris.org/. * ==================================================================== */ #if defined( _MSC_VER) && _MSC_VER <= 1200 #pragma warning( disable: 4786 )// debug symbol truncated #endif // stl #include // Subversion api #include "svn_client.h" // svncpp #include "kdevsvncpp/client.hpp" #include "kdevsvncpp/exception.hpp" #include "kdevsvncpp/pool.hpp" #include "kdevsvncpp/status.hpp" #include "m_check.hpp" namespace svn { std::string Client::cat(const Path & path, const Revision & revision, - const Revision & peg_revision) throw(ClientException) + const Revision & peg_revision) { Pool pool; svn_stringbuf_t * stringbuf = svn_stringbuf_create("", pool); svn_stream_t * stream = svn_stream_from_stringbuf(stringbuf, pool); svn_error_t * error; error = svn_client_cat2(stream, path.c_str(), peg_revision.revision(), revision.revision(), *m_context, pool); if (error != nullptr) throw ClientException(error); return std::string(stringbuf->data, stringbuf->len); } /** * Create a new temporary file in @a dstPath. If @a dstPath * is empty (""), then construct the temporary filename * from the temporary directory and the filename component * of @a path. The file-extension of @a path will be transformed * to @a dstPath and @a dstPath will be a unique filename * * @param dstPath path to temporary file. Will be constructed * from @a path and temporary dir (and unique elements) * if empty string * @param path existing filename. Necessary only for construction * of @a dstPath * @param pool pool to use * @return open file */ static apr_file_t * openTempFile(Path & dstPath, const Path & path, const Revision & revision, Pool & pool) - throw(ClientException) { apr_file_t * file = nullptr; if (dstPath.length() > 0) { apr_status_t status = apr_file_open(&file, dstPath.c_str(), APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY, APR_OS_DEFAULT, pool); if (status != 0) throw ClientException(status); } else { // split the path into its components std::string dir, filename, ext; path.split(dir, filename, ext); // add the revision number to the filename char revstring[20]; if (revision.kind() == revision.HEAD) strcpy(revstring, "HEAD"); else sprintf(revstring, "%" SVN_REVNUM_T_FMT, revision.revnum()); filename += '-'; filename += revstring; // replace the dir component with tempdir Path tempPath = Path::getTempDir(); tempPath.addComponent(filename); const char * unique_name; svn_error_t * error = svn_io_open_unique_file( &file, &unique_name, tempPath.c_str(), // path ext.c_str(), // suffix 0, // dont delete on close pool); if (error != nullptr) throw ClientException(error); dstPath = unique_name; } return file; } void Client::get(Path & dstPath, const Path & path, const Revision & revision, - const Revision & peg_revision) throw(ClientException) + const Revision & peg_revision) { Pool pool; // create a new file and suppose we only want // this users to be able to read and write the file apr_file_t * file = openTempFile(dstPath, path, revision, pool); // now create a stream and let svn_client_cat write to the // stream svn_stream_t * stream = svn_stream_from_aprfile(file, pool); if (stream != nullptr) { svn_error_t * error = svn_client_cat2( stream, path.c_str(), peg_revision.revision() , revision.revision(), *m_context, pool); if (error != nullptr) throw ClientException(error); svn_stream_close(stream); } // finalize stuff apr_file_close(file); } } /* ----------------------------------------------------------------- * local variables: * eval: (load-file "../../rapidsvn-dev.el") * end: */ diff --git a/plugins/subversion/kdevsvncpp/client_diff.cpp b/plugins/subversion/kdevsvncpp/client_diff.cpp index ed21fb4c16..ae6b6f569b 100644 --- a/plugins/subversion/kdevsvncpp/client_diff.cpp +++ b/plugins/subversion/kdevsvncpp/client_diff.cpp @@ -1,340 +1,339 @@ /* * ==================================================================== * Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved. * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the file GPL.txt. * If not, see . * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://rapidsvn.tigris.org/. * ==================================================================== */ #if defined( _MSC_VER) && _MSC_VER <= 1200 #pragma warning( disable: 4786 )// debug symbol truncated #endif // Subversion api #include "svn_client.h" // svncpp #include "kdevsvncpp/client.hpp" #include "kdevsvncpp/exception.hpp" #include "kdevsvncpp/pool.hpp" #include "kdevsvncpp/status.hpp" namespace svn { /** * a quick way to create error messages */ static void fail(apr_pool_t *pool, apr_status_t status, const char *fmt, ...) { va_list ap; char *msg; svn_error_t * error; va_start(ap, fmt); msg = apr_pvsprintf(pool, fmt, ap); va_end(ap); error = svn_error_create(status, nullptr, msg); throw ClientException(error); } /** * closes and deletes temporary files that diff has been using */ static void diffCleanup(apr_file_t * outfile, const char * outfileName, apr_file_t * errfile, const char * errfileName, apr_pool_t *pool) { if (outfile != nullptr) apr_file_close(outfile); if (errfile != nullptr) apr_file_close(errfile); if (outfileName != nullptr) svn_error_clear(svn_io_remove_file(outfileName, pool)); if (errfileName != nullptr) svn_error_clear(svn_io_remove_file(errfileName, pool)); } std::string Client::diff(const Path & tmpPath, const Path & path, const Revision & revision1, const Revision & revision2, const bool recurse, const bool ignoreAncestry, - const bool noDiffDeleted) throw(ClientException) + const bool noDiffDeleted) { Pool pool; svn_error_t * error; apr_status_t status; apr_file_t * outfile = nullptr; const char * outfileName = nullptr; apr_file_t * errfile = nullptr; const char * errfileName = nullptr; apr_array_header_t * options; svn_stringbuf_t * stringbuf; // svn_client_diff needs an options array, even if it is empty options = apr_array_make(pool, 0, 0); // svn_client_diff needs a temporary file to write diff output to error = svn_io_open_unique_file(&outfile, &outfileName, tmpPath.c_str(), ".tmp", false, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // and another one to write errors to error = svn_io_open_unique_file(&errfile, &errfileName, tmpPath.c_str(), ".tmp", false, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // run diff error = svn_client_diff(options, path.c_str(), revision1.revision(), path.c_str(), revision2.revision(), recurse, ignoreAncestry, noDiffDeleted, outfile, errfile, *m_context, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // then we reopen outfile for reading status = apr_file_close(outfile); if (status) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); fail(pool, status, "failed to close '%s'", outfileName); } status = apr_file_open(&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool); if (status) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); fail(pool, status, "failed to open '%s'", outfileName); } // now we can read the diff output from outfile and return that error = svn_stringbuf_from_aprfile(&stringbuf, outfile, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } diffCleanup(outfile, outfileName, errfile, errfileName, pool); return stringbuf->data; } std::string Client::diff(const Path & tmpPath, const Path & path1, const Path & path2, const Revision & revision1, const Revision & revision2, const bool recurse, const bool ignoreAncestry, const bool noDiffDeleted) - throw(ClientException) { Pool pool; svn_error_t * error; apr_status_t status; apr_file_t * outfile = nullptr; const char * outfileName = nullptr; apr_file_t * errfile = nullptr; const char * errfileName = nullptr; apr_array_header_t * options; svn_stringbuf_t * stringbuf; // svn_client_diff needs an options array, even if it is empty options = apr_array_make(pool, 0, 0); // svn_client_diff needs a temporary file to write diff output to error = svn_io_open_unique_file(&outfile, &outfileName, tmpPath.c_str(), ".tmp", false, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // and another one to write errors to error = svn_io_open_unique_file(&errfile, &errfileName, tmpPath.c_str(), ".tmp", false, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // run diff error = svn_client_diff(options, path1.c_str(), revision1.revision(), path2.c_str(), revision2.revision(), recurse, ignoreAncestry, noDiffDeleted, outfile, errfile, *m_context, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // then we reopen outfile for reading status = apr_file_close(outfile); if (status) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); fail(pool, status, "failed to close '%s'", outfileName); } status = apr_file_open(&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool); if (status) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); fail(pool, status, "failed to open '%s'", outfileName); } // now we can read the diff output from outfile and return that error = svn_stringbuf_from_aprfile(&stringbuf, outfile, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } diffCleanup(outfile, outfileName, errfile, errfileName, pool); return stringbuf->data; } std::string Client::diff(const Path & tmpPath, const Path & path, const Revision & pegRevision, const Revision & revision1, const Revision & revision2, const bool recurse, const bool ignoreAncestry, - const bool noDiffDeleted) throw(ClientException) + const bool noDiffDeleted) { Pool pool; svn_error_t * error; apr_status_t status; apr_file_t * outfile = nullptr; const char * outfileName = nullptr; apr_file_t * errfile = nullptr; const char * errfileName = nullptr; apr_array_header_t * options; svn_stringbuf_t * stringbuf; // svn_client_diff needs an options array, even if it is empty options = apr_array_make(pool, 0, 0); // svn_client_diff needs a temporary file to write diff output to error = svn_io_open_unique_file(&outfile, &outfileName, tmpPath.c_str(), ".tmp", false, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // and another one to write errors to error = svn_io_open_unique_file(&errfile, &errfileName, tmpPath.c_str(), ".tmp", false, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // run diff error = svn_client_diff_peg(options, path.c_str(), pegRevision.revision(), revision1.revision(), revision2.revision(), recurse, ignoreAncestry, noDiffDeleted, outfile, errfile, *m_context, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } // then we reopen outfile for reading status = apr_file_close(outfile); if (status) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); fail(pool, status, "failed to close '%s'", outfileName); } status = apr_file_open(&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool); if (status) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); fail(pool, status, "failed to open '%s'", outfileName); } // now we can read the diff output from outfile and return that error = svn_stringbuf_from_aprfile(&stringbuf, outfile, pool); if (error != nullptr) { diffCleanup(outfile, outfileName, errfile, errfileName, pool); throw ClientException(error); } diffCleanup(outfile, outfileName, errfile, errfileName, pool); return stringbuf->data; } } /* ----------------------------------------------------------------- * local variables: * eval: (load-file "../../rapidsvn-dev.el") * end: */ diff --git a/plugins/subversion/kdevsvncpp/client_ls.cpp b/plugins/subversion/kdevsvncpp/client_ls.cpp index 95fd6cb919..c9915c4b63 100644 --- a/plugins/subversion/kdevsvncpp/client_ls.cpp +++ b/plugins/subversion/kdevsvncpp/client_ls.cpp @@ -1,166 +1,166 @@ /* * ==================================================================== * Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved. * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the file GPL.txt. * If not, see . * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://rapidsvn.tigris.org/. * ==================================================================== */ #if defined( _MSC_VER) && _MSC_VER <= 1200 #pragma warning( disable: 4786 )// debug symbol truncated #endif // subversion api #include "svn_client.h" #include "svn_path.h" #include "svn_sorts.h" #include "svn_version.h" //#include "svn_utf.h" // svncpp #include "kdevsvncpp/client.hpp" #include "kdevsvncpp/dirent.hpp" #include "kdevsvncpp/exception.hpp" #if SVN_VER_MAJOR == 1 && SVN_VER_MINOR < 8 static int compare_items_as_paths(const svn_sort__item_t *a, const svn_sort__item_t *b) { return svn_path_compare_paths((const char *)a->key, (const char *)b->key); } namespace svn { DirEntries Client::list(const char * pathOrUrl, svn_opt_revision_t * revision, bool recurse) throw(ClientException) { Pool pool; apr_hash_t * hash; svn_error_t * error = svn_client_ls(&hash, pathOrUrl, revision, recurse, *m_context, pool); if (error != 0) throw ClientException(error); apr_array_header_t * array = svn_sort__hash( hash, compare_items_as_paths, pool); DirEntries entries; for (int i = 0; i < array->nelts; ++i) { const char *entryname; svn_dirent_t *dirent; svn_sort__item_t *item; item = &APR_ARRAY_IDX(array, i, svn_sort__item_t); entryname = static_cast(item->key); dirent = static_cast (apr_hash_get(hash, entryname, item->klen)); entries.push_back(DirEntry(entryname, dirent)); } return entries; } } #else #include static svn_error_t* store_entry( void *baton, const char *path, const svn_dirent_t *dirent, const svn_lock_t *, const char *abs_path, const char *, const char *, apr_pool_t *scratch_pool) { svn::DirEntries *entries = reinterpret_cast(baton); if (path[0] == '\0') { if (dirent->kind == svn_node_file) { // for compatibility with svn_client_ls behaviour, listing a file // stores that file name entries->push_back(svn::DirEntry(svn_path_basename(abs_path, scratch_pool), dirent)); } } else { entries->push_back(svn::DirEntry(path, dirent)); } return SVN_NO_ERROR; } static bool sort_by_path(svn::DirEntry const& a, svn::DirEntry const& b) { return svn_path_compare_paths(a.name(), b.name()) < 0; } namespace svn { DirEntries Client::list(const char * pathOrUrl, svn_opt_revision_t * revision, - bool recurse) throw(ClientException) + bool recurse) { Pool pool; DirEntries entries; svn_error_t * error = svn_client_list3(pathOrUrl, revision, revision, SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse), SVN_DIRENT_ALL, FALSE, // fetch locks FALSE, // include externals &store_entry, &entries, *m_context, pool); if (error != SVN_NO_ERROR) throw ClientException(error); std::sort(entries.begin(), entries.end(), &sort_by_path); return entries; } } #endif /* ----------------------------------------------------------------- * local variables: * eval: (load-file "../../rapidsvn-dev.el") * end: */ diff --git a/plugins/subversion/kdevsvncpp/client_modify.cpp b/plugins/subversion/kdevsvncpp/client_modify.cpp index c125d4be46..5bb714d4bb 100644 --- a/plugins/subversion/kdevsvncpp/client_modify.cpp +++ b/plugins/subversion/kdevsvncpp/client_modify.cpp @@ -1,554 +1,554 @@ /* * ==================================================================== * Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved. * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the file GPL.txt. * If not, see . * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://rapidsvn.tigris.org/. * ==================================================================== */ #if defined( _MSC_VER) && _MSC_VER <= 1200 #pragma warning( disable: 4786 )// debug symbol truncated #endif // subversion api #include "svn_client.h" // svncpp #include "kdevsvncpp/client.hpp" #include "kdevsvncpp/exception.hpp" #include "kdevsvncpp/pool.hpp" #include "kdevsvncpp/targets.hpp" #include "m_check.hpp" namespace svn { svn_revnum_t Client::checkout(const char * url, const Path & destPath, const Revision & revision, bool recurse, bool ignore_externals, - const Revision & peg_revision) throw(ClientException) + const Revision & peg_revision) { Pool subPool; apr_pool_t * apr_pool = subPool.pool(); svn_revnum_t revnum = 0; svn_error_t * error = svn_client_checkout2(&revnum, url, destPath.c_str(), peg_revision.revision(), // peg_revision revision.revision(), // revision recurse, ignore_externals, *m_context, apr_pool); if (error != nullptr) throw ClientException(error); return revnum; } void Client::remove(const Path & path, - bool force) throw(ClientException) + bool force) { Pool pool; Targets targets(path.c_str()); svn_client_commit_info_t *commit_info = nullptr; svn_error_t * error = svn_client_delete(&commit_info, const_cast(targets.array(pool)), force, *m_context, pool); if (error != nullptr) throw ClientException(error); } void Client::remove(const Targets & targets, - bool force) throw(ClientException) + bool force) { Pool pool; svn_client_commit_info_t *commit_info = nullptr; svn_error_t * error = svn_client_delete(&commit_info, const_cast(targets.array(pool)), force, *m_context, pool); if (error != nullptr) throw ClientException(error); } void Client::lock(const Targets & targets, bool force, - const char * comment) throw(ClientException) + const char * comment) { Pool pool; svn_error_t * error = svn_client_lock(const_cast(targets.array(pool)), comment, force, *m_context, pool); if (error != nullptr) throw ClientException(error); } void - Client::unlock(const Targets & targets, bool force) throw(ClientException) + Client::unlock(const Targets & targets, bool force) { Pool pool; svn_error_t * error = svn_client_unlock(const_cast(targets.array(pool)), force, *m_context, pool); if (error != nullptr) throw ClientException(error); } void Client::revert(const Targets & targets, - bool recurse) throw(ClientException) + bool recurse) { Pool pool; svn_error_t * error = svn_client_revert((targets.array(pool)), recurse, *m_context, pool); if (error != nullptr) throw ClientException(error); } void Client::add(const Path & path, - bool recurse) throw(ClientException) + bool recurse) { Pool pool; // we do not need the newer version of this // function "svn_client_add2" or "svn_client_add3" // since RapidSVN doesnt even have a dialog // for adding false svn_error_t * error = svn_client_add(path.c_str(), recurse, *m_context, pool); if (error != nullptr) throw ClientException(error); } std::vector Client::update(const Targets & targets, const Revision & revision, bool recurse, - bool ignore_externals) throw(ClientException) + bool ignore_externals) { Pool pool; apr_array_header_t * result_revs; svn_error_t * error = svn_client_update2(&result_revs, const_cast(targets.array(pool)), revision.revision(), recurse, ignore_externals, *m_context, pool); if (error != nullptr) throw ClientException(error); std::vector revnums; int i; for (i = 0; i < result_revs->nelts; i++) { svn_revnum_t revnum= APR_ARRAY_IDX(result_revs, i, svn_revnum_t); revnums.push_back(revnum); } return revnums; } svn_revnum_t Client::update(const Path & path, const Revision & revision, bool recurse, - bool ignore_externals) throw(ClientException) + bool ignore_externals) { Targets targets(path.c_str()); return update(targets, revision, recurse, ignore_externals)[0]; } svn_revnum_t Client::commit(const Targets & targets, const char * message, bool recurse, - bool keep_locks) throw(ClientException) + bool keep_locks) { Pool pool; m_context->setLogMessage(message); svn_client_commit_info_t *commit_info = nullptr; svn_error_t * error = svn_client_commit2(&commit_info, targets.array(pool), recurse, keep_locks, *m_context, pool); if (error != nullptr) throw ClientException(error); if (commit_info && SVN_IS_VALID_REVNUM(commit_info->revision)) return commit_info->revision; return -1; } void Client::copy(const Path & srcPath, const Revision & srcRevision, - const Path & destPath) throw(ClientException) + const Path & destPath) { Pool pool; svn_client_commit_info_t *commit_info = nullptr; svn_error_t * error = svn_client_copy(&commit_info, srcPath.c_str(), srcRevision.revision(), destPath.c_str(), *m_context, pool); if (error != nullptr) throw ClientException(error); } void Client::move(const Path & srcPath, const Revision & /*srcRevision*/, const Path & destPath, - bool force) throw(ClientException) + bool force) { Pool pool; svn_client_commit_info_t *commit_info = nullptr; svn_error_t * error = svn_client_move2(&commit_info, srcPath.c_str(), destPath.c_str(), force, *m_context, pool); if (error != nullptr) throw ClientException(error); } void - Client::mkdir(const Path & path) throw(ClientException) + Client::mkdir(const Path & path) { Pool pool; Targets targets(path.c_str()); svn_client_commit_info_t *commit_info = nullptr; svn_error_t * error = svn_client_mkdir(&commit_info, const_cast (targets.array(pool)), *m_context, pool); if (error != nullptr) throw ClientException(error); } void - Client::mkdir(const Targets & targets) throw(ClientException) + Client::mkdir(const Targets & targets) { Pool pool; svn_client_commit_info_t *commit_info = nullptr; svn_error_t * error = svn_client_mkdir(&commit_info, const_cast (targets.array(pool)), *m_context, pool); if (error != nullptr) throw ClientException(error); } void - Client::cleanup(const Path & path) throw(ClientException) + Client::cleanup(const Path & path) { Pool subPool; apr_pool_t * apr_pool = subPool.pool(); svn_error_t * error = svn_client_cleanup(path.c_str(), *m_context, apr_pool); if (error != nullptr) throw ClientException(error); } void Client::resolved(const Path & path, - bool recurse) throw(ClientException) + bool recurse) { Pool pool; svn_error_t * error = svn_client_resolved(path.c_str(), recurse, *m_context, pool); if (error != nullptr) throw ClientException(error); } void Client::doExport(const Path & from_path, const Path & to_path, const Revision & revision, bool overwrite, const Revision & peg_revision, bool ignore_externals, bool recurse, - const char * native_eol) throw(ClientException) + const char * native_eol) { Pool pool; svn_revnum_t revnum = 0; svn_error_t * error = svn_client_export3(&revnum, from_path.c_str(), to_path.c_str(), peg_revision.revision(), revision.revision(), overwrite, ignore_externals, recurse, native_eol, *m_context, pool); if (error != nullptr) throw ClientException(error); } svn_revnum_t Client::doSwitch(const Path & path, const char * url, const Revision & revision, - bool recurse) throw(ClientException) + bool recurse) { Pool pool; svn_revnum_t revnum = 0; svn_error_t * error = svn_client_switch(&revnum, path.c_str(), url, revision.revision(), recurse, *m_context, pool); if (error != nullptr) throw ClientException(error); return revnum; } void Client::import(const Path & path, const char * url, const char * message, - bool recurse) throw(ClientException) + bool recurse) { Pool pool; svn_client_commit_info_t *commit_info = nullptr; m_context->setLogMessage(message); svn_error_t * error = svn_client_import(&commit_info, path.c_str(), url, !recurse, *m_context, pool); if (error != nullptr) throw ClientException(error); } void Client::import(const Path & path, const Path & url, const char * message, - bool recurse) throw(ClientException) + bool recurse) { import(path, url.c_str(), message, recurse); } void Client::merge(const Path & path1, const Revision & revision1, const Path & path2, const Revision & revision2, const Path & localPath, bool force, bool recurse, bool notice_ancestry, - bool dry_run) throw(ClientException) + bool dry_run) { Pool pool; svn_error_t * error = svn_client_merge(path1.c_str(), revision1.revision(), path2.c_str(), revision2.revision(), localPath.c_str(), recurse, !notice_ancestry, force, dry_run, *m_context, pool); if (error != nullptr) throw ClientException(error); } void Client::relocate(const Path & path, const char * from_url, const char * to_url, - bool recurse) throw(ClientException) + bool recurse) { Pool pool; svn_error_t * error = svn_client_relocate(path.c_str(), from_url, to_url, recurse, *m_context, pool); if (error != nullptr) throw ClientException(error); } void - Client::ignore(const Path & path) throw(ClientException) + Client::ignore(const Path & path) { static const char s_svnIgnore[] = "svn:ignore"; Pool pool; std::string dirpath, basename; path.split(dirpath, basename); Revision revision; apr_hash_t *props; svn_error_t * error = svn_client_propget(&props, s_svnIgnore, dirpath.c_str(), Revision::UNSPECIFIED.revision(), false, // recursive *m_context, pool); if (error != nullptr) throw ClientException(error); PathPropertiesMapList path_prop_map_list; apr_hash_index_t *hi; for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi)) { PropertiesMap prop_map; const void *key; void *val; apr_hash_this(hi, &key, nullptr, &val); prop_map [std::string(s_svnIgnore)] = std::string(((const svn_string_t *)val)->data); path_prop_map_list.push_back(PathPropertiesMapEntry((const char *)key, prop_map)); } std::string str = basename; for (PathPropertiesMapList::const_iterator i=path_prop_map_list.begin(), ei=path_prop_map_list.end();i!=ei;++i) { if (dirpath != i->first) continue; for (PropertiesMap::const_iterator j=i->second.begin(), ej=i->second.end(); j != ej; ++j) { if (s_svnIgnore != j->first) continue; str += '\n'+j->second; } } const svn_string_t * propval = svn_string_create(str.c_str(), pool); error = svn_client_propset2(s_svnIgnore, propval, dirpath.c_str(), false, false, *m_context, pool); if (error != nullptr) throw ClientException(error); } void - Client::ignore(const Targets & targets) throw(ClientException) + Client::ignore(const Targets & targets) { // it's slow, but simple for (std::vector::const_iterator i=targets.targets().begin(), e=targets.targets().end();i!=e;++i) { ignore(*i); } } } /* ----------------------------------------------------------------- * local variables: * eval: (load-file "../../rapidsvn-dev.el") * end: */ diff --git a/plugins/subversion/kdevsvncpp/client_status.cpp b/plugins/subversion/kdevsvncpp/client_status.cpp index 66c215b653..8b4e72c2a2 100644 --- a/plugins/subversion/kdevsvncpp/client_status.cpp +++ b/plugins/subversion/kdevsvncpp/client_status.cpp @@ -1,418 +1,418 @@ /* * ==================================================================== * Copyright (c) 2002-2009 The RapidSvn Group. All rights reserved. * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (in the file GPL.txt. * If not, see . * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://rapidsvn.tigris.org/. * ==================================================================== */ #if defined( _MSC_VER) && _MSC_VER <= 1200 #pragma warning( disable: 4786 )// debug symbol truncated #endif // Stdlib (for strcmp) #include "string.h" // Subversion api #include "svn_client.h" #include "svn_sorts.h" //#include "svn_utf.h" // svncpp #include "kdevsvncpp/client.hpp" #include "kdevsvncpp/dirent.hpp" #include "kdevsvncpp/exception.hpp" #include "kdevsvncpp/info.hpp" #include "kdevsvncpp/pool.hpp" #include "kdevsvncpp/status.hpp" #include "kdevsvncpp/targets.hpp" #include "kdevsvncpp/url.hpp" namespace svn { static svn_error_t * logReceiver(void *baton, apr_hash_t * changedPaths, svn_revnum_t rev, const char *author, const char *date, const char *msg, apr_pool_t * pool) { LogEntries * entries = (LogEntries *) baton; entries->insert(entries->begin(), LogEntry(rev, author, date, msg)); if (changedPaths != nullptr) { LogEntry &entry = entries->front(); for (apr_hash_index_t *hi = apr_hash_first(pool, changedPaths); hi != nullptr; hi = apr_hash_next(hi)) { char *path; void *val; apr_hash_this(hi, (const void **)&path, nullptr, &val); svn_log_changed_path_t *log_item = reinterpret_cast(val); entry.changedPaths.push_back( LogChangePathEntry(path, log_item->action, log_item->copyfrom_path, log_item->copyfrom_rev)); } } return nullptr; } static void statusEntriesFunc(void *baton, const char *path, svn_wc_status2_t *status) { StatusEntries * entries = static_cast(baton); entries->push_back(Status(path, status)); } static StatusEntries localStatus(const char * path, const bool descend, const bool get_all, const bool update, const bool no_ignore, Context * context, const bool ignore_externals) { svn_error_t *error; StatusEntries entries; svn_revnum_t revnum; Revision rev(Revision::HEAD); Pool pool; error = svn_client_status2( &revnum, // revnum path, // path rev, // revision statusEntriesFunc, // status func &entries, // status baton descend, // recurse get_all, update, // need 'update' to be true to get repository lock info no_ignore, ignore_externals, // ignore_externals *context, // client ctx pool); if (error!=nullptr) throw ClientException(error); return entries; } static Status dirEntryToStatus(const char * path, const DirEntry & dirEntry) { Pool pool; svn_wc_entry_t * e = static_cast( apr_pcalloc(pool, sizeof(svn_wc_entry_t))); std::string url(path); url += '/'; url += dirEntry.name(); e->name = dirEntry.name(); e->revision = dirEntry.createdRev(); e->url = url.c_str(); e->kind = dirEntry.kind(); e->schedule = svn_wc_schedule_normal; e->text_time = dirEntry.time(); e->prop_time = dirEntry.time(); e->cmt_rev = dirEntry.createdRev(); e->cmt_date = dirEntry.time(); e->cmt_author = dirEntry.lastAuthor(); svn_wc_status2_t * s = static_cast( apr_pcalloc(pool, sizeof(svn_wc_status2_t))); s->entry = e; s->text_status = svn_wc_status_normal; s->prop_status = svn_wc_status_normal; s->locked = 0; s->switched = 0; s->repos_text_status = svn_wc_status_normal; s->repos_prop_status = svn_wc_status_normal; return Status(url.c_str(), s); } static svn_revnum_t remoteStatus(Client * client, const char * path, const bool descend, StatusEntries & entries, Context * /*context*/) { Revision rev(Revision::HEAD); DirEntries dirEntries = client->list(path, rev, descend); DirEntries::const_iterator it; svn_revnum_t revnum = 0; for (it = dirEntries.begin(); it != dirEntries.end(); ++it) { const DirEntry & dirEntry = *it; entries.push_back(dirEntryToStatus(path, dirEntry)); } if (dirEntries.size() > 0) revnum = dirEntries[0].createdRev(); return revnum; } StatusEntries Client::status(const char * path, const bool descend, const bool get_all, const bool update, const bool no_ignore, - const bool ignore_externals) throw(ClientException) + const bool ignore_externals) { if (Url::isValid(path)) { StatusEntries entries; remoteStatus(this, path, descend, entries, m_context); return entries; } else return localStatus(path, descend, get_all, update, no_ignore, m_context, ignore_externals); } struct StatusFilter; struct StatusBaton { public: const StatusFilter & filter; StatusEntries & entries; StatusBaton(const StatusFilter & filter_, StatusEntries & entries_) : filter(filter_), entries(entries_) { } }; static void filteredStatusFunc(void *baton_, const char *path, svn_wc_status2_t *status) { StatusBaton * baton = static_cast(baton_); // now we have to decide whether to return the entry or not if (nullptr == status) return; bool useStatus = false; bool isUnversioned = nullptr == status->entry; if (isUnversioned) { // unversioned if (baton->filter.showUnversioned) useStatus = true; } else { bool isUnmodified = ((svn_wc_status_normal == status->text_status) && (svn_wc_status_normal == status->prop_status)); if (isUnmodified) { if (baton->filter.showUnmodified) useStatus = true; } else { // so here we know its modified. // what are we interested in? if (baton->filter.showModified) useStatus = true; else if (baton->filter.showConflicted) { if (svn_wc_status_conflicted == status->text_status) useStatus = true; } } } if (useStatus) baton->entries.push_back(Status(path, status)); } static svn_revnum_t localFilteredStatus(const char * path, const StatusFilter & filter, const bool descend, const bool update, StatusEntries & entries, Context * context) { svn_error_t *error; svn_revnum_t revnum; Revision rev(Revision::HEAD); Pool pool; StatusBaton baton(filter, entries); error = svn_client_status2( &revnum, // revnum path, // path rev, // revision filteredStatusFunc, // status func &baton, // status baton descend, // recurse filter.showUnmodified, update, // need 'update' to be true to get repository lock info filter.showIgnored, // no_ignores !filter.showExternals, // ignore_externals *context, // client ctx pool); if (error!=nullptr) throw ClientException(error); return revnum; } svn_revnum_t Client::status(const char * path, const StatusFilter & filter, const bool descend, const bool update, - StatusEntries & entries) throw(ClientException) + StatusEntries & entries) { entries.clear(); if (Url::isValid(path)) return remoteStatus(this, path, descend, entries, m_context); else { // remote URLs only need a subset of the filters: // we dont expect any modified, conflicting, unknown, // ignored entries. And externals arent visible there anyhow return localFilteredStatus( path, filter, descend, update, entries, m_context); } } const LogEntries * Client::log(const char * path, const Revision & revisionStart, const Revision & revisionEnd, bool discoverChangedPaths, - bool strictNodeHistory) throw(ClientException) + bool strictNodeHistory) { Pool pool; Targets target(path); LogEntries * entries = new LogEntries(); svn_error_t *error; int limit = 0; error = svn_client_log2( target.array(pool), revisionStart.revision(), revisionEnd.revision(), limit, discoverChangedPaths ? 1 : 0, strictNodeHistory ? 1 : 0, logReceiver, entries, *m_context, // client ctx pool); if (error != nullptr) { delete entries; throw ClientException(error); } return entries; } /** * callback function for Client::info, will be * called for every entry svn_client_info wants to * return */ static svn_error_t * infoReceiverFunc(void * baton, const char * path, const svn_info_t * info, apr_pool_t * /*pool*/) { InfoVector * infoVector = static_cast(baton); infoVector->push_back(Info(path, info)); return nullptr; } InfoVector Client::info(const Path & pathOrUrl, bool recurse, const Revision & revision, - const Revision & pegRevision) throw(ClientException) + const Revision & pegRevision) { Pool pool; InfoVector infoVector; svn_error_t * error = svn_client_info(pathOrUrl.c_str(), pegRevision.revision(), revision.revision(), infoReceiverFunc, &infoVector, recurse, *m_context, pool); if (error != nullptr) throw ClientException(error); return infoVector; } } /* ----------------------------------------------------------------- * local variables: * eval: (load-file "../../rapidsvn-dev.el") * end: */ diff --git a/plugins/subversion/svnclient.cpp b/plugins/subversion/svnclient.cpp index 5889678d4f..1de142d5ae 100644 --- a/plugins/subversion/svnclient.cpp +++ b/plugins/subversion/svnclient.cpp @@ -1,335 +1,332 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * * * Parts of the file are copied from the RapidSvn C++ library * * Copyright (c) 2002-2006 The RapidSvn Group. All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "svnclient.h" #include #include #include extern "C" { #include #include } #include "kdevsvncpp/targets.hpp" #include "kdevsvncpp/pool.hpp" #include #include void fail (apr_pool_t *pool, apr_status_t status, const char *fmt, ...) { va_list ap; char *msg; svn_error_t * error; va_start (ap, fmt); msg = apr_pvsprintf (pool, fmt, ap); va_end (ap); error = svn_error_create (status, nullptr, msg); throw svn::ClientException (error); } void cleanup( apr_file_t* outfile, const char* outfileName, apr_file_t* errfile, const char* errfileName, const svn::Pool& pool ) { if( outfile != nullptr ) { apr_file_close( outfile ); } if( errfile != nullptr ) { apr_file_close( outfile ); } if( outfileName != nullptr ) { svn_error_clear( svn_io_remove_file ( outfileName, pool ) ); } if( errfileName != nullptr ) { svn_error_clear( svn_io_remove_file ( errfileName, pool ) ); } } SvnClient::SvnClient( svn::Context* ctx ) : QObject(nullptr), svn::Client( ctx ), m_ctxt( ctx ) { } QString SvnClient::diff( const svn::Path& src, const svn::Revision& srcRev, const svn::Path& dst, const svn::Revision& dstRev, const bool recurse, const bool ignoreAncestry, const bool noDiffDeleted, const bool ignoreContentType ) - throw (svn::ClientException) { svn::Pool pool; // null options apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", false, pool ); svn_error_t* error; const char* outfileName = nullptr; apr_file_t* outfile = nullptr; const char* errfileName = nullptr; apr_file_t* errfile = nullptr; QByteArray ba = QString(QStandardPaths::writableLocation(QStandardPaths::TempLocation)+"/kdevelop_svn_diff" ).toUtf8(); error = svn_io_open_unique_file( &outfile, &outfileName, ba.data(), ".tmp", false, pool ); if( error != nullptr ) { ::cleanup( outfile, outfileName, errfile, errfileName, pool ); throw svn::ClientException( error ); } error = svn_io_open_unique_file( &errfile, &errfileName, ba.data(), ".tmp", false, pool ); if( error != nullptr ) { ::cleanup( outfile, outfileName, errfile, errfileName, pool ); throw svn::ClientException( error ); } error = svn_client_diff3( options, src.c_str(), srcRev.revision(), dst.c_str(), dstRev.revision(), recurse, ignoreAncestry, noDiffDeleted, ignoreContentType, "UTF-8", outfile, errfile, m_ctxt->ctx(), pool ); if ( error ) { ::cleanup( outfile, outfileName, errfile, errfileName, pool ); throw svn::ClientException(error); } // then we reopen outfile for reading apr_status_t aprstatus = apr_file_close (outfile); if (aprstatus) { ::cleanup (outfile, outfileName, errfile, errfileName, pool); ::fail (pool, aprstatus, "failed to close '%s'", outfileName); } aprstatus = apr_file_open (&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool); if (aprstatus) { ::cleanup (outfile, outfileName, errfile, errfileName, pool); ::fail (pool, aprstatus, "failed to open '%s'", outfileName); } svn_stringbuf_t* stringbuf; // now we can read the diff output from outfile and return that error = svn_stringbuf_from_aprfile (&stringbuf, outfile, pool); if (error != nullptr) { ::cleanup (outfile, outfileName, errfile, errfileName, pool); throw svn::ClientException (error); } ::cleanup (outfile, outfileName, errfile, errfileName, pool); return QString::fromUtf8( stringbuf->data ); } QString SvnClient::diff( const svn::Path& src, const svn::Revision& pegRev, const svn::Revision& srcRev, const svn::Revision& dstRev, const bool recurse, const bool ignoreAncestry, const bool noDiffDeleted, const bool ignoreContentType ) - throw (svn::ClientException) { svn::Pool pool; // null options apr_array_header_t *options = svn_cstring_split( "", "\t\r\n", false, pool ); svn_error_t* error; const char* outfileName = nullptr; apr_file_t* outfile = nullptr; const char* errfileName = nullptr; apr_file_t* errfile = nullptr; QByteArray ba = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toUtf8(); error = svn_io_open_unique_file( &outfile, &outfileName, ba.data(), ".tmp", false, pool ); if( error != nullptr ) { ::cleanup( outfile, outfileName, errfile, errfileName, pool ); throw svn::ClientException( error ); } error = svn_io_open_unique_file( &errfile, &errfileName, ba.data(), ".tmp", false, pool ); if( error != nullptr ) { ::cleanup( outfile, outfileName, errfile, errfileName, pool ); throw svn::ClientException( error ); } error = svn_client_diff_peg3( options, src.c_str(), pegRev.revision(), srcRev.revision(), dstRev.revision(), recurse, ignoreAncestry, noDiffDeleted, ignoreContentType, "UTF-8", outfile, errfile, m_ctxt->ctx(), pool ); if ( error ) { ::cleanup( outfile, outfileName, errfile, errfileName, pool ); throw svn::ClientException(error); } // then we reopen outfile for reading apr_status_t aprstatus = apr_file_close (outfile); if (aprstatus) { ::cleanup (outfile, outfileName, errfile, errfileName, pool); ::fail (pool, aprstatus, "failed to close '%s'", outfileName); } aprstatus = apr_file_open (&outfile, outfileName, APR_READ, APR_OS_DEFAULT, pool); if (aprstatus) { ::cleanup (outfile, outfileName, errfile, errfileName, pool); ::fail (pool, aprstatus, "failed to open '%s'", outfileName); } svn_stringbuf_t* stringbuf; // now we can read the diff output from outfile and return that error = svn_stringbuf_from_aprfile (&stringbuf, outfile, pool); if (error != nullptr) { ::cleanup (outfile, outfileName, errfile, errfileName, pool); throw svn::ClientException(error); } ::cleanup (outfile, outfileName, errfile, errfileName, pool); return QString::fromUtf8( stringbuf->data ); } static svn_error_t * kdev_logReceiver (void *baton, apr_hash_t * changedPaths, svn_revnum_t rev, const char *author, const char *date, const char *msg, apr_pool_t * pool) { SvnClient* client = (SvnClient *) baton; KDevelop::VcsEvent ev; ev.setAuthor( QString::fromUtf8( author ) ); ev.setDate( QDateTime::fromString( QString::fromUtf8( date ), Qt::ISODate ) ); ev.setMessage( QString::fromUtf8( msg ) ); KDevelop::VcsRevision vcsrev; vcsrev.setRevisionValue( QVariant( qlonglong( rev ) ), KDevelop::VcsRevision::GlobalNumber ); ev.setRevision( vcsrev ); if (changedPaths != nullptr) { for (apr_hash_index_t *hi = apr_hash_first (pool, changedPaths); hi != nullptr; hi = apr_hash_next (hi)) { char *path; void *val; apr_hash_this (hi, (const void **)&path, nullptr, &val); svn_log_changed_path_t *log_item = reinterpret_cast (val); KDevelop::VcsItemEvent iev; iev.setRepositoryLocation( QString::fromUtf8( path ) ); iev.setRepositoryCopySourceLocation( QString::fromUtf8( log_item->copyfrom_path ) ); KDevelop::VcsRevision irev; irev.setRevisionValue( QVariant( qlonglong( log_item->copyfrom_rev ) ), KDevelop::VcsRevision::GlobalNumber ); iev.setRepositoryCopySourceRevision( irev ); switch( log_item->action ) { case 'A': iev.setActions( KDevelop::VcsItemEvent::Added ); break; case 'M': iev.setActions( KDevelop::VcsItemEvent::Modified ); break; case 'D': iev.setActions( KDevelop::VcsItemEvent::Deleted ); break; case 'R': iev.setActions( KDevelop::VcsItemEvent::Replaced ); break; } auto items = ev.items(); items.append( iev ); ev.setItems( items ); } } client->emitLogEventReceived( ev ); return nullptr; } void SvnClient::log( const char* path, const svn::Revision& start, const svn::Revision& end, int limit, bool discoverChangedPaths, bool strictNodeHistory ) - throw (svn::ClientException) { svn::Pool pool; svn::Targets target(path); svn_error_t *error; error = svn_client_log2 ( target.array(pool), start.revision(), end.revision(), limit, discoverChangedPaths ? 1 : 0, strictNodeHistory ? 1 : 0, kdev_logReceiver, this, m_ctxt->ctx(), // client ctx pool); if (error != nullptr) { throw svn::ClientException (error); } } void SvnClient::emitLogEventReceived( const KDevelop::VcsEvent& ev ) { emit logEventReceived( ev ); } diff --git a/plugins/subversion/svnclient.h b/plugins/subversion/svnclient.h index 77388bf7a5..bea8e65ca4 100644 --- a/plugins/subversion/svnclient.h +++ b/plugins/subversion/svnclient.h @@ -1,71 +1,68 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef KDEVPLATFORM_PLUGIN_SVNCLIENT_H #define KDEVPLATFORM_PLUGIN_SVNCLIENT_H #include #include #include "kdevsvncpp/path.hpp" #include "kdevsvncpp/revision.hpp" #include "kdevsvncpp/client.hpp" #include namespace KDevelop { class VcsAnnotationLine; } class SvnClient : public QObject, public svn::Client { Q_OBJECT public: explicit SvnClient( svn::Context* = nullptr ); QString diff( const svn::Path& src, const svn::Revision& srcRev, const svn::Path& dst, const svn::Revision& dstRev, const bool recurse, const bool ignoreAncestry, - const bool noDiffDeleted, const bool ignoreContentType ) - throw (svn::ClientException); + const bool noDiffDeleted, const bool ignoreContentType ); QString diff( const svn::Path& src, const svn::Revision& pegRev, const svn::Revision& srcRev, const svn::Revision& dstRev, const bool recurse, const bool ignoreAncestry, - const bool noDiffDeleted, const bool ignoreContentType ) - throw (svn::ClientException); + const bool noDiffDeleted, const bool ignoreContentType ); void log( const char* path, const svn::Revision& start, const svn::Revision& end, int limit, bool discoverChangedPaths = false, - bool strictNodeHistory = true ) - throw (svn::ClientException); + bool strictNodeHistory = true ); void emitLogEventReceived( const KDevelop::VcsEvent& ); signals: void logEventReceived( const KDevelop::VcsEvent& ); private: svn::Context* m_ctxt; }; #endif