Changeset View
Changeset View
Standalone View
Standalone View
plugins/patchreview/patchhighlighter.cpp
Show First 20 Lines • Show All 64 Lines • ▼ Show 20 Line(s) | 54 | QSize sizeHintForHtml( QString html, QSize maxSize ) { | |||
---|---|---|---|---|---|
65 | ret.setHeight( doc.size().height() ); | 65 | ret.setHeight( doc.size().height() ); | ||
66 | if( ret.height() > maxSize.height() ) | 66 | if( ret.height() > maxSize.height() ) | ||
67 | ret.setHeight( maxSize.height() ); | 67 | ret.setHeight( maxSize.height() ); | ||
68 | return ret; | 68 | return ret; | ||
69 | } | 69 | } | ||
70 | 70 | | |||
71 | } | 71 | } | ||
72 | 72 | | |||
73 | const unsigned int PatchHighlighter::m_allmarks = | ||||
74 | KTextEditor::MarkInterface::markType22 | KTextEditor::MarkInterface::markType23 | | ||||
75 | KTextEditor::MarkInterface::markType24 | KTextEditor::MarkInterface::markType25 | | ||||
76 | KTextEditor::MarkInterface::markType26 | KTextEditor::MarkInterface::markType27; | ||||
77 | | ||||
73 | void PatchHighlighter::showToolTipForMark(const QPoint& pos, KTextEditor::MovingRange* markRange) | 78 | void PatchHighlighter::showToolTipForMark(const QPoint& pos, KTextEditor::MovingRange* markRange) | ||
74 | { | 79 | { | ||
75 | if( currentTooltipMark == markRange && currentTooltip ) | 80 | if( currentTooltipMark == markRange && currentTooltip ) | ||
76 | return; | 81 | return; | ||
77 | delete currentTooltip; | 82 | delete currentTooltip; | ||
78 | 83 | | |||
79 | //Got the difference | 84 | //Got the difference | ||
80 | Diff2::Difference* diff = m_differencesForRanges[markRange]; | 85 | Diff2::Difference* diff = m_ranges[markRange]; | ||
81 | 86 | | |||
82 | QString html; | 87 | QString html; | ||
83 | #if 0 | 88 | #if 0 | ||
84 | if( diff->hasConflict() ) | 89 | if( diff->hasConflict() ) | ||
85 | html += i18n( "<b><span style=\"color:red\">Conflict</span></b><br/>" ); | 90 | html += i18n( "<b><span style=\"color:red\">Conflict</span></b><br/>" ); | ||
86 | #endif | 91 | #endif | ||
87 | 92 | | |||
88 | Diff2::DifferenceStringList lines; | 93 | Diff2::DifferenceStringList lines; | ||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Line(s) | |||||
162 | 167 | | |||
163 | currentTooltip = tooltip; | 168 | currentTooltip = tooltip; | ||
164 | currentTooltipMark = markRange; | 169 | currentTooltipMark = markRange; | ||
165 | 170 | | |||
166 | ActiveToolTip::showToolTip( tooltip ); | 171 | ActiveToolTip::showToolTip( tooltip ); | ||
167 | } | 172 | } | ||
168 | 173 | | |||
169 | void PatchHighlighter::markClicked( KTextEditor::Document* doc, const KTextEditor::Mark& mark, bool& handled ) { | 174 | void PatchHighlighter::markClicked( KTextEditor::Document* doc, const KTextEditor::Mark& mark, bool& handled ) { | ||
170 | m_applying = true; | 175 | if( handled || !(mark.type & m_allmarks) ) | ||
171 | if( handled ) | | |||
172 | return; | 176 | return; | ||
173 | 177 | | |||
174 | handled = true; | 178 | auto range_diff = rangeForMark(mark); | ||
179 | m_applying = true; | ||||
175 | 180 | | |||
176 | // TODO: reconsider workaround | 181 | if (range_diff.first) { | ||
177 | // if( doc->activeView() ) ///This is a workaround, if the cursor is somewhere else, the editor will always jump there when a mark was clicked | 182 | handled = true; | ||
178 | // doc->activeView()->setCursorPosition( KTextEditor::Cursor( mark.line, 0 ) ); | | |||
179 | 183 | | |||
180 | KTextEditor::MovingRange* range = rangeForMark( mark ); | 184 | KTextEditor::MovingRange *&range = range_diff.first; | ||
185 | Diff2::Difference *&diff = range_diff.second; | ||||
181 | 186 | | |||
182 | if( range ) { | | |||
183 | QString currentText = doc->text( range->toRange() ); | 187 | QString currentText = doc->text( range->toRange() ); | ||
184 | Diff2::Difference* diff = m_differencesForRanges[range]; | | |||
185 | 188 | | |||
186 | removeLineMarker( range ); | 189 | removeLineMarker( range ); | ||
187 | 190 | | |||
188 | QString sourceText; | 191 | QString sourceText; | ||
189 | QString targetText; | 192 | QString targetText; | ||
190 | 193 | | |||
191 | for( int a = 0; a < diff->sourceLineCount(); ++a ) { | 194 | for( int a = 0; a < diff->sourceLineCount(); ++a ) { | ||
192 | sourceText += diff->sourceLineAt( a )->string(); | 195 | sourceText += diff->sourceLineAt( a )->string(); | ||
193 | if( !sourceText.endsWith( '\n' ) ) | 196 | if( !sourceText.endsWith( '\n' ) ) | ||
194 | sourceText += '\n'; | 197 | sourceText += '\n'; | ||
195 | } | 198 | } | ||
196 | 199 | | |||
197 | for( int a = 0; a < diff->destinationLineCount(); ++a ) { | 200 | for( int a = 0; a < diff->destinationLineCount(); ++a ) { | ||
198 | targetText += diff->destinationLineAt( a )->string(); | 201 | targetText += diff->destinationLineAt( a )->string(); | ||
199 | if( !targetText.endsWith( '\n' ) ) | 202 | if( !targetText.endsWith( '\n' ) ) | ||
200 | targetText += '\n'; | 203 | targetText += '\n'; | ||
201 | } | 204 | } | ||
202 | 205 | | |||
203 | QString replace; | 206 | bool applied = diff->applied(); | ||
204 | QString replaceWith; | 207 | QString &replace(applied ? targetText : sourceText); | ||
205 | 208 | QString &replaceWith(applied ? sourceText : targetText); | |||
206 | if( !diff->applied() ) { | | |||
207 | replace = sourceText; | | |||
208 | replaceWith = targetText; | | |||
209 | }else { | | |||
210 | replace = targetText; | | |||
211 | replaceWith = sourceText; | | |||
212 | } | | |||
213 | 209 | | |||
214 | if( currentText.simplified() != replace.simplified() ) { | 210 | if( currentText.simplified() != replace.simplified() ) { | ||
215 | KMessageBox::error( ICore::self()->uiController()->activeMainWindow(), i18n( "Could not apply the change: Text should be \"%1\", but is \"%2\".", replace, currentText ) ); | 211 | KMessageBox::error( ICore::self()->uiController()->activeMainWindow(), i18n( "Could not apply the change: Text should be \"%1\", but is \"%2\".", replace, currentText ) ); | ||
212 | | ||||
213 | m_applying = false; | ||||
216 | return; | 214 | return; | ||
217 | } | 215 | } | ||
218 | 216 | | |||
219 | diff->apply( !diff->applied() ); | 217 | diff->apply(!applied); | ||
220 | 218 | | |||
221 | KTextEditor::Cursor start = range->start().toCursor(); | 219 | KTextEditor::Cursor start = range->start().toCursor(); | ||
222 | range->document()->replaceText( range->toRange(), replaceWith ); | 220 | range->document()->replaceText( range->toRange(), replaceWith ); | ||
223 | uint replaceWithLines = replaceWith.count( '\n' ); | 221 | uint replaceWithLines = replaceWith.count( '\n' ); | ||
224 | KTextEditor::Range newRange( start, KTextEditor::Cursor(start.line() + replaceWithLines, start.column()) ); | 222 | KTextEditor::Range newRange( start, KTextEditor::Cursor(start.line() + replaceWithLines, start.column()) ); | ||
225 | 223 | | |||
226 | range->setRange( newRange ); | 224 | range->setRange( newRange ); | ||
227 | 225 | | |||
228 | addLineMarker( range, diff ); | 226 | addLineMarker( range, diff ); | ||
229 | } | | |||
230 | 227 | | |||
231 | { | 228 | { | ||
232 | // After applying the change, show the tooltip again, mainly to update an old tooltip | 229 | // After applying the change, show the tooltip again, mainly to update an old tooltip | ||
233 | delete currentTooltip; | 230 | delete currentTooltip; | ||
231 | currentTooltip = nullptr; | ||||
234 | bool h = false; | 232 | bool h = false; | ||
235 | markToolTipRequested( doc, mark, QCursor::pos(), h ); | 233 | markToolTipRequested( doc, mark, QCursor::pos(), h ); | ||
236 | } | 234 | } | ||
235 | } | ||||
236 | | ||||
237 | m_applying = false; | 237 | m_applying = false; | ||
238 | } | 238 | } | ||
239 | 239 | | |||
240 | KTextEditor::MovingRange* PatchHighlighter::rangeForMark( const KTextEditor::Mark& mark ) { | 240 | QPair<KTextEditor::MovingRange*, Diff2::Difference*> PatchHighlighter::rangeForMark( const KTextEditor::Mark &mark ) { | ||
241 | for( QMap<KTextEditor::MovingRange*, Diff2::Difference*>::const_iterator it = m_differencesForRanges.constBegin(); it != m_differencesForRanges.constEnd(); ++it ) { | 241 | if (!m_applying) { | ||
242 | if( it.key()->start().line() == mark.line ) | 242 | for( QMap<KTextEditor::MovingRange*, Diff2::Difference*>::const_iterator it = m_ranges.constBegin(); it != m_ranges.constEnd(); ++it ) { | ||
243 | { | 243 | if (it.value() && it.key()->start().line() <= mark.line && mark.line <= it.key()->end().line()) { | ||
244 | return it.key(); | 244 | return qMakePair(it.key(), it.value()); | ||
245 | } | ||||
245 | } | 246 | } | ||
246 | } | 247 | } | ||
247 | 248 | | |||
248 | return nullptr; | 249 | return qMakePair(nullptr, nullptr); | ||
249 | } | 250 | } | ||
250 | 251 | | |||
251 | void PatchHighlighter::markToolTipRequested( KTextEditor::Document*, const KTextEditor::Mark& mark, QPoint pos, bool& handled ) { | 252 | void PatchHighlighter::markToolTipRequested( KTextEditor::Document*, const KTextEditor::Mark& mark, QPoint pos, bool& handled ) { | ||
252 | if( handled ) | 253 | if( handled ) | ||
253 | return; | 254 | return; | ||
254 | 255 | | |||
255 | handled = true; | 256 | if( mark.type & m_allmarks ) { | ||
256 | | ||||
257 | int myMarksPattern = KTextEditor::MarkInterface::markType22 | KTextEditor::MarkInterface::markType23 | KTextEditor::MarkInterface::markType24 | KTextEditor::MarkInterface::markType25 | KTextEditor::MarkInterface::markType26 | KTextEditor::MarkInterface::markType27; | | |||
258 | if( mark.type & myMarksPattern ) { | | |||
259 | //There is a mark in this line. Show the old text. | 257 | //There is a mark in this line. Show the old text. | ||
260 | KTextEditor::MovingRange* range = rangeForMark( mark ); | 258 | auto range = rangeForMark(mark); | ||
261 | if( range ) | 259 | if( range.first ) { | ||
262 | showToolTipForMark( pos, range ); | 260 | showToolTipForMark( pos, range.first ); | ||
261 | handled = true; | ||||
262 | } | ||||
263 | } | 263 | } | ||
264 | } | 264 | } | ||
265 | 265 | | |||
266 | bool PatchHighlighter::isInsertion( Diff2::Difference* diff ) { | 266 | bool PatchHighlighter::isInsertion( Diff2::Difference* diff ) { | ||
267 | return diff->sourceLineCount() == 0; | 267 | return diff->sourceLineCount() == 0; | ||
268 | } | 268 | } | ||
269 | 269 | | |||
270 | bool PatchHighlighter::isRemoval( Diff2::Difference* diff ) { | 270 | bool PatchHighlighter::isRemoval( Diff2::Difference* diff ) { | ||
271 | return diff->destinationLineCount() == 0; | 271 | return diff->destinationLineCount() == 0; | ||
272 | } | 272 | } | ||
273 | 273 | | |||
274 | QStringList PatchHighlighter::splitAndAddNewlines( const QString& text ) const { | | |||
275 | QStringList result = text.split( '\n', QString::KeepEmptyParts ); | | |||
276 | for( QStringList::iterator iter = result.begin(); iter != result.end(); ++iter ) { | | |||
277 | iter->append( '\n' ); | | |||
278 | } | | |||
279 | if ( !result.isEmpty() ) { | | |||
280 | QString & last = result.last(); | | |||
281 | last.remove( last.size() - 1, 1 ); | | |||
282 | } | | |||
283 | return result; | | |||
284 | } | | |||
285 | | ||||
286 | void PatchHighlighter::performContentChange( KTextEditor::Document* doc, const QStringList& oldLines, const QStringList& newLines, int editLineNumber ) { | 274 | void PatchHighlighter::performContentChange( KTextEditor::Document* doc, const QStringList& oldLines, const QStringList& newLines, int editLineNumber ) { | ||
287 | QPair<QList<Diff2::Difference*>, QList<Diff2::Difference*> > diffChange = m_model->linesChanged( oldLines, newLines, editLineNumber ); | 275 | QPair<QList<Diff2::Difference*>, QList<Diff2::Difference*> > diffChange = m_model->linesChanged( oldLines, newLines, editLineNumber ); | ||
288 | QList<Diff2::Difference*> inserted = diffChange.first; | 276 | QList<Diff2::Difference*> inserted = diffChange.first; | ||
289 | QList<Diff2::Difference*> removed = diffChange.second; | 277 | QList<Diff2::Difference*> removed = diffChange.second; | ||
290 | 278 | | |||
279 | foreach(Diff2::Difference* d, removed) { | ||||
280 | foreach(Diff2::DifferenceString* s, d->sourceLines()) | ||||
281 | qCDebug(PLUGIN_PATCHREVIEW) << "removed source" << s->string(); | ||||
282 | foreach(Diff2::DifferenceString* s, d->destinationLines()) | ||||
283 | qCDebug(PLUGIN_PATCHREVIEW) << "removed destination" << s->string(); | ||||
284 | } | ||||
285 | foreach(Diff2::Difference* d, inserted) { | ||||
286 | foreach(Diff2::DifferenceString* s, d->sourceLines()) | ||||
287 | qCDebug(PLUGIN_PATCHREVIEW) << "inserted source" << s->string(); | ||||
288 | foreach(Diff2::DifferenceString* s, d->destinationLines()) | ||||
289 | qCDebug(PLUGIN_PATCHREVIEW) << "inserted destination" << s->string(); | ||||
290 | } | ||||
291 | | ||||
291 | // Remove all ranges that are in the same line (the line markers) | 292 | // Remove all ranges that are in the same line (the line markers) | ||
292 | foreach( KTextEditor::MovingRange* r, m_differencesForRanges.keys() ) { | 293 | for (auto it = m_ranges.begin(); it != m_ranges.end();) { | ||
293 | Diff2::Difference* diff = m_differencesForRanges[r]; | 294 | if (removed.contains(it.value())) { | ||
294 | if ( removed.contains( diff ) ) { | 295 | KTextEditor::MovingRange* r = it.key(); | ||
295 | removeLineMarker( r ); | 296 | removeLineMarker(r); // is altering m_ranges | ||
296 | m_ranges.remove( r ); | 297 | it = m_ranges.erase(it); | ||
297 | m_differencesForRanges.remove( r ); | 298 | | ||
298 | delete r; | 299 | delete r; | ||
299 | delete diff; | 300 | } else { | ||
301 | ++it; | ||||
300 | } | 302 | } | ||
301 | } | 303 | } | ||
304 | qDeleteAll(removed); | ||||
302 | 305 | | |||
303 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( doc ); | 306 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( doc ); | ||
304 | if ( !moving ) | 307 | if ( !moving ) | ||
305 | return; | 308 | return; | ||
306 | 309 | | |||
307 | foreach( Diff2::Difference* diff, inserted ) { | 310 | foreach( Diff2::Difference* diff, inserted ) { | ||
308 | int lineStart = diff->destinationLineNumber(); | 311 | int lineStart = diff->destinationLineNumber(); | ||
309 | if ( lineStart > 0 ) { | 312 | if ( lineStart > 0 ) { | ||
310 | --lineStart; | 313 | --lineStart; | ||
311 | } | 314 | } | ||
312 | int lineEnd = diff->destinationLineEnd(); | 315 | int lineEnd = diff->destinationLineEnd(); | ||
313 | if ( lineEnd > 0 ) { | 316 | if ( lineEnd > 0 ) { | ||
314 | --lineEnd; | 317 | --lineEnd; | ||
315 | } | 318 | } | ||
316 | KTextEditor::Range newRange( lineStart, 0, lineEnd, 0 ); | 319 | KTextEditor::Range newRange( lineStart, 0, lineEnd, 0 ); | ||
317 | KTextEditor::MovingRange * r = moving->newMovingRange( newRange ); | 320 | KTextEditor::MovingRange * r = moving->newMovingRange( newRange ); | ||
318 | 321 | | |||
319 | m_differencesForRanges[r] = diff; | 322 | m_ranges[r] = diff; | ||
320 | m_ranges.insert( r ); | | |||
321 | addLineMarker( r, diff ); | 323 | addLineMarker( r, diff ); | ||
322 | } | 324 | } | ||
323 | } | 325 | } | ||
324 | 326 | | |||
325 | void PatchHighlighter::textRemoved( KTextEditor::Document* doc, const KTextEditor::Range& range, const QString& oldText ) { | 327 | void PatchHighlighter::textRemoved( KTextEditor::Document* doc, const KTextEditor::Range& range, const QString& oldText ) { | ||
326 | if ( m_applying ) { // Do not interfere with patch application | 328 | if ( m_applying ) { // Do not interfere with patch application | ||
327 | return; | 329 | return; | ||
328 | } | 330 | } | ||
329 | qCDebug(PLUGIN_PATCHREVIEW) << "removal range" << range; | 331 | qCDebug(PLUGIN_PATCHREVIEW) << "removal range" << range; | ||
330 | qCDebug(PLUGIN_PATCHREVIEW) << "removed text" << oldText; | 332 | qCDebug(PLUGIN_PATCHREVIEW) << "removed text" << oldText; | ||
331 | QStringList removedLines = splitAndAddNewlines( oldText ); | 333 | | ||
332 | int startLine = range.start().line(); | 334 | KTextEditor::Cursor cursor = range.start(); | ||
333 | QString remainingLine = doc->line( startLine ); | 335 | int startLine = cursor.line(); | ||
334 | remainingLine += '\n'; | 336 | QStringList removedLines; | ||
335 | QString prefix = remainingLine.mid( 0, range.start().column() ); | 337 | QStringList remainingLines; | ||
336 | QString suffix = remainingLine.mid( range.start().column() ); | 338 | if (startLine > 0) { | ||
337 | if ( !removedLines.empty() ) { | 339 | QString above = doc->line(--startLine); | ||
338 | removedLines.first() = prefix + removedLines.first(); | 340 | removedLines << above; | ||
339 | removedLines.last() = removedLines.last() + suffix; | 341 | remainingLines << above; | ||
342 | } | ||||
343 | QString changed = doc->line(cursor.line()) + '\n'; | ||||
344 | removedLines << changed.mid(0, cursor.column()) + oldText + changed.mid(cursor.column()); | ||||
345 | remainingLines << changed; | ||||
346 | if (doc->documentRange().end().line() > cursor.line()) { | ||||
347 | QString below = doc->line(cursor.line() + 1); | ||||
348 | removedLines << below; | ||||
349 | remainingLines << below; | ||||
350 | } | ||||
351 | | ||||
352 | performContentChange(doc, removedLines, remainingLines, startLine + 1); | ||||
340 | } | 353 | } | ||
341 | performContentChange( doc, removedLines, QStringList() << remainingLine, startLine + 1 ); | 354 | | ||
355 | void PatchHighlighter::newlineRemoved(KTextEditor::Document* doc, int line) { | ||||
356 | if ( m_applying ) { // Do not interfere with patch application | ||||
357 | return; | ||||
358 | } | ||||
359 | qCDebug(PLUGIN_PATCHREVIEW) << "remove newline" << line; | ||||
360 | | ||||
361 | KTextEditor::Cursor cursor = m_doc->cursorPosition(); | ||||
362 | | ||||
363 | int startLine = line - 1; | ||||
364 | QStringList removedLines; | ||||
365 | QStringList remainingLines; | ||||
366 | if (startLine > 0) { | ||||
367 | QString above = doc->line(--startLine); | ||||
368 | removedLines << above; | ||||
369 | remainingLines << above; | ||||
370 | } | ||||
371 | QString changed = doc->line(line - 1); | ||||
372 | if (cursor.line() == line - 1) { | ||||
373 | removedLines << changed.mid(0, cursor.column()); | ||||
374 | removedLines << changed.mid(cursor.column()); | ||||
375 | } else { | ||||
376 | removedLines << changed; | ||||
377 | removedLines << QString(); | ||||
378 | } | ||||
379 | remainingLines << changed; | ||||
380 | if (doc->documentRange().end().line() >= line) { | ||||
381 | QString below = doc->line(line); | ||||
382 | removedLines << below; | ||||
383 | remainingLines << below; | ||||
342 | } | 384 | } | ||
343 | 385 | | |||
344 | void PatchHighlighter::highlightFromScratch(KTextEditor::Document* doc) | 386 | performContentChange(doc, removedLines, remainingLines, startLine + 1); | ||
387 | } | ||||
388 | | ||||
389 | void PatchHighlighter::documentReloaded(KTextEditor::Document* doc) | ||||
345 | { | 390 | { | ||
346 | qCDebug(PLUGIN_PATCHREVIEW) << "re-doing"; | 391 | qCDebug(PLUGIN_PATCHREVIEW) << "re-doing"; | ||
347 | //The document was loaded / reloaded | 392 | //The document was loaded / reloaded | ||
348 | if ( !m_model->differences() ) | 393 | if ( !m_model->differences() ) | ||
349 | return; | 394 | return; | ||
350 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( doc ); | 395 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( doc ); | ||
351 | if ( !moving ) | 396 | if ( !moving ) | ||
352 | return; | 397 | return; | ||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Line(s) | 428 | for ( Diff2::DifferenceList::const_iterator it = m_model->differences()->constBegin(); it != m_model->differences()->constEnd(); ++it ) { | |||
402 | KTextEditor::Cursor endC( line + lineCount, 0 ); | 447 | KTextEditor::Cursor endC( line + lineCount, 0 ); | ||
403 | if ( doc->lines() <= c.line() ) | 448 | if ( doc->lines() <= c.line() ) | ||
404 | c.setLine( doc->lines() - 1 ); | 449 | c.setLine( doc->lines() - 1 ); | ||
405 | if ( doc->lines() <= endC.line() ) | 450 | if ( doc->lines() <= endC.line() ) | ||
406 | endC.setLine( doc->lines() ); | 451 | endC.setLine( doc->lines() ); | ||
407 | 452 | | |||
408 | if ( endC.isValid() && c.isValid() ) { | 453 | if ( endC.isValid() && c.isValid() ) { | ||
409 | KTextEditor::MovingRange * r = moving->newMovingRange( KTextEditor::Range( c, endC ) ); | 454 | KTextEditor::MovingRange * r = moving->newMovingRange( KTextEditor::Range( c, endC ) ); | ||
410 | m_ranges << r; | 455 | m_ranges[r] = diff; | ||
411 | | ||||
412 | m_differencesForRanges[r] = *it; | | |||
413 | | ||||
414 | addLineMarker( r, diff ); | 456 | addLineMarker( r, diff ); | ||
415 | } | 457 | } | ||
416 | } | 458 | } | ||
417 | } | 459 | } | ||
418 | 460 | | |||
419 | void PatchHighlighter::textInserted(KTextEditor::Document* doc, const KTextEditor::Cursor& cursor, const QString& text) { | 461 | void PatchHighlighter::textInserted(KTextEditor::Document* doc, const KTextEditor::Cursor& cursor, const QString& text) { | ||
420 | KTextEditor::Range range(cursor, KTextEditor::Cursor(text.count('\n'), text.size()-text.lastIndexOf('\n')+1)); | | |||
421 | if( range == doc->documentRange() ) { | | |||
422 | highlightFromScratch(doc); | | |||
423 | } else { | | |||
424 | if ( m_applying ) { // Do not interfere with patch application | 462 | if ( m_applying ) { // Do not interfere with patch application | ||
425 | return; | 463 | return; | ||
426 | } | 464 | } | ||
427 | qCDebug(PLUGIN_PATCHREVIEW) << "insertion range" << range; | 465 | | ||
428 | QString text = doc->text( range ); | 466 | int startLine = cursor.line(); | ||
467 | int endColumn = cursor.column() + text.length(); | ||||
468 | | ||||
469 | qCDebug(PLUGIN_PATCHREVIEW) << "insertion range" << | ||||
470 | KTextEditor::Range(cursor, KTextEditor::Cursor(startLine, endColumn)); | ||||
429 | qCDebug(PLUGIN_PATCHREVIEW) << "inserted text" << text; | 471 | qCDebug(PLUGIN_PATCHREVIEW) << "inserted text" << text; | ||
430 | QStringList insertedLines = splitAndAddNewlines( text ); | 472 | | ||
431 | int startLine = range.start().line(); | 473 | QStringList removedLines; | ||
432 | int endLine = range.end().line(); | 474 | QStringList insertedLines; | ||
433 | QString prefix = doc->line( startLine ).mid( 0, range.start().column() ); | 475 | if (startLine > 0) { | ||
434 | QString suffix = doc->line( endLine ).mid( range.end().column() ); | 476 | QString above = doc->line(--startLine) + '\n'; | ||
435 | suffix += '\n'; | 477 | removedLines << above; | ||
436 | QString removedLine = prefix + suffix; | 478 | insertedLines << above; | ||
437 | if ( !insertedLines.empty() ) { | 479 | } | ||
438 | insertedLines.first() = prefix + insertedLines.first(); | 480 | QString changed = doc->line(cursor.line()) + '\n'; | ||
439 | insertedLines.last() = insertedLines.last() + suffix; | 481 | removedLines << changed.mid(0, cursor.column()) + changed.mid(endColumn); | ||
482 | insertedLines << changed; | ||||
483 | if (doc->documentRange().end().line() > cursor.line()) { | ||||
484 | QString below = doc->line(cursor.line() + 1) + '\n'; | ||||
485 | removedLines << below; | ||||
486 | insertedLines << below; | ||||
487 | } | ||||
488 | | ||||
489 | performContentChange(doc, removedLines, insertedLines, startLine + 1); | ||||
440 | } | 490 | } | ||
441 | performContentChange( doc, QStringList() << removedLine, insertedLines, startLine + 1 ); | 491 | | ||
492 | void PatchHighlighter::newlineInserted(KTextEditor::Document* doc, const KTextEditor::Cursor& cursor) | ||||
493 | { | ||||
494 | if ( m_applying ) { // Do not interfere with patch application | ||||
495 | return; | ||||
442 | } | 496 | } | ||
497 | qCDebug(PLUGIN_PATCHREVIEW) << "newline range" << | ||||
498 | KTextEditor::Range(cursor, KTextEditor::Cursor(cursor.line() + 1, 0)); | ||||
499 | | ||||
500 | int startLine = cursor.line(); | ||||
501 | QStringList removedLines; | ||||
502 | QStringList insertedLines; | ||||
503 | if (startLine > 0) { | ||||
504 | QString above = doc->line(--startLine) + '\n'; | ||||
505 | removedLines << above; | ||||
506 | insertedLines << above; | ||||
507 | } | ||||
508 | insertedLines << QString('\n'); | ||||
509 | if (doc->documentRange().end().line() > cursor.line()) { | ||||
510 | QString below = doc->line(cursor.line() + 1) + '\n'; | ||||
511 | removedLines << below; | ||||
512 | insertedLines << below; | ||||
513 | } | ||||
514 | | ||||
515 | performContentChange(doc, removedLines, insertedLines, startLine + 1); | ||||
443 | } | 516 | } | ||
444 | 517 | | |||
445 | PatchHighlighter::PatchHighlighter( Diff2::DiffModel* model, IDocument* kdoc, PatchReviewPlugin* plugin, bool updatePatchFromEdits ) throw( QString ) | 518 | PatchHighlighter::PatchHighlighter( Diff2::DiffModel* model, IDocument* kdoc, PatchReviewPlugin* plugin, bool updatePatchFromEdits ) throw( QString ) | ||
446 | : m_doc( kdoc ), m_plugin( plugin ), m_model( model ), m_applying( false ) { | 519 | : m_doc( kdoc ), m_plugin( plugin ), m_model( model ), m_applying( false ) { | ||
447 | KTextEditor::Document* doc = kdoc->textDocument(); | 520 | KTextEditor::Document* doc = kdoc->textDocument(); | ||
448 | // connect( kdoc, SIGNAL(destroyed(QObject*)), this, SLOT(documentDestroyed()) ); | 521 | // connect( kdoc, SIGNAL(destroyed(QObject*)), this, SLOT(documentDestroyed()) ); | ||
449 | if (updatePatchFromEdits) { | 522 | if (updatePatchFromEdits) { | ||
450 | connect(doc, &KTextEditor::Document::textInserted, this, &PatchHighlighter::textInserted); | 523 | connect(doc, &KTextEditor::Document::textInserted, this, &PatchHighlighter::textInserted); | ||
524 | connect(doc, &KTextEditor::Document::lineWrapped, this, &PatchHighlighter::newlineInserted); | ||||
451 | connect(doc, &KTextEditor::Document::textRemoved, this, &PatchHighlighter::textRemoved); | 525 | connect(doc, &KTextEditor::Document::textRemoved, this, &PatchHighlighter::textRemoved); | ||
526 | connect(doc, &KTextEditor::Document::lineUnwrapped, this, &PatchHighlighter::newlineRemoved); | ||||
452 | } | 527 | } | ||
528 | connect(doc, &KTextEditor::Document::reloaded, this, &PatchHighlighter::documentReloaded); | ||||
453 | connect(doc, &KTextEditor::Document::destroyed, this, &PatchHighlighter::documentDestroyed); | 529 | connect(doc, &KTextEditor::Document::destroyed, this, &PatchHighlighter::documentDestroyed); | ||
454 | 530 | | |||
455 | if ( doc->lines() == 0 ) | 531 | if ( doc->lines() == 0 ) | ||
456 | return; | 532 | return; | ||
457 | 533 | | |||
458 | if (qobject_cast<KTextEditor::MarkInterface*>(doc)) { | 534 | if (qobject_cast<KTextEditor::MarkInterface*>(doc)) { | ||
459 | //can't use new signal/slot syntax here, MarkInterface is not a QObject | 535 | //can't use new signal/slot syntax here, MarkInterface is not a QObject | ||
460 | connect(doc, SIGNAL(markToolTipRequested(KTextEditor::Document*,KTextEditor::Mark,QPoint,bool&)), | 536 | connect(doc, SIGNAL(markToolTipRequested(KTextEditor::Document*,KTextEditor::Mark,QPoint,bool&)), | ||
461 | this, SLOT(markToolTipRequested(KTextEditor::Document*,KTextEditor::Mark,QPoint,bool&))); | 537 | this, SLOT(markToolTipRequested(KTextEditor::Document*,KTextEditor::Mark,QPoint,bool&))); | ||
462 | connect(doc, SIGNAL(markClicked(KTextEditor::Document*,KTextEditor::Mark,bool&)), | 538 | connect(doc, SIGNAL(markClicked(KTextEditor::Document*,KTextEditor::Mark,bool&)), | ||
463 | this, SLOT(markClicked(KTextEditor::Document*,KTextEditor::Mark,bool&))); | 539 | this, SLOT(markClicked(KTextEditor::Document*,KTextEditor::Mark,bool&))); | ||
464 | } | 540 | } | ||
465 | if (qobject_cast<KTextEditor::MovingInterface*>(doc)) { | 541 | if (qobject_cast<KTextEditor::MovingInterface*>(doc)) { | ||
466 | //can't use new signal/slot syntax here, MovingInterface is not a QObject | 542 | //can't use new signal/slot syntax here, MovingInterface is not a QObject | ||
467 | connect(doc, SIGNAL(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*)), | 543 | connect(doc, SIGNAL(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*)), | ||
468 | this, SLOT(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*))); | 544 | this, SLOT(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*))); | ||
469 | connect(doc, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)), | 545 | connect(doc, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)), | ||
470 | this, SLOT(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*))); | 546 | this, SLOT(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*))); | ||
471 | } | 547 | } | ||
472 | 548 | | |||
473 | highlightFromScratch(doc); | 549 | documentReloaded(doc); | ||
474 | } | 550 | } | ||
475 | 551 | | |||
476 | void PatchHighlighter::removeLineMarker( KTextEditor::MovingRange* range ) { | 552 | void PatchHighlighter::removeLineMarker( KTextEditor::MovingRange* range ) { | ||
477 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( range->document() ); | 553 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( range->document() ); | ||
478 | if ( !moving ) | 554 | if ( !moving ) | ||
479 | return; | 555 | return; | ||
480 | 556 | | |||
481 | KTextEditor::MarkInterface* markIface = dynamic_cast<KTextEditor::MarkInterface*>( range->document() ); | 557 | KTextEditor::MarkInterface* markIface = dynamic_cast<KTextEditor::MarkInterface*>( range->document() ); | ||
482 | if( !markIface ) | 558 | if( !markIface ) | ||
483 | return; | 559 | return; | ||
484 | 560 | | |||
485 | markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType22 ); | 561 | for (int line = range->start().line(); line <= range->end().line(); ++line) { | ||
486 | markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType23 ); | 562 | markIface->removeMark(line, m_allmarks); | ||
487 | markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType24 ); | 563 | } | ||
488 | markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType25 ); | | |||
489 | markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType26 ); | | |||
490 | markIface->removeMark( range->start().line(), KTextEditor::MarkInterface::markType27 ); | | |||
491 | 564 | | |||
492 | // Remove all ranges that are in the same line (the line markers) | 565 | // Remove all ranges that are in the same line (the line markers) | ||
493 | foreach( KTextEditor::MovingRange* r, m_ranges ) | 566 | for (auto it = m_ranges.begin(); it != m_ranges.end();) { | ||
494 | { | 567 | if (it.key() != range && range->overlaps(it.key()->toRange())) { | ||
495 | if( r != range && range->contains( r->toRange() ) ) | 568 | delete it.key(); | ||
496 | { | 569 | it = m_ranges.erase(it); | ||
497 | delete r; | 570 | } else { | ||
498 | m_ranges.remove( r ); | 571 | ++it; | ||
499 | m_differencesForRanges.remove( r ); | | |||
500 | } | 572 | } | ||
501 | } | 573 | } | ||
502 | } | 574 | } | ||
503 | 575 | | |||
504 | void PatchHighlighter::addLineMarker( KTextEditor::MovingRange* range, Diff2::Difference* diff ) { | 576 | void PatchHighlighter::addLineMarker( KTextEditor::MovingRange* range, Diff2::Difference* diff ) { | ||
505 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( range->document() ); | 577 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( range->document() ); | ||
506 | if ( !moving ) | 578 | if ( !moving ) | ||
507 | return; | 579 | return; | ||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Line(s) | 623 | for( int a = 0; a < lines.size(); ++a ) { | |||
556 | Diff2::MarkerList markers = line->markerList(); | 628 | Diff2::MarkerList markers = line->markerList(); | ||
557 | 629 | | |||
558 | for( int b = 0; b < markers.size(); ++b ) { | 630 | for( int b = 0; b < markers.size(); ++b ) { | ||
559 | if( markers[b]->type() == Diff2::Marker::End ) | 631 | if( markers[b]->type() == Diff2::Marker::End ) | ||
560 | { | 632 | { | ||
561 | if( currentPos != 0 || markers[b]->offset() != static_cast<uint>( string.size() ) ) | 633 | if( currentPos != 0 || markers[b]->offset() != static_cast<uint>( string.size() ) ) | ||
562 | { | 634 | { | ||
563 | KTextEditor::MovingRange * r2 = moving->newMovingRange( KTextEditor::Range( KTextEditor::Cursor( a + range->start().line(), currentPos ), KTextEditor::Cursor( a + range->start().line(), markers[b]->offset() ) ) ); | 635 | KTextEditor::MovingRange * r2 = moving->newMovingRange( KTextEditor::Range( KTextEditor::Cursor( a + range->start().line(), currentPos ), KTextEditor::Cursor( a + range->start().line(), markers[b]->offset() ) ) ); | ||
564 | m_ranges << r2; | 636 | m_ranges[r2] = nullptr; | ||
565 | 637 | | |||
566 | KTextEditor::Attribute::Ptr t( new KTextEditor::Attribute() ); | 638 | KTextEditor::Attribute::Ptr t( new KTextEditor::Attribute() ); | ||
567 | 639 | | |||
568 | t->setProperty( QTextFormat::BackgroundBrush, QBrush( ColorCache::self()->blendBackground( QColor( 255, 0, 0 ), 70 ) ) ); | 640 | t->setProperty( QTextFormat::BackgroundBrush, QBrush( ColorCache::self()->blendBackground( QColor( 255, 0, 0 ), 70 ) ) ); | ||
569 | r2->setAttribute( t ); | 641 | r2->setAttribute( t ); | ||
570 | r2->setZDepth( -600 ); | 642 | r2->setZDepth( -600 ); | ||
571 | } | 643 | } | ||
572 | } | 644 | } | ||
Show All 9 Lines | 650 | void PatchHighlighter::clear() { | |||
582 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( m_doc->textDocument() ); | 654 | KTextEditor::MovingInterface* moving = dynamic_cast<KTextEditor::MovingInterface*>( m_doc->textDocument() ); | ||
583 | if ( !moving ) | 655 | if ( !moving ) | ||
584 | return; | 656 | return; | ||
585 | 657 | | |||
586 | KTextEditor::MarkInterface* markIface = dynamic_cast<KTextEditor::MarkInterface*>( m_doc->textDocument() ); | 658 | KTextEditor::MarkInterface* markIface = dynamic_cast<KTextEditor::MarkInterface*>( m_doc->textDocument() ); | ||
587 | if( !markIface ) | 659 | if( !markIface ) | ||
588 | return; | 660 | return; | ||
589 | 661 | | |||
590 | QHash<int, KTextEditor::Mark*> marks = markIface->marks(); | 662 | foreach( int line, markIface->marks().keys() ) { | ||
591 | foreach( int line, marks.keys() ) { | 663 | markIface->removeMark( line, m_allmarks ); | ||
592 | markIface->removeMark( line, KTextEditor::MarkInterface::markType22 ); | | |||
593 | markIface->removeMark( line, KTextEditor::MarkInterface::markType23 ); | | |||
594 | markIface->removeMark( line, KTextEditor::MarkInterface::markType24 ); | | |||
595 | markIface->removeMark( line, KTextEditor::MarkInterface::markType25 ); | | |||
596 | markIface->removeMark( line, KTextEditor::MarkInterface::markType26 ); | | |||
597 | markIface->removeMark( line, KTextEditor::MarkInterface::markType27 ); | | |||
598 | } | 664 | } | ||
599 | 665 | | |||
600 | qDeleteAll( m_ranges ); | 666 | // Diff is taking care of its own objects (except removed ones) | ||
667 | qDeleteAll( m_ranges.keys() ); | ||||
601 | m_ranges.clear(); | 668 | m_ranges.clear(); | ||
602 | m_differencesForRanges.clear(); | | |||
603 | } | 669 | } | ||
604 | 670 | | |||
605 | PatchHighlighter::~PatchHighlighter() { | 671 | PatchHighlighter::~PatchHighlighter() { | ||
606 | clear(); | 672 | clear(); | ||
607 | } | 673 | } | ||
608 | 674 | | |||
609 | IDocument* PatchHighlighter::doc() { | 675 | IDocument* PatchHighlighter::doc() { | ||
610 | return m_doc; | 676 | return m_doc; | ||
611 | } | 677 | } | ||
612 | 678 | | |||
613 | void PatchHighlighter::documentDestroyed() { | 679 | void PatchHighlighter::documentDestroyed() { | ||
614 | qCDebug(PLUGIN_PATCHREVIEW) << "document destroyed"; | 680 | qCDebug(PLUGIN_PATCHREVIEW) << "document destroyed"; | ||
615 | m_ranges.clear(); | 681 | m_ranges.clear(); | ||
616 | m_differencesForRanges.clear(); | | |||
617 | } | 682 | } | ||
618 | 683 | | |||
619 | void PatchHighlighter::aboutToDeleteMovingInterfaceContent( KTextEditor::Document* ) { | 684 | void PatchHighlighter::aboutToDeleteMovingInterfaceContent( KTextEditor::Document* ) { | ||
620 | qCDebug(PLUGIN_PATCHREVIEW) << "about to delete"; | 685 | qCDebug(PLUGIN_PATCHREVIEW) << "about to delete"; | ||
621 | clear(); | 686 | clear(); | ||
622 | } | 687 | } | ||
623 | 688 | | |||
624 | QList< KTextEditor::MovingRange* > PatchHighlighter::ranges() const | 689 | QList< KTextEditor::MovingRange* > PatchHighlighter::ranges() const | ||
625 | { | 690 | { | ||
626 | return m_differencesForRanges.keys(); | 691 | return m_ranges.keys(); | ||
627 | } | 692 | } |